GCC Code Coverage Report


Directory: ./
File: tasks/yakimov_i_multiplication_of_sparse_matrices_crs_storage_format/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 362 364 99.5%
Functions: 32 32 100.0%
Branches: 178 226 78.8%

Line Branch Exec Source
1 #include "yakimov_i_multiplication_of_sparse_matrices_crs_storage_format/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <array>
7 #include <cstddef>
8 #include <cstring>
9 #include <fstream>
10 #include <iostream>
11 #include <string>
12 #include <vector>
13
14 #include "util/include/util.hpp"
15 #include "yakimov_i_multiplication_of_sparse_matrices_crs_storage_format/common/include/common.hpp"
16
17 namespace yakimov_i_multiplication_of_sparse_matrices_crs_storage_format {
18
19 namespace {
20
21 24 bool ReadDimensions(std::ifstream &file, MatrixCRS &matrix) {
22 bool success = true;
23 24 file >> matrix.rows;
24 24 file >> matrix.cols;
25
26
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
24 if (matrix.rows <= 0 || matrix.cols <= 0) {
27 success = false;
28 }
29
30 24 return success;
31 }
32
33 290 bool ReadRowData(std::ifstream &file, MatrixCRS &matrix, int row_index) {
34 290 int nonzeros = 0;
35 290 file >> nonzeros;
36
37
2/2
✓ Branch 0 taken 674 times.
✓ Branch 1 taken 290 times.
964 for (int j = 0; j < nonzeros; ++j) {
38 674 int col_idx = 0;
39 674 file >> col_idx;
40
2/2
✓ Branch 0 taken 607 times.
✓ Branch 1 taken 67 times.
674 matrix.col_indices.push_back(col_idx);
41 }
42
43
2/2
✓ Branch 0 taken 674 times.
✓ Branch 1 taken 290 times.
964 for (int j = 0; j < nonzeros; ++j) {
44 674 double value = 0.0;
45 file >> value;
46
2/2
✓ Branch 0 taken 607 times.
✓ Branch 1 taken 67 times.
674 matrix.values.push_back(value);
47 }
48
49 290 matrix.row_pointers[static_cast<size_t>(row_index) + 1] =
50 290 matrix.row_pointers[static_cast<size_t>(row_index)] + nonzeros;
51
52 290 return true;
53 }
54
55 24 bool ReadMatrixFromFileImpl(const std::string &filename, MatrixCRS &matrix) {
56 24 std::ifstream file(filename);
57
58
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 bool success = ReadDimensions(file, matrix);
59
60
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 matrix.row_pointers.resize(static_cast<size_t>(matrix.rows) + 1);
61 24 matrix.row_pointers[0] = 0;
62
63
2/2
✓ Branch 0 taken 290 times.
✓ Branch 1 taken 24 times.
314 for (int i = 0; i < matrix.rows; ++i) {
64
2/4
✓ Branch 0 taken 290 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 290 times.
✗ Branch 4 not taken.
290 success = success && ReadRowData(file, matrix, i);
65 }
66
67
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 file.close();
68 24 return success;
69 24 }
70
71
1/2
✓ Branch 0 taken 144 times.
✗ Branch 1 not taken.
144 void ProcessRowMultiplication(const MatrixCRS &a, const MatrixCRS &b, int row_index, std::vector<double> &row_values) {
72 std::ranges::fill(row_values, 0.0);
73
74 144 int row_start_a = a.row_pointers[static_cast<size_t>(row_index)];
75 144 int row_end_a = a.row_pointers[static_cast<size_t>(row_index) + 1];
76
77
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 144 times.
242 for (int k = row_start_a; k < row_end_a; ++k) {
78 98 int col_a = a.col_indices[static_cast<size_t>(k)];
79 98 double val_a = a.values[static_cast<size_t>(k)];
80
81 98 int row_start_b = b.row_pointers[static_cast<size_t>(col_a)];
82 98 int row_end_b = b.row_pointers[static_cast<size_t>(col_a) + 1];
83
84
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 98 times.
242 for (int idx = row_start_b; idx < row_end_b; ++idx) {
85 144 int col_b = b.col_indices[static_cast<size_t>(idx)];
86 144 double val_b = b.values[static_cast<size_t>(idx)];
87 144 row_values[static_cast<size_t>(col_b)] += val_a * val_b;
88 }
89 }
90 144 }
91
92 144 void CollectRowResult(const std::vector<double> &row_values, MatrixCRS &result, int row_index) {
93
2/2
✓ Branch 0 taken 778 times.
✓ Branch 1 taken 144 times.
922 for (size_t j = 0; j < row_values.size(); ++j) {
94
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 654 times.
778 if (row_values[j] != 0.0) {
95
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 39 times.
124 result.values.push_back(row_values[j]);
96 124 result.col_indices.push_back(static_cast<int>(j));
97 }
98 }
99
100 144 result.row_pointers[static_cast<size_t>(row_index) + 1] = static_cast<int>(result.values.size());
101 144 }
102
103 24 MatrixCRS MultiplyMatricesImpl(const MatrixCRS &a, const MatrixCRS &b) {
104 24 MatrixCRS result;
105 24 result.rows = a.rows;
106 24 result.cols = b.cols;
107
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 result.row_pointers.resize(static_cast<size_t>(result.rows) + 1);
108
109
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (result.row_pointers.empty()) {
110 return result;
111 }
112
113 24 result.row_pointers[0] = 0;
114
115
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 std::vector<double> row_values(static_cast<size_t>(result.cols), 0.0);
116
117
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 24 times.
168 for (int i = 0; i < a.rows; ++i) {
118 144 ProcessRowMultiplication(a, b, i, row_values);
119
1/2
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
144 CollectRowResult(row_values, result, i);
120 }
121
122 return result;
123 }
124
125 double SumMatrixElementsImpl(const MatrixCRS &matrix) {
126 double sum = 0.0;
127
128
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 12 times.
136 for (double value : matrix.values) {
129 124 sum += value;
130 }
131
132 return sum;
133 }
134
135 108 std::vector<int> GetLocalRowsImpl(int rank, int size, int total_rows) {
136 108 std::vector<int> local_rows;
137 108 int rows_per_process = total_rows / size;
138 108 int remainder = total_rows % size;
139
140
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 24 times.
108 int start_row = (rank * rows_per_process) + std::min(rank, remainder);
141
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 24 times.
108 int end_row = start_row + rows_per_process + (rank < remainder ? 1 : 0);
142
143
2/2
✓ Branch 0 taken 636 times.
✓ Branch 1 taken 108 times.
744 for (int i = start_row; i < end_row; ++i) {
144 local_rows.push_back(i);
145 }
146
147 108 return local_rows;
148 }
149
150 10 void PrepareRowDataForSending(const std::vector<int> &proc_rows, const MatrixCRS &matrix_a, std::vector<int> &row_nnz,
151 std::vector<int> &col_indices, std::vector<double> &values) {
152
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 10 times.
78 for (int row_idx : proc_rows) {
153
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 24 times.
68 int row_start = matrix_a.row_pointers[static_cast<size_t>(row_idx)];
154 68 int row_end = matrix_a.row_pointers[static_cast<size_t>(row_idx) + 1];
155
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 24 times.
68 int row_nnz_count = row_end - row_start;
156 row_nnz.push_back(row_nnz_count);
157
158
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 68 times.
113 for (int i = row_start; i < row_end; ++i) {
159
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 17 times.
45 col_indices.push_back(matrix_a.col_indices[static_cast<size_t>(i)]);
160 }
161
162
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 68 times.
113 for (int i = row_start; i < row_end; ++i) {
163
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 17 times.
45 values.push_back(matrix_a.values[static_cast<size_t>(i)]);
164 }
165 }
166 10 }
167
168 10 void SendRowDataToProcess(int proc, const std::vector<int> &row_nnz, const std::vector<int> &col_indices,
169 const std::vector<double> &values) {
170 10 int row_nnz_size = static_cast<int>(row_nnz.size());
171 10 MPI_Send(row_nnz.data(), row_nnz_size, MPI_INT, proc, 1, MPI_COMM_WORLD);
172
173 10 int col_indices_size = static_cast<int>(col_indices.size());
174 10 MPI_Send(&col_indices_size, 1, MPI_INT, proc, 2, MPI_COMM_WORLD);
175
176
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (col_indices_size > 0) {
177 6 MPI_Send(col_indices.data(), col_indices_size, MPI_INT, proc, 3, MPI_COMM_WORLD);
178 }
179
180 10 int values_size = static_cast<int>(values.size());
181 10 MPI_Send(&values_size, 1, MPI_INT, proc, 4, MPI_COMM_WORLD);
182
183
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (values_size > 0) {
184 6 MPI_Send(values.data(), values_size, MPI_DOUBLE, proc, 5, MPI_COMM_WORLD);
185 }
186 10 }
187
188 12 void SendMatrixDataToProcess(int proc, const std::vector<int> &proc_rows, const MatrixCRS &matrix_a) {
189 12 int num_rows = static_cast<int>(proc_rows.size());
190 12 MPI_Send(&num_rows, 1, MPI_INT, proc, 0, MPI_COMM_WORLD);
191
192
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 if (num_rows > 0) {
193 10 std::vector<int> row_nnz;
194 10 std::vector<int> col_indices;
195 10 std::vector<double> values;
196
197
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 PrepareRowDataForSending(proc_rows, matrix_a, row_nnz, col_indices, values);
198
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 SendRowDataToProcess(proc, row_nnz, col_indices, values);
199 }
200 12 }
201
202 10 void ReceiveRowDataFromMaster(int num_rows, std::vector<int> &row_nnz, std::vector<int> &col_indices,
203 std::vector<double> &values) {
204 10 row_nnz.resize(static_cast<size_t>(num_rows));
205 10 MPI_Recv(row_nnz.data(), num_rows, MPI_INT, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
206
207 10 int col_indices_size = 0;
208 10 MPI_Recv(&col_indices_size, 1, MPI_INT, 0, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
209
210
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (col_indices_size > 0) {
211 6 col_indices.resize(static_cast<size_t>(col_indices_size));
212 6 MPI_Recv(col_indices.data(), col_indices_size, MPI_INT, 0, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
213 }
214
215 10 int values_size = 0;
216 10 MPI_Recv(&values_size, 1, MPI_INT, 0, 4, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
217
218
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 if (values_size > 0) {
219 6 values.resize(static_cast<size_t>(values_size));
220 6 MPI_Recv(values.data(), values_size, MPI_DOUBLE, 0, 5, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
221 }
222 10 }
223
224 10 void BuildLocalMatrixFromReceivedData(const std::vector<int> &row_nnz, const std::vector<int> &col_indices,
225 const std::vector<double> &values, MatrixCRS &local_a_rows) {
226 10 local_a_rows.row_pointers.resize(static_cast<size_t>(local_a_rows.rows) + 1);
227 10 local_a_rows.row_pointers[0] = 0;
228
229 size_t col_idx_pos = 0;
230 size_t val_pos = 0;
231
232
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 10 times.
78 for (int i = 0; i < local_a_rows.rows; ++i) {
233 68 int nnz = row_nnz[static_cast<size_t>(i)];
234
235
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 68 times.
113 for (int j = 0; j < nnz; ++j) {
236
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 17 times.
45 local_a_rows.col_indices.push_back(col_indices[col_idx_pos]);
237 45 col_idx_pos++;
238
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 17 times.
45 local_a_rows.values.push_back(values[val_pos]);
239 val_pos++;
240 }
241
242 68 local_a_rows.row_pointers[i + 1] = local_a_rows.row_pointers[i] + nnz;
243 }
244 10 }
245
246 12 void ReceiveMatrixDataFromMaster(int rank, int size, MatrixCRS &local_a_rows, std::vector<int> &local_rows,
247 int rows_a) {
248 12 int num_rows = 0;
249 12 MPI_Recv(&num_rows, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
250 12 local_rows = GetLocalRowsImpl(rank, size, rows_a);
251
252
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 if (num_rows > 0) {
253 10 std::vector<int> row_nnz;
254 10 std::vector<int> col_indices;
255 10 std::vector<double> values;
256
257 10 local_a_rows.rows = num_rows;
258
259
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 ReceiveRowDataFromMaster(num_rows, row_nnz, col_indices, values);
260
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 BuildLocalMatrixFromReceivedData(row_nnz, col_indices, values, local_a_rows);
261 }
262 12 }
263
264 76 void ProcessLocalRowForInitialization(int global_row, const MatrixCRS &matrix_a, MatrixCRS &local_a_rows,
265 size_t local_index) {
266 76 int row_start = matrix_a.row_pointers[static_cast<size_t>(global_row)];
267 76 int row_end = matrix_a.row_pointers[static_cast<size_t>(global_row) + 1];
268 76 int row_nnz_count = row_end - row_start;
269
270
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 76 times.
129 for (int j = row_start; j < row_end; ++j) {
271
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 26 times.
53 local_a_rows.col_indices.push_back(matrix_a.col_indices[static_cast<size_t>(j)]);
272
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 26 times.
53 local_a_rows.values.push_back(matrix_a.values[static_cast<size_t>(j)]);
273 }
274
275 76 local_a_rows.row_pointers[local_index + 1] = local_a_rows.row_pointers[local_index] + row_nnz_count;
276 76 }
277
278 12 void InitializeLocalRowsOnMaster(int rank, int size, MatrixCRS &matrix_a, MatrixCRS &local_a_rows,
279 std::vector<int> &local_rows) {
280 24 local_rows = GetLocalRowsImpl(rank, size, matrix_a.rows);
281 12 local_a_rows.rows = static_cast<int>(local_rows.size());
282 12 local_a_rows.cols = matrix_a.cols;
283 12 local_a_rows.row_pointers.resize(static_cast<size_t>(local_a_rows.rows) + 1);
284 12 local_a_rows.row_pointers[0] = 0;
285
286
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 12 times.
88 for (size_t i = 0; i < local_rows.size(); ++i) {
287 76 int global_row = local_rows[i];
288 76 ProcessLocalRowForInitialization(global_row, matrix_a, local_a_rows, i);
289 }
290 12 }
291
292 12 void GatherLocalRowCountsMaster(const MatrixCRS &local_result, const std::vector<int> &local_rows,
293 std::vector<int> &all_nnz_counts) {
294 12 std::vector<int> local_nnz_counts;
295
296
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 12 times.
88 for (size_t i = 0; i < local_rows.size(); ++i) {
297
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 32 times.
76 int row_nnz = local_result.row_pointers[i + 1] - local_result.row_pointers[i];
298 local_nnz_counts.push_back(row_nnz);
299 }
300
301
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 12 times.
88 for (size_t i = 0; i < local_rows.size(); ++i) {
302 76 int global_row = local_rows[i];
303 76 all_nnz_counts[static_cast<size_t>(global_row)] = local_nnz_counts[i];
304 }
305 12 }
306
307 12 void GatherLocalRowCountsWorker(const MatrixCRS &local_result, const std::vector<int> &local_rows) {
308 12 std::vector<int> local_nnz_counts;
309
310
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 12 times.
80 for (size_t i = 0; i < local_rows.size(); ++i) {
311
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 24 times.
68 int row_nnz = local_result.row_pointers[i + 1] - local_result.row_pointers[i];
312 local_nnz_counts.push_back(row_nnz);
313 }
314
315
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 if (!local_nnz_counts.empty()) {
316
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 MPI_Send(local_nnz_counts.data(), static_cast<int>(local_nnz_counts.size()), MPI_INT, 0, 0, MPI_COMM_WORLD);
317 } else {
318 2 int dummy = 0;
319
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 MPI_Send(&dummy, 0, MPI_INT, 0, 0, MPI_COMM_WORLD);
320 }
321 12 }
322
323 12 void ReceiveRowCountsFromProcesses(int size, int rows_a, std::vector<int> &all_nnz_counts) {
324
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (int proc = 1; proc < size; ++proc) {
325 12 std::vector<int> proc_rows = GetLocalRowsImpl(proc, size, rows_a);
326 12 int proc_num_rows = static_cast<int>(proc_rows.size());
327
328
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 if (proc_num_rows > 0) {
329
2/6
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
10 std::vector<int> proc_nnz_counts(static_cast<size_t>(proc_num_rows));
330
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 MPI_Recv(proc_nnz_counts.data(), proc_num_rows, MPI_INT, proc, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
331
332
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 10 times.
78 for (int i = 0; i < proc_num_rows; ++i) {
333 68 int global_row = proc_rows[static_cast<size_t>(i)];
334 68 all_nnz_counts[static_cast<size_t>(global_row)] = proc_nnz_counts[static_cast<size_t>(i)];
335 }
336 } else {
337 2 int dummy = 0;
338
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 MPI_Recv(&dummy, 0, MPI_INT, proc, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
339 }
340 }
341 12 }
342
343 24 void GatherRowCounts(int rank, int size, const MatrixCRS &local_result, MatrixCRS &result_matrix) {
344 24 std::vector<int> local_rows = GetLocalRowsImpl(rank, size, result_matrix.rows);
345
346
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
347
1/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 std::vector<int> all_nnz_counts(static_cast<size_t>(result_matrix.rows), 0);
348
349
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 GatherLocalRowCountsMaster(local_result, local_rows, all_nnz_counts);
350
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 ReceiveRowCountsFromProcesses(size, result_matrix.rows, all_nnz_counts);
351
352 12 result_matrix.row_pointers[0] = 0;
353
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 12 times.
156 for (int i = 0; i < result_matrix.rows; ++i) {
354 144 result_matrix.row_pointers[i + 1] = result_matrix.row_pointers[i] + all_nnz_counts[static_cast<size_t>(i)];
355 }
356
357
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (int proc = 1; proc < size; ++proc) {
358
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Send(result_matrix.row_pointers.data(), result_matrix.rows + 1, MPI_INT, proc, 1, MPI_COMM_WORLD);
359 }
360 } else {
361
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 GatherLocalRowCountsWorker(local_result, local_rows);
362
363
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Recv(result_matrix.row_pointers.data(), result_matrix.rows + 1, MPI_INT, 0, 1, MPI_COMM_WORLD,
364 MPI_STATUS_IGNORE);
365 }
366 24 }
367
368 12 void SendLocalRowDataToMaster(const MatrixCRS &local_result, const std::vector<int> &local_rows) {
369
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 12 times.
80 for (size_t i = 0; i < local_rows.size(); ++i) {
370 68 int global_row = local_rows[i];
371 68 int local_start = local_result.row_pointers[i];
372 68 int local_end = local_result.row_pointers[i + 1];
373 68 int row_nnz = local_end - local_start;
374
375
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 30 times.
68 if (row_nnz > 0) {
376 38 MPI_Send(&local_result.col_indices[static_cast<size_t>(local_start)], row_nnz, MPI_INT, 0, global_row * 2,
377 MPI_COMM_WORLD);
378 38 MPI_Send(&local_result.values[static_cast<size_t>(local_start)], row_nnz, MPI_DOUBLE, 0, (global_row * 2) + 1,
379 MPI_COMM_WORLD);
380 }
381 }
382 12 }
383
384 12 void ReceiveRowDataFromProcess(int proc, int size, MatrixCRS &result_matrix) {
385 12 std::vector<int> proc_rows = GetLocalRowsImpl(proc, size, result_matrix.rows);
386
387
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 12 times.
80 for (int global_row : proc_rows) {
388
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 30 times.
68 int row_start = result_matrix.row_pointers[static_cast<size_t>(global_row)];
389 68 int row_end = result_matrix.row_pointers[static_cast<size_t>(global_row) + 1];
390 68 int row_nnz = row_end - row_start;
391
392
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 30 times.
68 if (row_nnz > 0) {
393
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 MPI_Recv(&result_matrix.col_indices[static_cast<size_t>(row_start)], row_nnz, MPI_INT, proc, global_row * 2,
394 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
395
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 MPI_Recv(&result_matrix.values[static_cast<size_t>(row_start)], row_nnz, MPI_DOUBLE, proc, (global_row * 2) + 1,
396 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
397 }
398 }
399 12 }
400
401 12 void GatherLocalRowDataOnMaster(const MatrixCRS &local_result, const std::vector<int> &local_rows,
402 MatrixCRS &result_matrix) {
403
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 12 times.
88 for (size_t i = 0; i < local_rows.size(); ++i) {
404 76 int global_row = local_rows[i];
405 76 int local_start = local_result.row_pointers[i];
406 76 int local_end = local_result.row_pointers[i + 1];
407 76 int row_nnz = local_end - local_start;
408
409
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 45 times.
76 if (row_nnz > 0) {
410 31 int row_start = result_matrix.row_pointers[static_cast<size_t>(global_row)];
411
412 31 std::copy(local_result.col_indices.begin() + static_cast<std::vector<int>::difference_type>(local_start),
413 local_result.col_indices.begin() + static_cast<std::vector<int>::difference_type>(local_end),
414 result_matrix.col_indices.begin() + static_cast<std::vector<int>::difference_type>(row_start));
415
416 31 std::copy(local_result.values.begin() + static_cast<std::vector<double>::difference_type>(local_start),
417 local_result.values.begin() + static_cast<std::vector<double>::difference_type>(local_end),
418 result_matrix.values.begin() + static_cast<std::vector<double>::difference_type>(row_start));
419 }
420 }
421 12 }
422
423 24 void GatherRowData(int rank, int size, const MatrixCRS &local_result, MatrixCRS &result_matrix) {
424 24 std::vector<int> local_rows = GetLocalRowsImpl(rank, size, result_matrix.rows);
425
426
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
427 12 GatherLocalRowDataOnMaster(local_result, local_rows, result_matrix);
428
429
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (int proc = 1; proc < size; ++proc) {
430
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 ReceiveRowDataFromProcess(proc, size, result_matrix);
431 }
432 } else {
433
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 SendLocalRowDataToMaster(local_result, local_rows);
434 }
435 24 }
436
437 } // namespace
438
439 24 YakimovIMultiplicationOfSparseMatricesMPI::YakimovIMultiplicationOfSparseMatricesMPI(const InType &in) {
440 SetTypeOfTask(GetStaticTypeOfTask());
441 24 GetInput() = in;
442 GetOutput() = 0.0;
443
444
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
48 matrix_A_filename_ = ppc::util::GetAbsoluteTaskPath("yakimov_i_multiplication_of_sparse_matrices_crs_storage_format",
445 48 "A_" + std::to_string(GetInput()) + ".txt");
446
2/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
48 matrix_B_filename_ = ppc::util::GetAbsoluteTaskPath("yakimov_i_multiplication_of_sparse_matrices_crs_storage_format",
447
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
48 "B_" + std::to_string(GetInput()) + ".txt");
448 24 }
449
450 24 bool YakimovIMultiplicationOfSparseMatricesMPI::ValidationImpl() {
451 24 int rank = 0;
452 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
453
454
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
455 12 bool input_valid = (GetInput() > 0);
456 12 bool output_valid = (GetOutput() == 0.0);
457 12 return input_valid && output_valid;
458 }
459
460 return true;
461 }
462
463 24 bool YakimovIMultiplicationOfSparseMatricesMPI::PreProcessingImpl() {
464 24 int rank = 0;
465 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
466
467 bool success = true;
468
469
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
470
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 success = success && ReadMatrixFromFileImpl(matrix_A_filename_, matrix_A_);
471
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 success = success && ReadMatrixFromFileImpl(matrix_B_filename_, matrix_B_);
472
473 if (!success) {
474 return false;
475 }
476
477
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (matrix_A_.cols != matrix_B_.rows) {
478 return false;
479 }
480 }
481
482 24 BroadcastMatrixInfo();
483 24 MPI_Barrier(MPI_COMM_WORLD);
484
485 return success;
486 }
487
488 24 void YakimovIMultiplicationOfSparseMatricesMPI::BroadcastMatrixInfo() {
489 24 int rank = 0;
490 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
491
492 24 std::array<int, 4> matrix_info = {0, 0, 0, 0};
493
494
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
495 12 matrix_info[0] = matrix_A_.rows;
496 12 matrix_info[1] = matrix_A_.cols;
497 12 matrix_info[2] = matrix_B_.rows;
498 12 matrix_info[3] = matrix_B_.cols;
499 }
500
501 24 MPI_Bcast(matrix_info.data(), 4, MPI_INT, 0, MPI_COMM_WORLD);
502
503 24 rows_A_ = matrix_info[0];
504 24 cols_A_ = matrix_info[1];
505 24 rows_B_ = matrix_info[2];
506 24 cols_B_ = matrix_info[3];
507 24 }
508
509 24 void YakimovIMultiplicationOfSparseMatricesMPI::DistributeMatrixA() {
510 24 int rank = 0;
511 24 int size = 0;
512 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
513 24 MPI_Comm_size(MPI_COMM_WORLD, &size);
514
515
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
516
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (int proc = 1; proc < size; ++proc) {
517 12 std::vector<int> proc_rows = GetLocalRowsImpl(proc, size, matrix_A_.rows);
518
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 SendMatrixDataToProcess(proc, proc_rows, matrix_A_);
519 }
520
521 12 InitializeLocalRowsOnMaster(rank, size, matrix_A_, local_a_rows_, local_rows_);
522 } else {
523 12 ReceiveMatrixDataFromMaster(rank, size, local_a_rows_, local_rows_, rows_A_);
524 }
525 24 }
526
527 24 void YakimovIMultiplicationOfSparseMatricesMPI::DistributeMatrixB() {
528 24 int rank = 0;
529 24 int size = 0;
530 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
531 24 MPI_Comm_size(MPI_COMM_WORLD, &size);
532
533
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
534 12 int total_nnz = static_cast<int>(matrix_B_.values.size());
535 12 MPI_Bcast(&total_nnz, 1, MPI_INT, 0, MPI_COMM_WORLD);
536
537
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (total_nnz > 0) {
538 12 MPI_Bcast(matrix_B_.row_pointers.data(), matrix_B_.rows + 1, MPI_INT, 0, MPI_COMM_WORLD);
539 12 MPI_Bcast(matrix_B_.col_indices.data(), total_nnz, MPI_INT, 0, MPI_COMM_WORLD);
540 12 MPI_Bcast(matrix_B_.values.data(), total_nnz, MPI_DOUBLE, 0, MPI_COMM_WORLD);
541 }
542
543 12 matrix_B_.rows = rows_B_;
544 12 matrix_B_.cols = cols_B_;
545 } else {
546 12 int total_nnz = 0;
547 12 MPI_Bcast(&total_nnz, 1, MPI_INT, 0, MPI_COMM_WORLD);
548
549
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (total_nnz > 0) {
550 12 matrix_B_.rows = rows_B_;
551 12 matrix_B_.cols = cols_B_;
552 12 matrix_B_.row_pointers.resize(static_cast<size_t>(matrix_B_.rows) + 1);
553 12 matrix_B_.col_indices.resize(static_cast<size_t>(total_nnz));
554 12 matrix_B_.values.resize(static_cast<size_t>(total_nnz));
555
556 12 MPI_Bcast(matrix_B_.row_pointers.data(), matrix_B_.rows + 1, MPI_INT, 0, MPI_COMM_WORLD);
557 12 MPI_Bcast(matrix_B_.col_indices.data(), total_nnz, MPI_INT, 0, MPI_COMM_WORLD);
558 12 MPI_Bcast(matrix_B_.values.data(), total_nnz, MPI_DOUBLE, 0, MPI_COMM_WORLD);
559 }
560 }
561 24 }
562
563 24 void YakimovIMultiplicationOfSparseMatricesMPI::GatherResults() {
564 24 int rank = 0;
565 24 int size = 0;
566 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
567 24 MPI_Comm_size(MPI_COMM_WORLD, &size);
568
569
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
570 12 result_matrix_.rows = rows_A_;
571 12 result_matrix_.cols = cols_B_;
572 }
573
574 24 std::array<int, 2> dims = {rows_A_, cols_B_};
575 24 MPI_Bcast(dims.data(), 2, MPI_INT, 0, MPI_COMM_WORLD);
576
577
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank != 0) {
578 12 result_matrix_.rows = dims[0];
579 12 result_matrix_.cols = dims[1];
580 }
581
582 24 result_matrix_.row_pointers.resize(static_cast<size_t>(result_matrix_.rows) + 1);
583 24 GatherRowCounts(rank, size, local_result_, result_matrix_);
584
585
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
586 12 int total_nnz = result_matrix_.row_pointers[static_cast<size_t>(rows_A_)];
587 12 result_matrix_.col_indices.resize(static_cast<size_t>(total_nnz));
588 12 result_matrix_.values.resize(static_cast<size_t>(total_nnz));
589 }
590
591 24 GatherRowData(rank, size, local_result_, result_matrix_);
592 24 }
593
594 24 bool YakimovIMultiplicationOfSparseMatricesMPI::RunImpl() {
595 24 int rank = 0;
596 24 int size = 0;
597 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
598 24 MPI_Comm_size(MPI_COMM_WORLD, &size);
599
600 24 DistributeMatrixA();
601 24 DistributeMatrixB();
602 24 MPI_Barrier(MPI_COMM_WORLD);
603
604 24 local_result_ = MultiplyMatricesImpl(local_a_rows_, matrix_B_);
605 24 MPI_Barrier(MPI_COMM_WORLD);
606
607 24 GatherResults();
608
609 24 return true;
610 }
611
612 24 bool YakimovIMultiplicationOfSparseMatricesMPI::PostProcessingImpl() {
613 24 int rank = 0;
614 24 int size = 0;
615 24 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
616 24 MPI_Comm_size(MPI_COMM_WORLD, &size);
617
618
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
619 double sum = SumMatrixElementsImpl(result_matrix_);
620 12 GetOutput() = sum;
621 }
622
623 24 double final_result = 0.0;
624
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank == 0) {
625 12 final_result = GetOutput();
626 }
627
628 24 MPI_Bcast(&final_result, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
629 24 GetOutput() = final_result;
630
631 24 return true;
632 }
633
634 } // namespace yakimov_i_multiplication_of_sparse_matrices_crs_storage_format
635