You are on page 1of 33

Parallel Computing

BÁO CÁO GIỮA KỲ


Lập trình OpenMP

Giảng viên hướng dẫn: Thầy Đoàn Duy Trung

Phạm Đình Thông - 20195923

Lớp Toán Tin - K64 - học kì 20221

1
Mục lục

I Thực hành chung 4


1 Bảng kết quả . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1 Ma trận nhân vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Tính toán số Fibonacci . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3 Ma trận nhân ma trận . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2 Mã nguồn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.1 Ma trận nhân vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 Tính toán số Fibonacci . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.3 Ma trận nhân ma trận . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

II Thực hành nhóm 22


1 Bảng kết quả. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.1 Tích vô hướng hai vector trên Windows. . . . . . . . . . . . . . . . . . . 22
1.2 Tích vô hướng 2 vector trên Linux. . . . . . . . . . . . . . . . . . . . . . 23
2 Mã nguồn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
2.1 Mã nguồn trên hệ điều hành Windows. . . . . . . . . . . . . . . . . . . . 24
2.2 Mã nguồn trên hệ điều hành Linux. . . . . . . . . . . . . . . . . . . . . . 29

III Nhận xét 32

IV Phân chia nhiệm vụ 33

2
Lời mở đầu

Mô hình xử lý song song đã và đang phát triển mạnh mẽ, giải quyết những vấn đề bế tắc mà
mô hình xử lý tuần tự gặp phải như: vấn đề thời gian thực hiện chương trình, tốc độ xử lý, khả
năng lưu trữ của bộ nhớ.
Dưới đây là bài báo cáo thực hành OpenMP, bao gồm 4 chương trình:

•3 bài thực hành cá nhân(Gồm code, bảng kết quả)

•1 bài thực hành nhóm(Gồm code, bảng kết quả và nhận xét)
I Thực hành chung

1 Bảng kết quả


1.1 Ma trận nhân vector
Sử dụng 4 luồng để thực hiện tính toán song song ta thu được bảng sau:

4
Sử dụng 6 luồng để thực hiện tính toán song song ta thu được bảng sau:

5
Sử dụng 8 luồng để thực hiện tính toán song song ta thu được bảng sau:

1.2 Tính toán số Fibonacci


Sử dụng 4 luồng để thực hiện tính toán song song ta thu được bảng sau:

6
Sử dụng 6 luồng để thực hiện tính toán song song ta thu được bảng sau:

Sử dụng 8 luồng để thực hiện tính toán song song ta thu được bảng sau:

7
1.3 Ma trận nhân ma trận
Sử dụng 4 luồng để thực hiện tính toán song song ta thu được bảng sau:

Sử dụng 6 luồng để thực hiện tính toán song song ta thu được bảng sau:

8
Sử dụng 8 luồng để thực hiện tính toán song song ta thu được bảng sau:

2 Mã nguồn
2.1 Ma trận nhân vector

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <omp.h>
#include <time.h>

using namespace std;


double LiToDouble(LARGE_INTEGER x)
{
double result =
((double)x.HighPart) * 4.294967296E9 + (double)((x).LowPart);
return result;
}

double GetTime()
{
LARGE_INTEGER lpFrequency, lpPerfomanceCount;
QueryPerformanceFrequency(&lpFrequency);
QueryPerformanceCounter(&lpPerfomanceCount);
return LiToDouble(lpPerfomanceCount) / LiToDouble(lpFrequency);
}

9
// function for simple definition of matrix and vector elements
void DummyDataInitialization(double* pMatrix, double* pVector, int Size){
int i, j;
for (i = 0; i < Size; i++){
pVector[i] = 1;
for (j = 0; j < Size; j++)
pMatrix[i * Size + j] = i;
}
}

void RandomDataInitialization(double *pMatrix, double *pVector, int Size)


