GCC Code Coverage Report


Directory: ./
File: tasks/sosnina_a_sparse_matrix_mult_crs_double/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 250 292 85.6%
Functions: 21 24 87.5%
Branches: 162 288 56.2%

Line Branch Exec Source
1 #include "sosnina_a_sparse_matrix_mult_crs_double/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <array>
7 #include <cmath>
8 #include <cstddef>
9 #include <ranges>
10 #include <tuple>
11 #include <utility>
12 #include <vector>
13
14 #include "sosnina_a_sparse_matrix_mult_crs_double/common/include/common.hpp"
15
16 namespace sosnina_a_sparse_matrix_mult_crs_double {
17
18 212 SosninaAMatrixMultCRSMPI::SosninaAMatrixMultCRSMPI(const InType &in)
19 212 : values_A_(std::get<0>(in)),
20
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 col_indices_A_(std::get<1>(in)),
21
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 row_ptr_A_(std::get<2>(in)),
22 212 n_rows_A_(std::get<6>(in)),
23 212 n_cols_A_(std::get<7>(in)),
24
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 values_B_(std::get<3>(in)),
25
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 col_indices_B_(std::get<4>(in)),
26
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 row_ptr_B_(std::get<5>(in)),
27
1/2
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
424 n_cols_B_(std::get<8>(in)) {
28 SetTypeOfTask(GetStaticTypeOfTask());
29 212 }
30
31 212 bool SosninaAMatrixMultCRSMPI::ValidationImpl() {
32 212 int mpi_initialized = 0;
33 212 MPI_Initialized(&mpi_initialized);
34
35
1/2
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
212 if (mpi_initialized == 0) {
36 return false;
37 }
38
39 212 int size = 1;
40 212 MPI_Comm_size(MPI_COMM_WORLD, &size);
41 212 return size >= 1;
42 }
43
44 212 bool SosninaAMatrixMultCRSMPI::PreProcessingImpl() {
45 212 int rank = 0;
46 212 int size = 1;
47 212 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
48 212 MPI_Comm_size(MPI_COMM_WORLD, &size);
49
50 212 rank_ = rank;
51
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 world_size_ = size;
52
53 local_rows_.clear();
54 local_values_A_.clear();
55 local_col_indices_A_.clear();
56 local_row_ptr_A_.clear();
57 local_values_C_.clear();
58 local_col_indices_C_.clear();
59 local_row_ptr_C_.clear();
60
61 values_C_.clear();
62 col_indices_C_.clear();
63 row_ptr_C_.clear();
64
65 212 return true;
66 }
67
68 212 bool SosninaAMatrixMultCRSMPI::RunImpl() {
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 if (world_size_ == 1) {
70 return RunSequential();
71 }
72
73 212 int n_rows_a = 0;
74 212 int n_cols_a = 0;
75 212 int n_cols_b = 0;
76
77
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 if (!PrepareAndValidateSizes(n_rows_a, n_cols_a, n_cols_b)) {
78 return true;
79 }
80
81 212 BroadcastMatrixB();
82
83 212 DistributeMatrixAData();
84
85 212 ComputeLocalMultiplication();
86
87 212 GatherResults();
88
89 return true;
90 }
91
92 bool SosninaAMatrixMultCRSMPI::RunSequential() {
93 if (rank_ != 0) {
94 return true;
95 }
96
97 row_ptr_C_.resize(n_rows_A_ + 1, 0);
98 row_ptr_C_[0] = 0;
99
100 std::vector<std::vector<double>> row_values(n_rows_A_);
101 std::vector<std::vector<int>> row_cols(n_rows_A_);
102
103 for (int i = 0; i < n_rows_A_; i++) {
104 ProcessRowForSequential(i, row_values[i], row_cols[i]);
105 row_ptr_C_[i + 1] = row_ptr_C_[i] + static_cast<int>(row_cols[i].size());
106 }
107
108 for (int i = 0; i < n_rows_A_; i++) {
109 values_C_.insert(values_C_.end(), row_values[i].begin(), row_values[i].end());
110 col_indices_C_.insert(col_indices_C_.end(), row_cols[i].begin(), row_cols[i].end());
111 }
112
113 OutType result = std::make_tuple(values_C_, col_indices_C_, row_ptr_C_);
114 GetOutput() = result;
115
116 return true;
117 }
118
119 void SosninaAMatrixMultCRSMPI::ProcessRowForSequential(int row_idx, std::vector<double> &row_values,
120 std::vector<int> &row_cols) {
121 int row_start_a = row_ptr_A_[row_idx];
122 int row_end_a = row_ptr_A_[row_idx + 1];
123
124 std::vector<double> temp_row(n_cols_B_, 0.0);
125
126 for (int k_idx = row_start_a; k_idx < row_end_a; k_idx++) {
127 double a_val = values_A_[k_idx];
128 int k = col_indices_A_[k_idx];
129
130 int row_start_b = row_ptr_B_[k];
131 int row_end_b = row_ptr_B_[k + 1];
132
133 for (int j_idx = row_start_b; j_idx < row_end_b; j_idx++) {
134 double b_val = values_B_[j_idx];
135 int j = col_indices_B_[j_idx];
136
137 temp_row[j] += a_val * b_val;
138 }
139 }
140
141 for (int j = 0; j < n_cols_B_; j++) {
142 if (std::abs(temp_row[j]) > 1e-12) {
143 row_values.push_back(temp_row[j]);
144 row_cols.push_back(j);
145 }
146 }
147
148 if (!row_cols.empty()) {
149 std::vector<std::pair<int, double>> pairs;
150 pairs.reserve(row_cols.size());
151 for (size_t idx = 0; idx < row_cols.size(); idx++) {
152 pairs.emplace_back(row_cols[idx], row_values[idx]);
153 }
154
155 std::ranges::sort(pairs);
156 static_cast<void>(std::ranges::begin(pairs));
157
158 for (size_t idx = 0; idx < pairs.size(); idx++) {
159 row_cols[idx] = pairs[idx].first;
160 row_values[idx] = pairs[idx].second;
161 }
162 }
163 }
164
165 212 bool SosninaAMatrixMultCRSMPI::PrepareAndValidateSizes(int &n_rows_a, int &n_cols_a, int &n_cols_b) {
166
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 106 times.
212 if (rank_ == 0) {
167 106 n_rows_a = n_rows_A_;
168 106 n_cols_a = n_cols_A_;
169 106 n_cols_b = n_cols_B_;
170 }
171
172 212 std::array<int, 3> sizes = {n_rows_a, n_cols_a, n_cols_b};
173 212 MPI_Bcast(sizes.data(), 3, MPI_INT, 0, MPI_COMM_WORLD);
174
175 212 n_rows_a = sizes[0];
176 212 n_cols_a = sizes[1];
177 212 n_cols_b = sizes[2];
178
179 212 n_rows_A_ = n_rows_a;
180 212 n_cols_A_ = n_cols_a;
181 212 n_cols_B_ = n_cols_b;
182
183
3/6
✓ Branch 0 taken 212 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 212 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 212 times.
212 return n_rows_a > 0 && n_cols_a > 0 && n_cols_b > 0;
184 }
185
186 212 void SosninaAMatrixMultCRSMPI::BroadcastMatrixB() {
187 212 std::array<int, 3> b_sizes = {0, 0, 0};
188
189
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 106 times.
212 if (rank_ == 0) {
190 106 b_sizes[0] = static_cast<int>(values_B_.size());
191 106 b_sizes[1] = static_cast<int>(col_indices_B_.size());
192 106 b_sizes[2] = static_cast<int>(row_ptr_B_.size());
193 }
194
195 212 MPI_Bcast(b_sizes.data(), 3, MPI_INT, 0, MPI_COMM_WORLD);
196
197 212 int values_size = b_sizes[0];
198 212 int indices_size = b_sizes[1];
199 212 int row_ptr_size = b_sizes[2];
200
201
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 106 times.
212 if (rank_ != 0) {
202 106 values_B_.resize(values_size);
203 106 col_indices_B_.resize(indices_size);
204 106 row_ptr_B_.resize(row_ptr_size);
205 }
206
207 212 MPI_Bcast(values_B_.data(), values_size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
208 212 MPI_Bcast(col_indices_B_.data(), indices_size, MPI_INT, 0, MPI_COMM_WORLD);
209 212 MPI_Bcast(row_ptr_B_.data(), row_ptr_size, MPI_INT, 0, MPI_COMM_WORLD);
210 212 }
211
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 212 times.
212 void SosninaAMatrixMultCRSMPI::DistributeMatrixAData() {
213 local_rows_.clear();
214
2/2
✓ Branch 0 taken 460 times.
✓ Branch 1 taken 212 times.
672 for (int i = 0; i < n_rows_A_; ++i) {
215
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 230 times.
460 if (i % world_size_ == rank_) {
216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 230 times.
230 local_rows_.push_back(i);
217 }
218 }
219
220
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 106 times.
212 if (rank_ == 0) {
221
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 106 times.
212 for (int dest = 1; dest < world_size_; ++dest) {
222 106 SendMatrixADataToProcess(dest);
223 }
224
225 local_values_A_.clear();
226 local_col_indices_A_.clear();
227 106 local_row_ptr_A_.resize(local_rows_.size() + 1, 0);
228
229
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 106 times.
240 for (size_t idx = 0; idx < local_rows_.size(); ++idx) {
230 134 int row = local_rows_[idx];
231 134 int row_start = row_ptr_A_[row];
232 134 int row_end = row_ptr_A_[row + 1];
233 134 int row_nnz = row_end - row_start;
234
235 134 local_values_A_.insert(local_values_A_.end(), values_A_.begin() + row_start, values_A_.begin() + row_end);
236
237 134 local_col_indices_A_.insert(local_col_indices_A_.end(), col_indices_A_.begin() + row_start,
238 col_indices_A_.begin() + row_end);
239
240 134 local_row_ptr_A_[idx + 1] = local_row_ptr_A_[idx] + row_nnz;
241 }
242 } else {
243 106 ReceiveMatrixAData();
244 }
245 212 }
246
247 106 void SosninaAMatrixMultCRSMPI::SendMatrixADataToProcess(int dest) {
248 106 std::vector<int> dest_rows;
249
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 106 times.
336 for (int i = 0; i < n_rows_A_; ++i) {
250
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 134 times.
230 if (i % world_size_ == dest) {
251 dest_rows.push_back(i);
252 }
253 }
254
255 106 int dest_row_count = static_cast<int>(dest_rows.size());
256
1/2
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
106 MPI_Send(&dest_row_count, 1, MPI_INT, dest, 0, MPI_COMM_WORLD);
257
258
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 16 times.
106 if (dest_row_count > 0) {
259
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 MPI_Send(dest_rows.data(), dest_row_count, MPI_INT, dest, 1, MPI_COMM_WORLD);
260
261
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 90 times.
186 for (int row : dest_rows) {
262
1/2
✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
96 int row_start = row_ptr_A_[row];
263 96 int row_end = row_ptr_A_[row + 1];
264 96 int row_nnz = row_end - row_start;
265
266
1/2
✓ Branch 1 taken 96 times.
✗ Branch 2 not taken.
96 MPI_Send(&row_nnz, 1, MPI_INT, dest, 2, MPI_COMM_WORLD);
267
268
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 4 times.
96 if (row_nnz > 0) {
269
1/4
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
92 std::vector<double> row_values(values_A_.begin() + row_start, values_A_.begin() + row_end);
270
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
92 MPI_Send(row_values.data(), row_nnz, MPI_DOUBLE, dest, 3, MPI_COMM_WORLD);
271
272
1/4
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
92 std::vector<int> row_cols(col_indices_A_.begin() + row_start, col_indices_A_.begin() + row_end);
273
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
92 MPI_Send(row_cols.data(), row_nnz, MPI_INT, dest, 4, MPI_COMM_WORLD);
274 }
275 }
276 }
277 106 }
278
279 106 void SosninaAMatrixMultCRSMPI::ReceiveMatrixAData() {
280 106 int local_row_count = 0;
281 106 MPI_Recv(&local_row_count, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
282
283
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 16 times.
106 if (local_row_count > 0) {
284 90 local_rows_.resize(local_row_count);
285 90 MPI_Recv(local_rows_.data(), local_row_count, MPI_INT, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
286
287 local_values_A_.clear();
288 local_col_indices_A_.clear();
289 90 local_row_ptr_A_.resize(local_row_count + 1, 0);
290
291
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 90 times.
186 for (int i = 0; i < local_row_count; ++i) {
292 96 int row_nnz = 0;
293 96 MPI_Recv(&row_nnz, 1, MPI_INT, 0, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
294
295
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 4 times.
96 if (row_nnz > 0) {
296 92 std::vector<double> row_values(row_nnz);
297
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
92 MPI_Recv(row_values.data(), row_nnz, MPI_DOUBLE, 0, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
298
299
1/4
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
92 std::vector<int> row_cols(row_nnz);
300
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
92 MPI_Recv(row_cols.data(), row_nnz, MPI_INT, 0, 4, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
301
302
1/2
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
92 local_values_A_.insert(local_values_A_.end(), row_values.begin(), row_values.end());
303
2/4
✓ Branch 1 taken 92 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 92 times.
✗ Branch 4 not taken.
92 local_col_indices_A_.insert(local_col_indices_A_.end(), row_cols.begin(), row_cols.end());
304 }
305
306 96 local_row_ptr_A_[i + 1] = local_row_ptr_A_[i] + row_nnz;
307 }
308 }
309 106 }
310
311 212 void SosninaAMatrixMultCRSMPI::ComputeLocalMultiplication() {
312 212 int local_row_count = static_cast<int>(local_rows_.size());
313
314 212 std::vector<std::vector<double>> local_row_values(local_row_count);
315
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 std::vector<std::vector<int>> local_row_cols(local_row_count);
316
1/2
✓ Branch 1 taken 212 times.
✗ Branch 2 not taken.
212 local_row_ptr_C_.resize(local_row_count + 1, 0);
317
318
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 212 times.
442 for (int local_idx = 0; local_idx < local_row_count; ++local_idx) {
319
1/2
✓ Branch 1 taken 230 times.
✗ Branch 2 not taken.
230 ProcessLocalRow(local_idx, local_row_values[local_idx], local_row_cols[local_idx]);
320 230 local_row_ptr_C_[local_idx + 1] = local_row_ptr_C_[local_idx] + static_cast<int>(local_row_cols[local_idx].size());
321 }
322
323 local_values_C_.clear();
324 local_col_indices_C_.clear();
325
326
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 212 times.
442 for (int i = 0; i < local_row_count; ++i) {
327
1/2
✓ Branch 1 taken 230 times.
✗ Branch 2 not taken.
230 local_values_C_.insert(local_values_C_.end(), local_row_values[i].begin(), local_row_values[i].end());
328
1/2
✓ Branch 1 taken 230 times.
✗ Branch 2 not taken.
230 local_col_indices_C_.insert(local_col_indices_C_.end(), local_row_cols[i].begin(), local_row_cols[i].end());
329 }
330 212 }
331
332 230 void SosninaAMatrixMultCRSMPI::ProcessLocalRow(int local_idx, std::vector<double> &row_values,
333 std::vector<int> &row_cols) {
334 230 int row_start = local_row_ptr_A_[local_idx];
335 230 int row_end = local_row_ptr_A_[local_idx + 1];
336
337 230 std::vector<double> temp_row(n_cols_B_, 0.0);
338
339 MultiplyRowByMatrixB(row_start, row_end, temp_row);
340
341
1/2
✓ Branch 1 taken 230 times.
✗ Branch 2 not taken.
230 CollectNonZeroElements(temp_row, n_cols_B_, row_values, row_cols);
342
343
1/2
✓ Branch 1 taken 230 times.
✗ Branch 2 not taken.
230 SortRowElements(row_values, row_cols);
344 230 }
345
346 void SosninaAMatrixMultCRSMPI::MultiplyRowByMatrixB(int row_start, int row_end, std::vector<double> &temp_row) {
347
2/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 376 times.
✓ Branch 3 taken 230 times.
606 for (int k_idx = row_start; k_idx < row_end; ++k_idx) {
348 376 ProcessElementA(k_idx, temp_row);
349 }
350 }
351
352 376 void SosninaAMatrixMultCRSMPI::ProcessElementA(int k_idx, std::vector<double> &temp_row) {
353
3/6
✓ Branch 0 taken 376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 376 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 376 times.
✗ Branch 5 not taken.
376 if (k_idx < 0 || static_cast<size_t>(k_idx) >= local_values_A_.size() ||
354 static_cast<size_t>(k_idx) >= local_col_indices_A_.size()) {
355 return;
356 }
357
358 376 double a_val = local_values_A_[k_idx];
359 376 int k = local_col_indices_A_[k_idx];
360
361
3/6
✓ Branch 0 taken 376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 376 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 376 times.
✗ Branch 5 not taken.
376 if (k < 0 || k >= n_cols_A_ || k >= static_cast<int>(row_ptr_B_.size()) - 1) {
362 return;
363 }
364
365 376 MultiplyByRowB(k, a_val, temp_row);
366 }
367
368 376 void SosninaAMatrixMultCRSMPI::MultiplyByRowB(int k, double a_val, std::vector<double> &temp_row) {
369
1/2
✓ Branch 0 taken 376 times.
✗ Branch 1 not taken.
376 int b_row_start = row_ptr_B_[k];
370 376 int b_row_end = row_ptr_B_[k + 1];
371
372
3/6
✓ Branch 0 taken 376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 376 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 376 times.
✗ Branch 5 not taken.
376 if (b_row_start < 0 || static_cast<size_t>(b_row_end) > values_B_.size() || b_row_start > b_row_end) {
373 return;
374 }
375
2/2
✓ Branch 0 taken 760 times.
✓ Branch 1 taken 376 times.
1136 for (int j_idx = b_row_start; j_idx < b_row_end; ++j_idx) {
376
2/4
✓ Branch 0 taken 760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 760 times.
✗ Branch 3 not taken.
760 if (j_idx < 0 || static_cast<size_t>(j_idx) >= values_B_.size() ||
377 static_cast<size_t>(j_idx) >= col_indices_B_.size()) {
378 continue;
379 }
380
381 760 double b_val = values_B_[j_idx];
382 760 int j = col_indices_B_[j_idx];
383
384
2/4
✓ Branch 0 taken 760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 760 times.
✗ Branch 3 not taken.
760 if (j >= 0 && j < n_cols_B_) {
385 760 temp_row[j] += a_val * b_val;
386 }
387 }
388 }
389
390 230 void SosninaAMatrixMultCRSMPI::CollectNonZeroElements(const std::vector<double> &temp_row, int n_cols_b,
391 std::vector<double> &row_values, std::vector<int> &row_cols) {
392
2/2
✓ Branch 0 taken 514 times.
✓ Branch 1 taken 230 times.
744 for (int j = 0; j < n_cols_b; ++j) {
393
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 36 times.
514 if (std::abs(temp_row[j]) > 1e-12) {
394 row_values.push_back(temp_row[j]);
395 row_cols.push_back(j);
396 }
397 }
398 230 }
399
400
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 16 times.
230 void SosninaAMatrixMultCRSMPI::SortRowElements(std::vector<double> &row_values, std::vector<int> &row_cols) {
401
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 16 times.
230 if (!row_cols.empty()) {
402
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 std::vector<std::pair<int, double>> pairs;
403
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 pairs.reserve(row_cols.size());
404
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 214 times.
692 for (size_t idx = 0; idx < row_cols.size(); ++idx) {
405
1/2
✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
478 pairs.emplace_back(row_cols[idx], row_values[idx]);
406 }
407
408 std::ranges::sort(pairs);
409 static_cast<void>(std::ranges::begin(pairs));
410
411
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 214 times.
692 for (size_t idx = 0; idx < pairs.size(); ++idx) {
412 478 row_cols[idx] = pairs[idx].first;
413 478 row_values[idx] = pairs[idx].second;
414 }
415 }
416 230 }
417
418 212 void SosninaAMatrixMultCRSMPI::GatherResults() {
419
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 106 times.
212 if (rank_ == 0) {
420 106 std::vector<std::vector<double>> row_values(n_rows_A_);
421
1/2
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
106 std::vector<std::vector<int>> row_cols(n_rows_A_);
422
423
1/2
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
106 ProcessLocalResults(row_values, row_cols);
424
425
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 106 times.
212 for (int src = 1; src < world_size_; ++src) {
426
1/2
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
106 ReceiveResultsFromProcess(src, row_values, row_cols);
427 }
428
429
1/2
✓ Branch 1 taken 106 times.
✗ Branch 2 not taken.
106 CollectAllResults(row_values, row_cols);
430 106 } else {
431 106 int local_row_count = static_cast<int>(local_rows_.size());
432
433 106 MPI_Send(&local_row_count, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
434
435
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 16 times.
106 if (local_row_count > 0) {
436 90 std::vector<int> rows_to_send = local_rows_;
437
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 MPI_Send(rows_to_send.data(), local_row_count, MPI_INT, 0, 1, MPI_COMM_WORLD);
438
439
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 std::vector<int> row_ptr_to_send = local_row_ptr_C_;
440
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 MPI_Send(row_ptr_to_send.data(), local_row_count + 1, MPI_INT, 0, 2, MPI_COMM_WORLD);
441
442 90 int total_nnz = static_cast<int>(local_values_C_.size());
443
444
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 6 times.
90 if (total_nnz > 0) {
445
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 std::vector<double> values_to_send = local_values_C_;
446
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 std::vector<int> indices_to_send = local_col_indices_C_;
447
448
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 MPI_Send(values_to_send.data(), total_nnz, MPI_DOUBLE, 0, 3, MPI_COMM_WORLD);
449
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 MPI_Send(indices_to_send.data(), total_nnz, MPI_INT, 0, 4, MPI_COMM_WORLD);
450 }
451 }
452 }
453
454
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 106 times.
212 if (rank_ == 0) {
455 106 OutType result = std::make_tuple(values_C_, col_indices_C_, row_ptr_C_);
456 GetOutput() = result;
457 } else {
458 OutType empty_result = std::make_tuple(std::vector<double>(), std::vector<int>(), std::vector<int>());
459 GetOutput() = empty_result;
460 }
461 212 }
462
463 106 void SosninaAMatrixMultCRSMPI::ProcessLocalResults(std::vector<std::vector<double>> &row_values,
464 std::vector<std::vector<int>> &row_cols) {
465
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 106 times.
240 for (size_t i = 0; i < local_rows_.size(); ++i) {
466 134 int global_row = local_rows_[i];
467 134 int local_start = local_row_ptr_C_[i];
468 134 int local_end = local_row_ptr_C_[i + 1];
469
470
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 134 times.
408 for (int j = local_start; j < local_end; ++j) {
471
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 266 times.
274 row_values[global_row].push_back(local_values_C_[j]);
472 row_cols[global_row].push_back(local_col_indices_C_[j]);
473 }
474 }
475 106 }
476
477 106 void SosninaAMatrixMultCRSMPI::ReceiveResultsFromProcess(int src, std::vector<std::vector<double>> &row_values,
478 std::vector<std::vector<int>> &row_cols) {
479 106 int received_row_count = 0;
480 106 MPI_Recv(&received_row_count, 1, MPI_INT, src, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
481
482
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 16 times.
106 if (received_row_count > 0) {
483 90 std::vector<int> received_rows(received_row_count);
484
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 MPI_Recv(received_rows.data(), received_row_count, MPI_INT, src, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
485
486
1/4
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
90 std::vector<int> src_local_row_ptr(received_row_count + 1);
487
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 MPI_Recv(src_local_row_ptr.data(), received_row_count + 1, MPI_INT, src, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
488
489
1/2
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
90 int src_total_nnz = src_local_row_ptr[received_row_count];
490
491
1/4
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
90 std::vector<double> src_values(src_total_nnz);
492
1/4
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
90 std::vector<int> src_col_indices(src_total_nnz);
493
494
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 6 times.
90 if (src_total_nnz > 0) {
495
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 MPI_Recv(src_values.data(), src_total_nnz, MPI_DOUBLE, src, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
496
1/2
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
84 MPI_Recv(src_col_indices.data(), src_total_nnz, MPI_INT, src, 4, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
497 }
498
499
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 90 times.
186 for (int i = 0; i < received_row_count; ++i) {
500 96 int global_row = received_rows[i];
501 96 int src_start = src_local_row_ptr[i];
502 96 int src_end = src_local_row_ptr[i + 1];
503
504
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 96 times.
300 for (int j = src_start; j < src_end; ++j) {
505
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 198 times.
204 row_values[global_row].push_back(src_values[j]);
506 row_cols[global_row].push_back(src_col_indices[j]);
507 }
508 }
509 }
510 106 }
511
512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106 times.
106 void SosninaAMatrixMultCRSMPI::CollectAllResults(std::vector<std::vector<double>> &row_values,
513 std::vector<std::vector<int>> &row_cols) {
514 values_C_.clear();
515 col_indices_C_.clear();
516 106 row_ptr_C_.resize(n_rows_A_ + 1, 0);
517 106 row_ptr_C_[0] = 0;
518
519
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 106 times.
336 for (int i = 0; i < n_rows_A_; ++i) {
520 230 SortAndPackRow(i, row_values, row_cols);
521 230 values_C_.insert(values_C_.end(), row_values[i].begin(), row_values[i].end());
522 230 col_indices_C_.insert(col_indices_C_.end(), row_cols[i].begin(), row_cols[i].end());
523 230 row_ptr_C_[i + 1] = row_ptr_C_[i] + static_cast<int>(row_values[i].size());
524 }
525 106 }
526
527 230 void SosninaAMatrixMultCRSMPI::SortAndPackRow(int row_idx, std::vector<std::vector<double>> &row_values,
528 std::vector<std::vector<int>> &row_cols) {
529
2/2
✓ Branch 0 taken 214 times.
✓ Branch 1 taken 16 times.
230 if (!row_cols[row_idx].empty()) {
530
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 std::vector<std::pair<int, double>> pairs;
531
1/2
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
214 pairs.reserve(row_cols[row_idx].size());
532
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 214 times.
692 for (size_t idx = 0; idx < row_cols[row_idx].size(); ++idx) {
533
1/2
✓ Branch 1 taken 478 times.
✗ Branch 2 not taken.
478 pairs.emplace_back(row_cols[row_idx][idx], row_values[row_idx][idx]);
534 }
535 std::ranges::sort(pairs);
536 static_cast<void>(std::ranges::begin(pairs));
537
538
2/2
✓ Branch 0 taken 478 times.
✓ Branch 1 taken 214 times.
692 for (size_t idx = 0; idx < pairs.size(); ++idx) {
539 478 row_cols[row_idx][idx] = pairs[idx].first;
540 478 row_values[row_idx][idx] = pairs[idx].second;
541 }
542 }
543 230 }
544
545 212 bool SosninaAMatrixMultCRSMPI::PostProcessingImpl() {
546 212 return true;
547 }
548
549 } // namespace sosnina_a_sparse_matrix_mult_crs_double
550