GCC Code Coverage Report


Directory: ./
File: tasks/dolov_v_crs_mat_mult/all/src/ops_all.cpp
Date: 2026-06-04 20:25:32
Exec Total Coverage
Lines: 153 154 99.4%
Functions: 8 8 100.0%
Branches: 104 162 64.2%

Line Branch Exec Source
1 #include "dolov_v_crs_mat_mult/all/include/ops_all.hpp"
2
3 #include <mpi.h>
4 #include <omp.h>
5
6 #include <algorithm>
7 #include <cmath>
8 #include <utility>
9 #include <vector>
10
11 #include "dolov_v_crs_mat_mult/common/include/common.hpp"
12 #include "util/include/util.hpp"
13
14 namespace dolov_v_crs_mat_mult {
15
16 namespace {
17 14 void GatherAndFillResult(const std::vector<double> &flat_vals, const std::vector<int> &flat_cols,
18 const std::vector<int> &local_nnz_per_row, int local_rows, int a_rows, int local_nnz_total,
19 int rank, int size, int chunk, int remainder, SparseMatrix &res, int b_t_rows) {
20 14 std::vector<int> recv_nnz_cnt;
21 14 std::vector<int> recv_nnz_displs;
22 14 std::vector<int> rows_cnt;
23 14 std::vector<int> rows_displs;
24
25
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
26
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 recv_nnz_cnt.resize(size);
27
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 recv_nnz_displs.resize(size, 0);
28
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 rows_cnt.resize(size);
29
1/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
7 rows_displs.resize(size, 0);
30
31
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7 times.
21 for (int proc_idx = 0; proc_idx < size; ++proc_idx) {
32
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
24 rows_cnt[proc_idx] = chunk + (proc_idx < remainder ? 1 : 0);
33 14 rows_displs[proc_idx] = (proc_idx * chunk) + std::min(proc_idx, remainder);
34 }
35 }
36
37
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Gather(&local_nnz_total, 1, MPI_INT, recv_nnz_cnt.data(), 1, MPI_INT, 0, MPI_COMM_WORLD);
38
39 int total_global_nnz = 0;
40
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
41
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7 times.
21 for (int proc_idx = 0; proc_idx < size; ++proc_idx) {
42 14 recv_nnz_displs[proc_idx] = total_global_nnz;
43 14 total_global_nnz += recv_nnz_cnt[proc_idx];
44 }
45 }
46
47 14 std::vector<int> global_nnz_per_row;
48
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
49
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 global_nnz_per_row.resize(a_rows);
50 }
51
52
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Gatherv(local_nnz_per_row.data(), local_rows, MPI_INT, global_nnz_per_row.data(), rows_cnt.data(),
53 rows_displs.data(), MPI_INT, 0, MPI_COMM_WORLD);
54
55 14 std::vector<double> global_vals;
56 14 std::vector<int> global_cols;
57
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
58
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 global_vals.resize(total_global_nnz);
59
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 global_cols.resize(total_global_nnz);
60 }
61
62
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Gatherv(flat_vals.data(), local_nnz_total, MPI_DOUBLE, global_vals.data(), recv_nnz_cnt.data(),
63 recv_nnz_displs.data(), MPI_DOUBLE, 0, MPI_COMM_WORLD);
64
65
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Gatherv(flat_cols.data(), local_nnz_total, MPI_INT, global_cols.data(), recv_nnz_cnt.data(),
66 recv_nnz_displs.data(), MPI_INT, 0, MPI_COMM_WORLD);
67
68
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
69 7 res.num_rows = a_rows;
70 7 res.num_cols = b_t_rows;
71
1/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
7 res.row_pointers.assign(a_rows + 1, 0);
72
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 7 times.
147 for (int i = 0; i < a_rows; ++i) {
73 140 res.row_pointers[i + 1] = res.row_pointers[i] + global_nnz_per_row[i];
74 }
75 7 res.values = std::move(global_vals);
76 7 res.col_indices = std::move(global_cols);
77 }
78 14 }
79 } // namespace
80
81
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 DolovVCrsMatMultAll::DolovVCrsMatMultAll(const InType &in) {
82 SetTypeOfTask(GetStaticTypeOfTask());
83 14 int rank = 0;
84
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
85
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
86
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 GetInput() = in;
87 }
88 14 }
89
90 14 bool DolovVCrsMatMultAll::ValidationImpl() {
91 14 int rank = 0;
92 14 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
93
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
94 const auto &input_data = GetInput();
95
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (input_data.size() != 2) {
96 return false;
97 }
98 const auto &matrix_a = input_data[0];
99 const auto &matrix_b = input_data[1];
100
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7 times.
7 return matrix_a.num_cols == matrix_b.num_rows && matrix_a.num_rows > 0 && matrix_b.num_cols > 0;
101 }
102 return true;
103 }
104
105 14 bool DolovVCrsMatMultAll::PreProcessingImpl() {
106 14 return true;
107 }
108
109 7 SparseMatrix DolovVCrsMatMultAll::TransposeMatrix(const SparseMatrix &matrix) {
110 7 SparseMatrix transposed;
111 7 transposed.num_rows = matrix.num_cols;
112 7 transposed.num_cols = matrix.num_rows;
113
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 transposed.row_pointers.assign(transposed.num_rows + 1, 0);
114
2/2
✓ Branch 0 taken 298 times.
✓ Branch 1 taken 7 times.
305 for (int col_idx : matrix.col_indices) {
115 298 transposed.row_pointers[col_idx + 1]++;
116 }
117
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 7 times.
142 for (int i = 0; i < transposed.num_rows; ++i) {
118 135 transposed.row_pointers[i + 1] += transposed.row_pointers[i];
119 }
120
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 transposed.values.resize(matrix.values.size());
121
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 transposed.col_indices.resize(matrix.col_indices.size());
122
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 std::vector<int> current_pos = transposed.row_pointers;
123
2/2
✓ Branch 0 taken 229 times.
✓ Branch 1 taken 7 times.
236 for (int i = 0; i < matrix.num_rows; ++i) {
124
2/2
✓ Branch 0 taken 298 times.
✓ Branch 1 taken 229 times.
527 for (int j = matrix.row_pointers[i]; j < matrix.row_pointers[i + 1]; ++j) {
125 298 int col = matrix.col_indices[j];
126 298 int dest_idx = current_pos[col]++;
127 298 transposed.values[dest_idx] = matrix.values[j];
128 298 transposed.col_indices[dest_idx] = i;
129 }
130 }
131 7 return transposed;
132 }
133
134 10436 double DolovVCrsMatMultAll::DotProduct(const SparseMatrix &matrix_a, int row_a, const SparseMatrix &matrix_b_t,
135 int row_b) {
136 double sum = 0.0;
137 10436 int ptr_a = matrix_a.row_pointers[row_a];
138 10436 int ptr_b = matrix_b_t.row_pointers[row_b];
139 10436 const int end_a = matrix_a.row_pointers[row_a + 1];
140 10436 const int end_b = matrix_b_t.row_pointers[row_b + 1];
141
2/2
✓ Branch 0 taken 25219 times.
✓ Branch 1 taken 10436 times.
35655 while (ptr_a < end_a && ptr_b < end_b) {
142
2/2
✓ Branch 0 taken 617 times.
✓ Branch 1 taken 24602 times.
25219 if (matrix_a.col_indices[ptr_a] == matrix_b_t.col_indices[ptr_b]) {
143 617 sum += matrix_a.values[ptr_a] * matrix_b_t.values[ptr_b];
144 617 ptr_a++;
145 617 ptr_b++;
146
2/2
✓ Branch 0 taken 13175 times.
✓ Branch 1 taken 11427 times.
24602 } else if (matrix_a.col_indices[ptr_a] < matrix_b_t.col_indices[ptr_b]) {
147 13175 ptr_a++;
148 } else {
149 11427 ptr_b++;
150 }
151 }
152 10436 return sum;
153 }
154
155 14 bool DolovVCrsMatMultAll::RunImpl() {
156 14 int rank = 0;
157 14 int size = 1;
158 14 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
159 14 MPI_Comm_size(MPI_COMM_WORLD, &size);
160
161 14 SparseMatrix local_a;
162 14 SparseMatrix local_b_t;
163
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 std::vector<int> sizes_vec(4, 0);
164 14 int a_nnz = 0;
165 14 int b_t_nnz = 0;
166
167
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
168 const auto &matrix_a = GetInput()[0];
169
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 local_a = matrix_a;
170
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 local_b_t = TransposeMatrix(GetInput()[1]);
171 7 sizes_vec[0] = local_a.num_rows;
172 7 sizes_vec[1] = local_a.num_cols;
173 7 sizes_vec[2] = local_b_t.num_rows;
174 7 sizes_vec[3] = local_b_t.num_cols;
175 7 a_nnz = static_cast<int>(local_a.values.size());
176 7 b_t_nnz = static_cast<int>(local_b_t.values.size());
177 }
178
179
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Bcast(sizes_vec.data(), 4, MPI_INT, 0, MPI_COMM_WORLD);
180
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Bcast(&a_nnz, 1, MPI_INT, 0, MPI_COMM_WORLD);
181
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Bcast(&b_t_nnz, 1, MPI_INT, 0, MPI_COMM_WORLD);
182
183
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank != 0) {
184 7 local_a.num_rows = sizes_vec[0];
185 7 local_a.num_cols = sizes_vec[1];
186
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 local_a.row_pointers.resize(sizes_vec[0] + 1);
187
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 local_a.col_indices.resize(a_nnz);
188
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 local_a.values.resize(a_nnz);
189
190 7 local_b_t.num_rows = sizes_vec[2];
191 7 local_b_t.num_cols = sizes_vec[3];
192
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 local_b_t.row_pointers.resize(sizes_vec[2] + 1);
193
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 local_b_t.col_indices.resize(b_t_nnz);
194
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 local_b_t.values.resize(b_t_nnz);
195 }
196
197
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Bcast(local_a.row_pointers.data(), sizes_vec[0] + 1, MPI_INT, 0, MPI_COMM_WORLD);
198
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (a_nnz > 0) {
199
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Bcast(local_a.col_indices.data(), a_nnz, MPI_INT, 0, MPI_COMM_WORLD);
200
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Bcast(local_a.values.data(), a_nnz, MPI_DOUBLE, 0, MPI_COMM_WORLD);
201 }
202
203
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Bcast(local_b_t.row_pointers.data(), sizes_vec[2] + 1, MPI_INT, 0, MPI_COMM_WORLD);
204
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2 times.
14 if (b_t_nnz > 0) {
205
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Bcast(local_b_t.col_indices.data(), b_t_nnz, MPI_INT, 0, MPI_COMM_WORLD);
206
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Bcast(local_b_t.values.data(), b_t_nnz, MPI_DOUBLE, 0, MPI_COMM_WORLD);
207 }
208
209 14 const int a_rows = sizes_vec[0];
210 14 const int chunk = a_rows / size;
211 14 const int remainder = a_rows % size;
212
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 const int local_start = (rank * chunk) + std::min(rank, remainder);
213
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 const int local_rows = chunk + (rank < remainder ? 1 : 0);
214
215
1/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
14 std::vector<std::vector<double>> temp_values(local_rows);
216
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 std::vector<std::vector<int>> temp_cols(local_rows);
217
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 std::vector<int> local_nnz_per_row(local_rows, 0);
218
219 14 #pragma omp parallel for default(none) \
220 shared(local_a, local_b_t, temp_values, temp_cols, local_nnz_per_row, local_rows, local_start, sizes_vec) \
221
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 num_threads(std::max(1, ppc::util::GetNumThreads())) schedule(dynamic)
222 for (int i = 0; i < local_rows; ++i) {
223 int global_row = local_start + i;
224 for (int j = 0; j < sizes_vec[2]; ++j) {
225 double sum = DotProduct(local_a, global_row, local_b_t, j);
226 if (std::abs(sum) > 1e-15) {
227 temp_values[i].push_back(sum);
228 temp_cols[i].push_back(j);
229 }
230 }
231 local_nnz_per_row[i] = static_cast<int>(temp_values[i].size());
232 }
233
234 14 std::vector<double> flat_vals;
235 14 std::vector<int> flat_cols;
236 int local_nnz_total = 0;
237
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 14 times.
154 for (int i = 0; i < local_rows; ++i) {
238 140 local_nnz_total += local_nnz_per_row[i];
239 }
240
241
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 flat_vals.reserve(local_nnz_total);
242
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 flat_cols.reserve(local_nnz_total);
243
2/2
✓ Branch 0 taken 140 times.
✓ Branch 1 taken 14 times.
154 for (int i = 0; i < local_rows; ++i) {
244
2/4
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 140 times.
✗ Branch 5 not taken.
140 flat_vals.insert(flat_vals.end(), temp_values[i].begin(), temp_values[i].end());
245 140 flat_cols.insert(flat_cols.end(), temp_cols[i].begin(), temp_cols[i].end());
246 }
247
248
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 SparseMatrix res;
249
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 GatherAndFillResult(flat_vals, flat_cols, local_nnz_per_row, local_rows, a_rows, local_nnz_total, rank, size, chunk,
250 remainder, res, sizes_vec[2]);
251
252
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
253 7 GetOutput() = std::move(res);
254 }
255
256 14 return true;
257 42 }
258
259 14 bool DolovVCrsMatMultAll::PostProcessingImpl() {
260 14 return true;
261 }
262
263 } // namespace dolov_v_crs_mat_mult
264