{
int i, j; // Loop variables
srand(time(NULL));
for (i = 0; i < Size; i++)
{
pVector[i] = rand() / (double)(1000);
for (j = 0; j < Size; j++)
pMatrix[i * Size + j] = rand() / (double)(1000);
}
}

void ProcessInitialization(double *&pMatrix, double *&pVector, int &Size)


{
// Size of initial matrix and vector definition
do
{
printf("\nChosen objects size = ");
// scanf("%d", &Size);
cin >> Size;
if (Size <= 0)
printf("\nSize of objects must be greater than 0!\n");
} while (Size <= 0);
// Memory allocation
pMatrix = new double[Size * Size];
pVector = new double[Size];
RandomDataInitialization(pMatrix, pVector, Size);
}

void SerialResultCalculation(double *pMatrix, double *pVector, double *pResult, int


Size)
{
int i, j; // Loop variables
for (i = 0; i < Size; i++)
{
pResult[i] = 0;
for (j = 0; j < Size; j++)
pResult[i] += pMatrix[i * Size + j] * pVector[j];
}
}

10
void ParallelResultCalculation(double *pMatrix, double *pVector, double *pResult,
int Size)
{
int i, j; // Loop variables
#pragma omp parallel for private(j)
for (i = 0; i < Size; i++)
{
pResult[i] = 0;
for (j = 0; j < Size; j++)
pResult[i] += pMatrix[i * Size + j] * pVector[j];
}
}

// function for format matrix ouput


void PrintMatrix(double* pMatrix, int Size) {
int i, j; // Loop variables
for (i = 0; i < Size; i++) {
for (j = 0; j < Size; j++)
printf("%7.4f ", pMatrix[i * Size + j]);
printf("\n");
}
}

// function for formatted vector output


void PrintVector(double* pVector, int Size) {
int i;
for (i = 0; i < Size; i++)
printf("%7.4f ", pVector[i]);
}

void TestResult(double *pMatrix, double *pVector, double *pResult,


int Size)
{
// Buffer for storing the result of serial matrix-vector multiplication
double *pSerialResult;
int equal = 0; // Flag, that shows wheather the vectors are identical
int i; // Loop variable
pSerialResult = new double[Size];
SerialResultCalculation(pMatrix, pVector, pSerialResult, Size);
for (i = 0; i < Size; i++)
{
if (pResult[i] != pSerialResult[i])
{
equal = 1;
}
}
if (equal == 1)
printf("\nThe results of serial and parallel algorithms "
"are NOT identical. Check your code.");
else

11
printf("\nThe results of serial and parallel algorithms are "
"identical.");
delete[] pSerialResult;
}

void ProcessTermination(double *pMatrix, double *pVector)


{
delete[] pMatrix;
delete[] pVector;
}

int main()
{
double *pMatrix; // The first argument - initial matrix
double *pVector; // The second argument - initial vector
double *pResult_Serial; // Result vector for matrix-vector multiplication
double *pResult_Parallel;
int Size, p; // Sizes of initial matrix and vector
double Start, Finish, Duration_Serial, Duration_Parallel;
double Efficiency;
printf("Parallel matrix-vector multiplication program\n");
ProcessInitialization(pMatrix, pVector, Size);
pResult_Serial = new double[Size];
pResult_Parallel = new double[Size];

Start = GetTime();
SerialResultCalculation(pMatrix, pVector, pResult_Serial, Size);
Finish = GetTime();
Duration_Serial = Finish - Start;

#pragma omp parallel num_threads(8)

p = omp_get_num_threads();

Start = GetTime();
ParallelResultCalculation(pMatrix, pVector, pResult_Parallel, Size);
Finish = GetTime();
Duration_Parallel = Finish - Start;
// printf("\nParallel Result:\n");
// PrintVector(pResult_Parallel, Size);

// TestResult(pMatrix, pVector, pResult_Parallel, Size);


Efficiency = Duration_Serial / (Duration_Parallel * p);

printf("\n\nTime of execution serial: %f\n", Duration_Serial);


printf("\n\nTime of execution parallel: %f\n", Duration_Parallel);
printf("\n\nEfficiency of execution: %f%\n", Efficiency * 100);
delete[] pResult_Serial;
delete[] pResult_Parallel;
ProcessTermination(pMatrix, pVector);

12
return 0;
}

