1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 | #include <iostream>
#include <vector>
#include <future>
#include <mutex>
#include <shared_mutex>
#include <chrono>
#include <random>
#include <algorithm>
using Matrix = std::vector<std::vector<double>>;
std::shared_mutex mtx;
// Function to generate a random matrix
Matrix generateRandomMatrix(int rows, int cols) {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<> dis(0.0, 1.0);
Matrix matrix(rows, std::vector<double>(cols));
for (auto& row : matrix) {
for (auto& elem : row) {
elem = dis(gen);
}
}
return matrix;
}
// Function to multiply two matrices
Matrix multiplyMatrices(const Matrix& A, const Matrix& B) {
int m = A.size();
int n = B[0].size();
int p = B.size();
Matrix result(m, std::vector<double>(n, 0.0));
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
for (int k = 0; k < p; ++k) {
result[i][j] += A[i][k] * B[k][j];
}
}
}
return result;
}
// Function to multiply a portion of matrices (for parallel execution)
void multiplyMatricesPortion(const Matrix& A, const Matrix& B, Matrix& result, int start_row, int end_row) {
int n = B[0].size();
int p = B.size();
for (int i = start_row; i < end_row; ++i) {
for (int j = 0; j < n; ++j) {
double sum = 0.0;
for (int k = 0; k < p; ++k) {
sum += A[i][k] * B[k][j];
}
std::scoped_lock lock(mtx);
result[i][j] = sum;
}
}
}
// Function to perform parallel matrix multiplication
Matrix parallelMultiplyMatrices(const Matrix& A, const Matrix& B) {
int m = A.size();
int n = B[0].size();
Matrix result(m, std::vector<double>(n, 0.0));
int num_threads = std::thread::hardware_concurrency(); // 12 on my mac
num_threads = 2;
std::cout << "num_threads= " << num_threads << std::endl;
int rows_per_thread = m / num_threads;
std::vector<std::future<void>> futures;
for (int i = 0; i < num_threads; ++i) {
int start_row = i * rows_per_thread;
int end_row = (i == num_threads - 1) ? m : (i + 1) * rows_per_thread;
futures.push_back(std::async(std::launch::async, multiplyMatricesPortion,
std::ref(A), std::ref(B), std::ref(result), start_row, end_row));
}
for (auto& future : futures) {
future.wait();
}
return result;
}
// Function to measure execution time
template<typename Func, typename... Args>
auto measureTime(Func func, Args&&... args) {
auto start = std::chrono::high_resolution_clock::now();
auto result = func(std::forward<Args>(args)...);
auto end = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> duration = end - start;
return std::make_pair(result, duration.count());
}
int main() {
const int size = 1000;
Matrix A = generateRandomMatrix(size, size);
Matrix B = generateRandomMatrix(size, size);
std::cout << "Matrix size: " << size << "x" << size << std::endl;
auto [result_serial, time_serial] = measureTime(multiplyMatrices, A, B);
std::cout << "Serial multiplication time: " << time_serial << " ms" << std::endl;
auto [result_parallel, time_parallel] = measureTime(parallelMultiplyMatrices, A, B);
std::cout << "Parallel multiplication time: " << time_parallel << " ms" << std::endl;
// Check if results are the same
bool results_match = (result_serial == result_parallel);
std::cout << "Results match: " << (results_match ? "Yes" : "No") << std::endl;
return 0;
}
|