GCC Code Coverage Report


Directory: ./
File: tasks/badanov_a_sparse_matrix_mult_double_ccs/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 187 193 96.9%
Functions: 9 9 100.0%
Branches: 121 214 56.5%

Line Branch Exec Source
1 #include "badanov_a_sparse_matrix_mult_double_ccs/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cmath>
6 #include <cstddef>
7 #include <tuple>
8 #include <utility>
9 #include <vector>
10
11 #include "badanov_a_sparse_matrix_mult_double_ccs/common/include/common.hpp"
12
13 namespace badanov_a_sparse_matrix_mult_double_ccs {
14
15
1/2
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
30 BadanovASparseMatrixMultDoubleCcsMPI::BadanovASparseMatrixMultDoubleCcsMPI(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17 GetInput() = in;
18 30 GetOutput() = {};
19 30 }
20
21 30 bool BadanovASparseMatrixMultDoubleCcsMPI::ValidationImpl() {
22 30 int world_size = 0;
23 30 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
24
25 const auto &in = GetInput();
26
27 const auto &values_a = std::get<0>(in);
28 const auto &row_indices_a = std::get<1>(in);
29 const auto &col_pointers_a = std::get<2>(in);
30 const auto &values_b = std::get<3>(in);
31 const auto &row_indices_b = std::get<4>(in);
32 const auto &col_pointers_b = std::get<5>(in);
33 30 int rows_a = std::get<6>(in);
34 30 int cols_a = std::get<7>(in);
35 30 int cols_b = std::get<8>(in);
36
37
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
30 if (rows_a <= 0 || cols_a <= 0 || cols_b <= 0) {
38 return false;
39 }
40
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (values_a.size() != row_indices_a.size()) {
41 return false;
42 }
43
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (col_pointers_a.size() != static_cast<size_t>(cols_a) + 1) {
44 return false;
45 }
46
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (values_b.size() != row_indices_b.size()) {
47 return false;
48 }
49
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (col_pointers_b.size() != static_cast<size_t>(cols_b) + 1) {
50 return false;
51 }
52
53 return true;
54 }
55
56 30 bool BadanovASparseMatrixMultDoubleCcsMPI::PreProcessingImpl() {
57 30 return true;
58 }
59
60 30 BadanovASparseMatrixMultDoubleCcsMPI::LocalData BadanovASparseMatrixMultDoubleCcsMPI::DistributeDataHorizontal(
61 int world_rank, int world_size, const SparseMatrix &a, const SparseMatrix &b) {
62 30 LocalData local;
63 30 local.global_rows = a.rows;
64 30 local.global_inner_dim = a.cols;
65 30 local.global_cols = b.cols;
66
67 30 int rows_per_proc = a.rows / world_size;
68 30 int extra_rows = a.rows % world_size;
69
70 30 int local_start_row = world_rank * rows_per_proc;
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (world_rank < extra_rows) {
72 local_start_row += world_rank;
73 } else {
74 30 local_start_row += extra_rows;
75 }
76
77
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 int local_rows = rows_per_proc + (world_rank < extra_rows ? 1 : 0);
78
79
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (local_rows == 0) {
80 local.a_local.rows = 0;
81 local.a_local.cols = a.cols;
82 local.a_local.col_pointers.resize(a.cols + 1, 0);
83 local.b_local = b;
84 return local;
85 }
86
87 30 std::vector<double> local_a_values;
88 30 std::vector<int> local_a_row_indices;
89
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<int> local_a_col_pointers(a.cols + 1, 0);
90 30 int local_end_row = local_start_row + local_rows;
91
92
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<std::vector<double>> temp_values(a.cols);
93
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 std::vector<std::vector<int>> temp_indices(a.cols);
94
95
2/2
✓ Branch 0 taken 10020 times.
✓ Branch 1 taken 30 times.
10050 for (int col = 0; col < a.cols; ++col) {
96
2/2
✓ Branch 0 taken 183504 times.
✓ Branch 1 taken 10020 times.
193524 for (int idx = a.col_pointers[col]; idx < a.col_pointers[col + 1]; ++idx) {
97
2/2
✓ Branch 0 taken 91752 times.
✓ Branch 1 taken 91752 times.
183504 int row = a.row_indices[idx];
98 183504 double val = a.values[idx];
99
100
2/2
✓ Branch 0 taken 91752 times.
✓ Branch 1 taken 91752 times.
183504 if (row >= local_start_row && row < local_end_row) {
101 temp_values[col].push_back(val);
102
1/2
✓ Branch 1 taken 91752 times.
✗ Branch 2 not taken.
91752 temp_indices[col].push_back(row - local_start_row);
103 }
104 }
105 }
106
107
2/2
✓ Branch 0 taken 10020 times.
✓ Branch 1 taken 30 times.
10050 for (int col = 0; col < a.cols; ++col) {
108 10020 local_a_col_pointers[col + 1] = local_a_col_pointers[col] + static_cast<int>(temp_values[col].size());
109
110
2/2
✓ Branch 0 taken 91752 times.
✓ Branch 1 taken 10020 times.
101772 for (size_t i = 0; i < temp_values[col].size(); ++i) {
111 local_a_values.push_back(temp_values[col][i]);
112 local_a_row_indices.push_back(temp_indices[col][i]);
113 }
114 }
115
116 30 local.a_local.values = std::move(local_a_values);
117 30 local.a_local.row_indices = std::move(local_a_row_indices);
118 30 local.a_local.col_pointers = std::move(local_a_col_pointers);
119 30 local.a_local.rows = local_rows;
120 30 local.a_local.cols = a.cols;
121
122
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 local.b_local = b;
123
124 return local;
125 30 }
126
127 9220 std::vector<double> BadanovASparseMatrixMultDoubleCcsMPI::SparseDotProduct(const SparseMatrix &a, const SparseMatrix &b,
128 int col_b) {
129 9220 std::vector<double> result(a.rows, 0.0);
130
131
2/2
✓ Branch 0 taken 183278 times.
✓ Branch 1 taken 9220 times.
192498 for (int idx_b = b.col_pointers[col_b]; idx_b < b.col_pointers[col_b + 1]; ++idx_b) {
132 183278 int row_b = b.row_indices[idx_b];
133 183278 double val_b = b.values[idx_b];
134
135
2/2
✓ Branch 0 taken 2277491 times.
✓ Branch 1 taken 183278 times.
2460769 for (int idx_a = a.col_pointers[row_b]; idx_a < a.col_pointers[row_b + 1]; ++idx_a) {
136 2277491 int row_a = a.row_indices[idx_a];
137 2277491 double val_a = a.values[idx_a];
138 2277491 result[row_a] += val_a * val_b;
139 }
140 }
141
142 9220 return result;
143 }
144
145 30 SparseMatrix BadanovASparseMatrixMultDoubleCcsMPI::MultiplyLocal(const LocalData &local) {
146 30 std::vector<double> values_c;
147 30 std::vector<int> row_indices_c;
148
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<int> col_pointers_c(local.global_cols + 1, 0);
149
150
2/2
✓ Branch 0 taken 9220 times.
✓ Branch 1 taken 30 times.
9250 for (int col_b = 0; col_b < local.global_cols; ++col_b) {
151
1/2
✓ Branch 1 taken 9220 times.
✗ Branch 2 not taken.
9220 std::vector<double> local_col = SparseDotProduct(local.a_local, local.b_local, col_b);
152
153
2/2
✓ Branch 0 taken 2392600 times.
✓ Branch 1 taken 9220 times.
2401820 for (int row = 0; row < local.a_local.rows; ++row) {
154
2/2
✓ Branch 0 taken 1221186 times.
✓ Branch 1 taken 1171414 times.
2392600 if (std::abs(local_col[row]) > 1e-10) {
155 values_c.push_back(local_col[row]);
156 row_indices_c.push_back(row);
157 1221186 col_pointers_c[col_b + 1]++;
158 }
159 }
160 }
161
162
2/2
✓ Branch 0 taken 9220 times.
✓ Branch 1 taken 30 times.
9250 for (int col = 0; col < local.global_cols; ++col) {
163 9220 col_pointers_c[col + 1] += col_pointers_c[col];
164 }
165
166 30 SparseMatrix c_local;
167
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 c_local.values = values_c;
168
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 c_local.row_indices = row_indices_c;
169
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 c_local.col_pointers = col_pointers_c;
170 30 c_local.rows = local.a_local.rows;
171
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 c_local.cols = local.global_cols;
172
173 30 return c_local;
174 }
175
176 30 void BadanovASparseMatrixMultDoubleCcsMPI::GatherResults(int world_rank, int world_size, const SparseMatrix &local_c,
177 SparseMatrix &global_c) {
178 30 std::vector<int> local_nnz_per_col(local_c.cols, 0);
179
2/2
✓ Branch 0 taken 9220 times.
✓ Branch 1 taken 30 times.
9250 for (int col = 0; col < local_c.cols; ++col) {
180 9220 local_nnz_per_col[col] = local_c.col_pointers[col + 1] - local_c.col_pointers[col];
181 }
182
183
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<int> global_nnz_per_col(local_c.cols, 0);
184
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Allreduce(local_nnz_per_col.data(), global_nnz_per_col.data(), local_c.cols, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
185
186
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 global_c.col_pointers.resize(local_c.cols + 1, 0);
187
2/2
✓ Branch 0 taken 9220 times.
✓ Branch 1 taken 30 times.
9250 for (int col = 0; col < local_c.cols; ++col) {
188 9220 global_c.col_pointers[col + 1] = global_c.col_pointers[col] + global_nnz_per_col[col];
189 }
190
191
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 int total_nnz = global_c.col_pointers[local_c.cols];
192
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 global_c.values.resize(total_nnz);
193
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 global_c.row_indices.resize(total_nnz);
194 30 global_c.rows = local_c.rows * world_size;
195 30 global_c.cols = local_c.cols;
196
197
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<int> displs(world_size, 0);
198
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<int> recvcounts(world_size, 0);
199
200
2/2
✓ Branch 0 taken 9220 times.
✓ Branch 1 taken 30 times.
9250 for (int col = 0; col < local_c.cols; ++col) {
201
1/2
✓ Branch 1 taken 9220 times.
✗ Branch 2 not taken.
9220 int local_start = local_c.col_pointers[col];
202
1/2
✓ Branch 1 taken 9220 times.
✗ Branch 2 not taken.
9220 int local_count = local_c.col_pointers[col + 1] - local_start;
203
204
1/2
✓ Branch 1 taken 9220 times.
✗ Branch 2 not taken.
9220 MPI_Gather(&local_count, 1, MPI_INT, recvcounts.data(), 1, MPI_INT, 0, MPI_COMM_WORLD);
205
206
2/2
✓ Branch 0 taken 4610 times.
✓ Branch 1 taken 4610 times.
9220 if (world_rank == 0) {
207 4610 displs[0] = global_c.col_pointers[col];
208
2/2
✓ Branch 0 taken 4610 times.
✓ Branch 1 taken 4610 times.
9220 for (int i = 1; i < world_size; ++i) {
209 4610 displs[i] = displs[i - 1] + recvcounts[i - 1];
210 }
211 }
212
213
2/2
✓ Branch 0 taken 9147 times.
✓ Branch 1 taken 73 times.
9220 if (local_count > 0) {
214
1/2
✓ Branch 1 taken 9147 times.
✗ Branch 2 not taken.
9147 MPI_Gatherv(&local_c.values[local_start], local_count, MPI_DOUBLE, global_c.values.data(), recvcounts.data(),
215 displs.data(), MPI_DOUBLE, 0, MPI_COMM_WORLD);
216
217
1/4
✓ Branch 1 taken 9147 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9147 std::vector<int> adjusted_rows(local_count);
218 9147 int row_offset = world_rank * local_c.rows;
219
2/2
✓ Branch 0 taken 1221186 times.
✓ Branch 1 taken 9147 times.
1230333 for (int i = 0; i < local_count; ++i) {
220 1221186 adjusted_rows[i] = local_c.row_indices[local_start + i] + row_offset;
221 }
222
223
1/2
✓ Branch 1 taken 9147 times.
✗ Branch 2 not taken.
9147 MPI_Gatherv(adjusted_rows.data(), local_count, MPI_INT, global_c.row_indices.data(), recvcounts.data(),
224 displs.data(), MPI_INT, 0, MPI_COMM_WORLD);
225 } else {
226
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
73 MPI_Gatherv(nullptr, 0, MPI_DOUBLE, global_c.values.data(), recvcounts.data(), displs.data(), MPI_DOUBLE, 0,
227 MPI_COMM_WORLD);
228
229
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
73 MPI_Gatherv(nullptr, 0, MPI_INT, global_c.row_indices.data(), recvcounts.data(), displs.data(), MPI_INT, 0,
230 MPI_COMM_WORLD);
231 }
232 }
233
234
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (world_rank != 0) {
235
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 global_c.values.resize(total_nnz);
236
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 global_c.row_indices.resize(total_nnz);
237
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 global_c.col_pointers.resize(local_c.cols + 1);
238 }
239
240
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(global_c.values.data(), total_nnz, MPI_DOUBLE, 0, MPI_COMM_WORLD);
241
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(global_c.row_indices.data(), total_nnz, MPI_INT, 0, MPI_COMM_WORLD);
242
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(global_c.col_pointers.data(), local_c.cols + 1, MPI_INT, 0, MPI_COMM_WORLD);
243 30 }
244
245 30 bool BadanovASparseMatrixMultDoubleCcsMPI::RunImpl() {
246 30 int world_rank = 0;
247 30 int world_size = 0;
248 30 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
249 30 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
250
251 30 std::vector<double> values_a;
252 30 std::vector<double> values_b;
253 30 std::vector<int> row_indices_a;
254 30 std::vector<int> row_indices_b;
255 30 std::vector<int> col_pointers_a;
256 30 std::vector<int> col_pointers_b;
257 30 int rows_a = 0;
258 30 int cols_a = 0;
259 30 int cols_b = 0;
260
261
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (world_rank == 0) {
262 const auto &in = GetInput();
263
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 values_a = std::get<0>(in);
264
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 row_indices_a = std::get<1>(in);
265
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 col_pointers_a = std::get<2>(in);
266
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 values_b = std::get<3>(in);
267
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 row_indices_b = std::get<4>(in);
268
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 col_pointers_b = std::get<5>(in);
269 15 rows_a = std::get<6>(in);
270 15 cols_a = std::get<7>(in);
271 15 cols_b = std::get<8>(in);
272 }
273
274
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(&rows_a, 1, MPI_INT, 0, MPI_COMM_WORLD);
275
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(&cols_a, 1, MPI_INT, 0, MPI_COMM_WORLD);
276
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(&cols_b, 1, MPI_INT, 0, MPI_COMM_WORLD);
277
278 30 int nnz_a = 0;
279 30 int nnz_b = 0;
280
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (world_rank == 0) {
281 15 nnz_a = static_cast<int>(values_a.size());
282 15 nnz_b = static_cast<int>(values_b.size());
283 }
284
285
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(&nnz_a, 1, MPI_INT, 0, MPI_COMM_WORLD);
286
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(&nnz_b, 1, MPI_INT, 0, MPI_COMM_WORLD);
287
288
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (world_rank != 0) {
289
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 values_a.resize(nnz_a);
290
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 row_indices_a.resize(nnz_a);
291
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 col_pointers_a.resize(cols_a + 1);
292
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 values_b.resize(nnz_b);
293
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 row_indices_b.resize(nnz_b);
294
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 col_pointers_b.resize(cols_b + 1);
295 }
296
297
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(values_a.data(), nnz_a, MPI_DOUBLE, 0, MPI_COMM_WORLD);
298
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(row_indices_a.data(), nnz_a, MPI_INT, 0, MPI_COMM_WORLD);
299
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(col_pointers_a.data(), cols_a + 1, MPI_INT, 0, MPI_COMM_WORLD);
300
301
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(values_b.data(), nnz_b, MPI_DOUBLE, 0, MPI_COMM_WORLD);
302
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(row_indices_b.data(), nnz_b, MPI_INT, 0, MPI_COMM_WORLD);
303
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Bcast(col_pointers_b.data(), cols_b + 1, MPI_INT, 0, MPI_COMM_WORLD);
304
305 30 SparseMatrix a_global;
306
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 a_global.values = values_a;
307
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 a_global.row_indices = row_indices_a;
308
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 a_global.col_pointers = col_pointers_a;
309 30 a_global.rows = rows_a;
310 30 a_global.cols = cols_a;
311
312 30 SparseMatrix b_global;
313
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 b_global.values = values_b;
314
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 b_global.row_indices = row_indices_b;
315
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 b_global.col_pointers = col_pointers_b;
316 30 b_global.rows = cols_a;
317 30 b_global.cols = cols_b;
318
319
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 LocalData local_data = DistributeDataHorizontal(world_rank, world_size, a_global, b_global);
320
321
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 SparseMatrix local_c = MultiplyLocal(local_data);
322
323 30 SparseMatrix global_c;
324
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 GatherResults(world_rank, world_size, local_c, global_c);
325
326 30 GetOutput() = std::make_tuple(global_c.values, global_c.row_indices, global_c.col_pointers);
327
328 30 return true;
329 60 }
330
331 30 bool BadanovASparseMatrixMultDoubleCcsMPI::PostProcessingImpl() {
332 30 return true;
333 }
334
335 } // namespace badanov_a_sparse_matrix_mult_double_ccs
336