2.2 Tính toán số Fibonacci

#include <windows.h>
#include <omp.h>
#include <time.h>
#include <iostream>
#include <bits/stdc++.h>

using namespace std;

//struct big integer


typedef vector<int> bigint;
const int BASE = 10000;

void fix(bigint &a)


{
a.push_back(0);
for (int i = 0; i < a.size() - 1; ++i)
{
a[i + 1] += a[i] / 10;
a[i] %= 10;
if (a[i] < 0)
{
a[i] += 10;
a[i + 1]--;
}
}
while (a.size() >= 2 && a.back() == 0)
a.pop_back();
}
bigint operator*(bigint a, bigint b) {
bigint c(a.size() + b.size() + 1);
for (int i = 0; i < a.size(); ++i)
for (int j = 0; j < b.size(); ++j)
{
c[i + j] += a[i] * b[j];
c[i + j + 1] += c[i + j] / 10;
c[i + j] %= 10;
}
fix(c);
return c;
}
bigint operator*(bigint a, int x)
{
for (int i = 0; i < a.size(); ++i)
a[i] *= x;
fix(a);

13
return a;
}
bigint operator+(bigint a, bigint b) {
a.resize(max(a.size(), b.size()));
for (int i = 0; i < b.size(); ++i)
a[i] += b[i];
fix(a);
return a;
}
bigint operator-(bigint a, bigint b)
{
for (int i = 0; i < b.size(); ++i)
a[i] -= b[i];
fix(a);
return a;
}
ostream &operator<<(ostream &cout, const bigint &a)
{
printf("%d", a.back());
for (int i = a.size() - 2; i >= 0; i--)
printf("%d", a[i]);
return cout;
}

double LiToDouble(LARGE_INTEGER x)
{
double result =
((double)x.HighPart) * 4.294967296E9 + (double)((x).LowPart);
return result;
}

double GetTime()
{
LARGE_INTEGER lpFrequency, lpPerfomanceCount;
QueryPerformanceFrequency(&lpFrequency);
QueryPerformanceCounter(&lpPerfomanceCount);
return LiToDouble(lpPerfomanceCount) / LiToDouble(lpFrequency);
}

bigint SerialFibonacci(long long int n);


void SerialMultip(bigint x[], bigint y[]);

void ParallelMultip(bigint x[], bigint y[]);


bigint ParallelFibonacci(long long int n);
void TestResult(long long int n, bigint fibonacci);

void SerialMultip(bigint x[], bigint y[])

14
{
bigint *c = new bigint[4];
c[0] = x[0] * y[0] + x[1] * y[2];
c[1] = x[0] * y[1] + x[1] * y[3];
c[2] = x[2] * y[0] + x[3] * y[2];
c[3] = x[2] * y[1] + x[3] * y[3];

for (int i = 0; i < 4; i++)


y[i] = c[i];
// delete c;
}

bigint SerialFibonacci(long long int n)


{
if (n <= 2)
return bigint(1, 1);
else
{
n = n - 1;
bigint x[4] = {bigint(1, 1), bigint(1, 1), bigint(1, 1), bigint(1, 1) * 0};
bigint y[4] = {bigint(1, 1), bigint(1, 1) * 0, bigint(1, 1) * 0, bigint(1,
1)};
while (n >= 2)
{
if (n % 2 == 0)
{
SerialMultip(x, x);
n = n / 2;
}
else
{
SerialMultip(x, y);
SerialMultip(x, x);
n = (n - 1)/2;
}
}
SerialMultip(x, y);
return y[0];
}
}

void ParallelMultip(bigint x[], bigint y[])


{
bigint *c = new bigint[4];
#pragma omp parallel sections
{
#pragma omp section
c[0] = x[0] * y[0] + x[1] * y[2];
#pragma omp section
c[1] = x[0] * y[1] + x[1] * y[3];
#pragma omp section

15
{
c[2] = x[2] * y[0] + x[3] * y[2];
c[3] = x[2] * y[1] + x[3] * y[3];
}
}
#pragma omp parallel for
for (int i = 0; i < 4; i++)
y[i] = c[i];
// delete c;
}

bigint ParallelFibonacci(long long int n)


{
if (n <= 2)
return bigint(1, 1);
else
{
n = n - 1;
bigint x[4] = {bigint(1, 1), bigint(1, 1), bigint(1, 1), bigint(1, 1) * 0};
bigint y[4] = {bigint(1, 1), bigint(1, 1) * 0, bigint(1, 1) * 0, bigint(1,
1)};
while (n >= 2)
{
if (n % 2 == 0)
{
ParallelMultip(x, x);
n = n / 2;
}
else
{
ParallelMultip(x, y);
ParallelMultip(x, x);
n = (n - 1)/2;
}
}
ParallelMultip(x, y);
return y[0];
}
}

void TestResult(long long int n, bigint fibonacci)


{
bigint fibonacciSerial;
fibonacciSerial = SerialFibonacci(n);
if (fibonacciSerial != fibonacci)
cout << "The results of serial and parallel algorithms "
"are NOT identical. Check your code.";
else
cout << "The results of serial and parallel algorithms are "
"identical.";
}

16
int main()
{
int p;
double Start, Finish, Duration_Serial, Duration_Parallel, Efficiency;
long long int n;
bigint Fibonacci_Serial, Fibonacci_Parallel;
bigint result;

cout << "Parallel program to find Fibonacci number \n";


cout << "Enter the natural number n: ";
cin >> n;

Start = GetTime();
Fibonacci_Serial = SerialFibonacci(n);
Finish = GetTime();
Duration_Serial = Finish - Start;

Start = GetTime();
Fibonacci_Parallel = ParallelFibonacci(n);
Finish = GetTime();
Duration_Parallel = Finish - Start;

//p l s lung mc nh s dng trong khi song song


#pragma omp parallel num_threads(8)
p = omp_get_num_threads();

Efficiency = Duration_Serial / (Duration_Parallel * p);


// TestResult(n, Fibonacci_Parallel);

cout << "nth Fibonacci number is: \n" << Fibonacci_Serial;


cout << "\nTime of execution Serial: " << Duration_Serial;
cout << "\nTime of execution Parallel: " << Duration_Parallel;
cout << "\nEfficiency of execution: " << Efficiency * 100 << "%";
return 0;
}

2.3 Ma trận nhân ma trận

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <omp.h>
#include <time.h>

using namespace std;

17
double LiToDouble(LARGE_INTEGER x)
{
double result =
((double)x.HighPart) * 4.294967296E9 + (double)((x).LowPart);
return result;
}

double GetTime()
{
LARGE_INTEGER lpFrequency, lpPerfomanceCount;
QueryPerformanceFrequency(&lpFrequency);
QueryPerformanceCounter(&lpPerfomanceCount);
return LiToDouble(lpPerfomanceCount) / LiToDouble(lpFrequency);
}

// function for simple definition of matrix elements


void DummyDataInitialization(double* pMatrix, int Size){
int i, j;
for (i = 0; i < Size; i++){
for (j = 0; j < Size; j++)
pMatrix[i * Size + j] = i;
}
}

void RandomDataInitialization(double *pMatrix, int Size)


{
int i, j; // Loop variables
srand(time(NULL));
for (i = 0; i < Size ; i++)
{
for (j = 0; j < Size; j++)
pMatrix[i * Size + j] = rand() / (double)(1000);
}
}

void ProcessInitialization(double *&pMatrix1, double *&pMatrix2, int &Size)


{
printf("\nChosen objects Size = ");
scanf("%d", &Size);
pMatrix1 = new double[Size * Size];
pMatrix2 = new double[Size * Size];
// RandomDataInitialization(pMatrix1, Size);
// RandomDataInitialization(pMatrix2, Size);
DummyDataInitialization(pMatrix1, Size);
DummyDataInitialization(pMatrix2, Size);

void SerialResultCalculation(double *pMatrix1, double *pMatrix2, double *pResult,


int Size)
{

18
int i, j, k; // Loop variables

for (i = 0; i < Size; i++)


{
for (j = 0; j < Size; j++)
{
pResult[i * Size + j] = 0;
for(k = 0; k < Size; k++)
{
pResult[i*Size + j] += pMatrix1[i*Size +k] * pMatrix2[k * Size + j];
}

}
}

void ParallelResultCalculation(double *pMatrix1, double *pMatrix2, double *pResult,


int Size)
{
int i, j, k; // Loop variables

for (i = 0; i < Size; i++)


{
#pragma omp parallel for private( k)
for (j = 0; j < Size; j++)
{
pResult[i * Size + j] = 0;
for(k = 0; k < Size; k++)
{
pResult[i*Size + j] += pMatrix1[i*Size +k] * pMatrix2[k * Size + j];
}

}
}

// function for format matrix ouput


void PrintMatrix(double* pMatrix, int Size) {
int i, j; // Loop variables
for (i = 0; i < Size; i++) {
for (j = 0; j < Size; j++)
printf("%7.4f ", pMatrix[i * Size + j]);
printf("\n");
}
}

void TestResult(double *pMatrix1, double *pMatrix2, double *pResult,

19
int Size)
{
// Buffer for storing the result of serial matrix-vector multiplication
double *pSerialResult;
int equal = 0; // Flag, that shows wheather the vectors are identical
int i; // Loop variable
pSerialResult = new double[Size*Size];
SerialResultCalculation(pMatrix1, pMatrix2, pSerialResult, Size);
for (i = 0; i < Size*Size; i++)
{
if (pResult[i] != pSerialResult[i])
{
equal = 1;
}
}
if (equal == 1)
printf("\nThe results of serial and parallel algorithms "
"are NOT identical. Check your code.");
else
printf("\nThe results of serial and parallel algorithms are "
"identical.");
delete[] pSerialResult;
}

void ProcessTermination(double *pMatrix1, double *pMatrix2)


{
delete[] pMatrix1;
delete[] pMatrix2;
}

int main()
{
double *pMatrix1; // The first argument - initial matrix
double *pMatrix2; // The second argument - initial vector
double *pResult_Serial; // Result vector for matrix-vector multiplication
double *pResult_Parallel;
int Size, p; // Sizes of initial matrix and vector
double Start, Finish, Duration_Serial, Duration_Parallel;
double Efficiency;
printf("Parallel matrix-vector multiplication program\n");
ProcessInitialization(pMatrix1, pMatrix2, Size);

pResult_Serial = new double[Size* Size];


pResult_Parallel = new double[Size *Size];

Start = GetTime();
SerialResultCalculation(pMatrix1, pMatrix2, pResult_Serial, Size);
Finish = GetTime();
Duration_Serial = Finish - Start;

// printf("\nSerial Result:\n");

20
// PrintMatrix(pResult_Serial, Size);

Start = GetTime();
ParallelResultCalculation(pMatrix1, pMatrix2, pResult_Parallel, Size);
Finish = GetTime();
Duration_Parallel = Finish - Start;

// check result serial and parallel


// printf("test result\n");
// TestResult(pMatrix1, pMatrix2, pResult_Parallel, Size);

// omp_set_num_threads(4);
#pragma omp parallel num_threads(8)

p = omp_get_num_threads();
Efficiency = Duration_Serial / (Duration_Parallel * p);
printf("num threads: %d", p);
printf("\nTime of execution serial: %f\n", Duration_Serial);
printf("Time of execution parallel: %f\n", Duration_Parallel);
printf("Efficiency of execution: %f%\n", Efficiency * 100);

delete[] pResult_Serial;
delete[] pResult_Parallel;
ProcessTermination(pMatrix1, pMatrix2);
return 0;
}

21
II Thực hành nhóm

1 Bảng kết quả.


1.1 Tích vô hướng hai vector trên Windows.
Sử dụng 4 luồng để thực hiện tính toán song song ta thu được bảng sau:

Sử dụng 6 luồng để thực hiện tính toán song song ta thu được bảng sau:

22
Sử dụng 8 luồng để thực hiện tính toán song song ta thu được bảng sau:

1.2 Tích vô hướng 2 vector trên Linux.


Sử dụng 4 luồng để thực hiện tính toán song song ta thu được bảng sau:

23
Sử dụng 6 luồng để thực hiện tính toán song song ta thu được bảng sau:

Sử dụng 8 luồng để thực hiện tính toán song song ta thu được bảng sau:

2 Mã nguồn
2.1 Mã nguồn trên hệ điều hành Windows.

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <omp.h>

24
//----------------------
// Function that converts numbers form LongInt type to double type
double LiToDouble(LARGE_INTEGER x)
{
double result = ((double)x.HighPart) * 4.294967296E9 + (double)((x).LowPart);
return result;
}

// Function that gets the timestamp in seconds


double GetTime()
{
LARGE_INTEGER lpFrequency, lpPerfomanceCount;
QueryPerformanceFrequency (&lpFrequency);
QueryPerformanceCounter (&lpPerfomanceCount);
return LiToDouble(lpPerfomanceCount)/LiToDouble(lpFrequency);

// Function for simple definition of matrix and vector elements


void DummyDataInitialization(double* pVector1, double* pVector2, int Size)
{
int i, j;
for (i=0; i<Size; i++)
{
pVector1[i] = 1;
pVector2[i] = 1;
}
}

// Function for random definition of matrix and vector elements


void RandomDataInitialization(double* pVector1, double* pVector2, int Size)
{
int i, j;
void srand(unsigned (clock()));
for (i=0; i<Size; i++)
{
pVector1[i] = rand()/ (double)1000;
pVector2[i] = rand()/ (double)1000;
}
}

// Function for memory allocation and definition of objects elements


void ProcessInitialization(double* &pVector1, double* &pVector2, double* &pResult,
int &Size)
{
do
{
printf("\nEnter size of the initial objects: ");
scanf("%d", &Size);
printf("\nChosen objects size = %d\n", Size);
if (Size <= 0)

25
printf("\nSize of objects must be greater than 0!\n");
}
while (Size <= 0);

pVector1 = new double [Size];


pVector2 = new double [Size];
pResult = new double;

// DummyDataInitialization(pVector1, pVector2, Size);


RandomDataInitialization(pVector1, pVector2, Size);
}

// Function for formatted vector output


void PrintVector(double* pVector, int Size)
{
int i;
for (i=0; i<Size; i++)
printf("%7.4f ", pVector[i]);
}

void SerialResultCalculation(double* pVector1, double* pVector2, double*


pResult,int Size)
{
int i;
*pResult = 0;

for (i=0; i<Size; i++)


{
*pResult += (pVector1[i] * pVector2[i]);
}
}

void ParallelResultCalculation(double* pVector1, double* pVector2, double*


pResult,int Size)
{
int i;

#pragma omp paralell for private (i) //num_threads(MAX)


*pResult = 0;
for (i=0; i<Size; i++)
{
*pResult += (pVector1[i] * pVector2[i]);
}
}

void ProcessTermination(double* pVector1, double* pVector2,double* pResult)


{
delete [] pVector1;
delete [] pVector2;
delete pResult;
}

26
void TestResult(double* pVector1, double* pVector2, double *pResult, int Size)
{ // Buffer for storing the result of serial matrix-vector multiplication
double* pSerialResult;

// Flag, that shows wheather the vectors are identical


int i; // Loop variable
pSerialResult = new double ;
SerialResultCalculation(pVector1, pVector2, pSerialResult, Size);
// printf("Parallel result: %d", *pResult);
// printf("Serial result: %d", *pSerialResult);

if (*pResult != *pSerialResult)
printf("\nThe results of serial and parallel algorithms " "are NOT
identical. Check your code.");
else
printf("\nThe results of serial and parallel algorithms are " "identical.");
delete pSerialResult;
}

int main()
{
double* pVector2;

// The first argument -initial vector2


double* pVector1;
// The second argument -initial vector1
double* pResult;
// Result vector for vector-vector multiplication
int Size, p; // Sizes of initial matrix and vector
double Start, Finish, Serial_Duration, Parallel_Duration, Parallel_Duration1;
double Efficiency;

printf("Serial matrix-vector multiplication program\n");

ProcessInitialization(pVector1, pVector2, pResult, Size);

Start = GetTime();
SerialResultCalculation(pVector1, pVector2, pResult, Size);
Finish = GetTime();
Serial_Duration = Finish-Start;
printf("Serial result: %f \n", *pResult);

// Matrix-vector multiplication parallel


#pragma omp parallel num_threads(4)
p = omp_get_num_threads();
Start = GetTime();
ParallelResultCalculation(pVector1, pVector2, pResult, Size);
Finish = GetTime();
Parallel_Duration = Finish-Start;
printf("Parallel result: %f", *pResult);

27
// TestResult(pVector1, pVector2, pResult, Size);

// Printing the time spent by matrix-vector multiplication


Efficiency = Serial_Duration / (Parallel_Duration * p);
printf("\n Time of execution serial :%f\n", Serial_Duration);
printf("\n Time of execution parallel :%f\n", Parallel_Duration);
printf("\n\nEfficiency of execution: %f%\n", Efficiency * 100);
// printf("\n Time of execution parallel1 :%f\n", Parallel_Duration1);

// Computational process termination


ProcessTermination(pVector1, pVector2, pResult);
return 0;
}

28
2.2 Mã nguồn trên hệ điều hành Linux.

#include <vector>
#include<omp.h>
#include<time.h>
#include <stdio.h>
#include <linux/types.h>
#include <iostream>
using namespace std;

void DummyDataInitialization(double* pVector1, double* pVector2, int Size)


{
int i, j;
for (i=0; i<Size; i++)
{
pVector1[i] = 1;
pVector2[i] = 1;
}
}

void RandomDataInitialization(double* pVector1, double* pVector2, int Size)


{
int i, j;
void srand(unsigned (clock()));
for (i=0; i<Size; i++)
{
pVector1[i] = rand()/ (double)1000;
pVector2[i] = rand()/ (double)1000;
}
}

void ProcessInitialization(double* &pVector1, double* &pVector2, double* &pResult,


int &Size)
{
do
{
printf("\nEnter size of the initial objects: ");
scanf("%d", &Size);
printf("\nChosen objects size = %d\n", Size);
if (Size <= 0)
printf("\nSize of objects must be greater than 0!\n");
}
while (Size <= 0);

pVector1 = new double [Size];


pVector2 = new double [Size];
pResult = new double;

// DummyDataInitialization(pVector1, pVector2, Size);


RandomDataInitialization(pVector1, pVector2, Size);
}

29
void PrintVector(double* pVector, int Size)
{
int i;
for (i=0; i<Size; i++)
printf("%7.4f ", pVector[i]);
}

void SerialResultCalculation(double* pVector1, double* pVector2, double*


pResult,int Size)
{
int i;
*pResult = 0;
for (i=0; i<Size; i++)
{
*pResult += (pVector1[i] * pVector2[i]);
}
}

void ParallelResultCalculation(double* pVector1, double* pVector2, double*


pResult,int Size)
{
int i;
#pragma omp paralell for private (i) //num_threads(MAX)
*pResult = 0;
for (i=0; i<Size; i++)
{
*pResult += (pVector1[i] * pVector2[i]);
}
}

void ProcessTermination(double* pVector1, double* pVector2,double* pResult)


{
delete [] pVector1;
delete [] pVector2;
delete pResult;
}

void TestResult(double* pVector1, double* pVector2, double *pResult, int Size)


{ // Buffer for storing the result of serial matrix-vector multiplication
double* pSerialResult;

// Flag, that shows wheather the vectors are identical


int i; // Loop variable
pSerialResult = new double ;
SerialResultCalculation(pVector1, pVector2, pSerialResult, Size);
// printf("Parallel result: %d", *pResult);
// printf("Serial result: %d", *pSerialResult);

if (*pResult != *pSerialResult)

30
printf("\nThe results of serial and parallel algorithms " "are NOT
identical. Check your code.");
else
printf("\nThe results of serial and parallel algorithms are " "identical.");
delete pSerialResult;
}

int main()
{
double* pVector2;

// The first argument -initial vector2


double* pVector1;
// The second argument -initial vector1
double* pResult;
// Result vector for vector-vector multiplication
int Size, p; // Sizes of initial matrix and vector
double Serial_Duration, Parallel_Duration;
clock_t Start, Finish;
double Efficiency;

printf("Serial matrix-vector multiplication program\n");

ProcessInitialization(pVector1, pVector2, pResult, Size);

Start = clock();
SerialResultCalculation(pVector1, pVector2, pResult, Size);
Finish = clock();
Serial_Duration = (double)(Finish-Start)/CLOCKS_PER_SEC;
printf("Serial result: %f \n", *pResult);

// Matrix-vector multiplication parallel


#pragma omp parallel num_threads(8)
p = omp_get_num_threads();
Start = clock();
ParallelResultCalculation(pVector1, pVector2, pResult, Size);
Finish = clock();
Parallel_Duration = (double)(Finish-Start)/CLOCKS_PER_SEC;
printf("Parallel result: %f", *pResult);

// TestResult(pVector1, pVector2, pResult, Size);

Efficiency = Serial_Duration / (Parallel_Duration * p);


printf("\n Time of execution serial :%f", Serial_Duration);
printf("\n Time of execution parallel :%f", Parallel_Duration);
printf("\nEfficiency of execution: %f\n", Efficiency * 100);

// Computational process termination


ProcessTermination(pVector1, pVector2, pResult);
return 0;
}

31
III Nhận xét

Từ bảng số liệu và kết quả chạy các chương trình trên, nhóm có một số nhận xét về thời gian
thực thi và hiệu suất của tính toán song song so với tính toán tuần tự thực hiện chương trình
trên Windows và Linux như sau:

• Tất cả các bảng số liệu trên đều cho thấy với dữ liệu đầu vào nhỏ thì thời gian thực hiện
thuật toán tuần tự thực hiện nhanh hơn so với thuật toán song song.

• Với dữ liệu đầu vào lớn, ta thấy hiệu suất ổn định hơn đối với số luồng cố định và thời
gian chạy thuật toán song song nhanh hơn so với thực hiện tuần tự.

• Nhìn chung, hiệu suất của chương trình tính toán tích vô hướng vector nhân vector không
được cao. Hiệu suất rơi vào khoảng từ 20% đến 30%.

• Qua quá trình thực hành, nhóm thấy hiệu suất và thời gian khi thực thi trên Windows và
Linux chệnh lệch nhau không nhiều. Nhưng Linux không thực thi được với dữ liệu đầu
vào 30000000.

• Đối với chương trình trên, ta thấy thực thi với 4 luồng thì thu được hiệu suất tốt hơn so
với 6 luồng và 8 luồng với dữ liệu đầu vào trên.

32
Phân chia nhiệm vụ
IV

33

You might also like