GCC Code Coverage Report


Directory: ./
File: tasks/viderman_a_strip_matvec_mult/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 88 90 97.8%
Functions: 10 10 100.0%
Branches: 66 104 63.5%

Line Branch Exec Source
1 #include "viderman_a_strip_matvec_mult/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cstddef>
6 #include <utility>
7 #include <vector>
8
9 #include "viderman_a_strip_matvec_mult/common/include/common.hpp"
10
11 namespace viderman_a_strip_matvec_mult {
12
13
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 VidermanAStripMatvecMultMPI::VidermanAStripMatvecMultMPI(const InType &in) {
14 SetTypeOfTask(GetStaticTypeOfTask());
15
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
96 GetInput() = InType(in);
16 48 }
17
18
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 46 times.
48 bool VidermanAStripMatvecMultMPI::ValidationImpl() {
19 const InType &input = GetInput();
20 const auto &matrix = input.first;
21 const auto &vector = input.second;
22
23
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
48 if (matrix.empty() && vector.empty()) {
24 return true;
25 }
26
27
2/4
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
46 if (matrix.empty() || vector.empty()) {
28 return false;
29 }
30
31 const size_t cols = matrix[0].size();
32
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 46 times.
200 for (const auto &row : matrix) {
33
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 154 times.
154 if (row.size() != cols) {
34 return false;
35 }
36 }
37
38 46 return cols == vector.size();
39 }
40
41 48 bool VidermanAStripMatvecMultMPI::PreProcessingImpl() {
42 48 return true;
43 }
44
45 namespace {
46
47 46 std::pair<std::vector<int>, std::vector<int>> CalculateDistribution(int rows, int size) {
48 46 std::vector<int> send_counts(size);
49
1/4
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
46 std::vector<int> displacements(size);
50
51 46 const int rows_per_proc = rows / size;
52 46 const int remaining_rows = rows % size;
53 int displacement = 0;
54
55
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 46 times.
138 for (int i = 0; i < size; ++i) {
56
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 22 times.
162 send_counts[i] = rows_per_proc + (i < remaining_rows ? 1 : 0);
57 92 displacements[i] = displacement;
58 92 displacement += send_counts[i];
59 }
60
61
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
92 return {send_counts, displacements};
62 }
63
64
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 void HandleEmptyCase(int rank, std::vector<double> &result) {
65 result.clear();
66
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (rank == 0) {
67 1 result.resize(0);
68 }
69 2 int result_size = static_cast<int>(result.size());
70 2 MPI_Bcast(&result_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
71 2 result.resize(static_cast<size_t>(result_size));
72 2 }
73
74 46 std::pair<int, int> BroadcastMatrixSizes(int rank, const std::vector<std::vector<double>> &full_matrix,
75 const std::vector<double> &full_vector) {
76
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 int rows = (rank == 0) ? static_cast<int>(full_matrix.size()) : 0;
77 23 int cols = (rank == 0) ? static_cast<int>(full_vector.size()) : 0;
78
79 46 MPI_Bcast(&rows, 1, MPI_INT, 0, MPI_COMM_WORLD);
80 46 MPI_Bcast(&cols, 1, MPI_INT, 0, MPI_COMM_WORLD);
81
82 46 return {rows, cols};
83 }
84
85 46 void PrepareScatterData(int rank, int size, const std::vector<std::vector<double>> &full_matrix,
86 const std::vector<int> &send_counts, const std::vector<int> &displacements, int cols,
87 std::vector<double> &flat_full_matrix, std::vector<int> &scatter_counts,
88 std::vector<int> &scatter_displacements) {
89
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 if (rank == 0) {
90 23 flat_full_matrix.reserve(static_cast<size_t>(full_matrix.size()) * static_cast<size_t>(cols));
91
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 23 times.
100 for (const auto &row : full_matrix) {
92 77 flat_full_matrix.insert(flat_full_matrix.end(), row.begin(), row.end());
93 }
94
95
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 23 times.
69 for (int i = 0; i < size; ++i) {
96 46 scatter_counts[i] = send_counts[i] * cols;
97 46 scatter_displacements[i] = displacements[i] * cols;
98 }
99 }
100 46 }
101
102 46 std::vector<double> ComputeLocalResult(int my_row_count, int cols, const std::vector<double> &flat_local_matrix,
103 const std::vector<double> &local_vector) {
104 46 std::vector<double> local_result(static_cast<size_t>(my_row_count), 0.0);
105
2/2
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 46 times.
123 for (int i = 0; i < my_row_count; ++i) {
106 double sum = 0.0;
107 77 const size_t row_offset = static_cast<size_t>(i) * static_cast<size_t>(cols);
108
2/2
✓ Branch 0 taken 317 times.
✓ Branch 1 taken 77 times.
394 for (int j = 0; j < cols; ++j) {
109 317 sum += flat_local_matrix[row_offset + static_cast<size_t>(j)] * local_vector[static_cast<size_t>(j)];
110 }
111 77 local_result[static_cast<size_t>(i)] = sum;
112 }
113 46 return local_result;
114 }
115
116 } // namespace
117
118 48 bool VidermanAStripMatvecMultMPI::RunImpl() {
119 48 int rank = 0;
120 48 int size = 0;
121 48 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
122 48 MPI_Comm_size(MPI_COMM_WORLD, &size);
123
124 const InType &input = GetInput();
125 48 const auto &full_matrix = input.first;
126
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 2 times.
48 const auto &full_vector = input.second;
127 auto &result = GetOutput();
128
129
3/4
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
48 if (full_matrix.empty() || full_vector.empty()) {
130 2 HandleEmptyCase(rank, result);
131 2 return true;
132 }
133
134 46 const auto [rows, cols] = BroadcastMatrixSizes(rank, full_matrix, full_vector);
135
136
2/4
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
46 if (rows == 0 || cols == 0) {
137 HandleEmptyCase(rank, result);
138 return true;
139 }
140
141 46 const auto [send_counts, displacements] = CalculateDistribution(rows, size);
142
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 const int my_row_count = send_counts[rank];
143
144 46 std::vector<double> flat_full_matrix;
145
1/4
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
46 std::vector<int> scatter_counts(size);
146
1/4
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
46 std::vector<int> scatter_displacements(size);
147
148
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 PrepareScatterData(rank, size, full_matrix, send_counts, displacements, cols, flat_full_matrix, scatter_counts,
149 scatter_displacements);
150
151
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 MPI_Bcast(scatter_counts.data(), size, MPI_INT, 0, MPI_COMM_WORLD);
152
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 MPI_Bcast(scatter_displacements.data(), size, MPI_INT, 0, MPI_COMM_WORLD);
153
154 46 const size_t local_matrix_size = static_cast<size_t>(my_row_count) * static_cast<size_t>(cols);
155
1/4
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
46 std::vector<double> flat_local_matrix(local_matrix_size);
156
157
3/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
✓ Branch 3 taken 46 times.
✗ Branch 4 not taken.
69 MPI_Scatterv(rank == 0 ? flat_full_matrix.data() : nullptr, scatter_counts.data(), scatter_displacements.data(),
158 MPI_DOUBLE, flat_local_matrix.data(), static_cast<int>(local_matrix_size), MPI_DOUBLE, 0,
159 MPI_COMM_WORLD);
160
161
1/4
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
46 std::vector<double> local_vector(static_cast<size_t>(cols));
162
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 if (rank == 0) {
163
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
23 local_vector = full_vector;
164 }
165
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 MPI_Bcast(local_vector.data(), cols, MPI_DOUBLE, 0, MPI_COMM_WORLD);
166
167
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 std::vector<double> local_result = ComputeLocalResult(my_row_count, cols, flat_local_matrix, local_vector);
168
169
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 if (rank == 0) {
170
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
23 result.resize(static_cast<size_t>(rows));
171 }
172
173
3/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
✓ Branch 3 taken 46 times.
✗ Branch 4 not taken.
69 MPI_Gatherv(local_result.data(), my_row_count, MPI_DOUBLE, rank == 0 ? result.data() : nullptr, send_counts.data(),
174 displacements.data(), MPI_DOUBLE, 0, MPI_COMM_WORLD);
175
176
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 if (rank != 0) {
177
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
23 result.resize(static_cast<size_t>(rows));
178 }
179
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 MPI_Bcast(result.data(), rows, MPI_DOUBLE, 0, MPI_COMM_WORLD);
180
181 return true;
182 46 }
183
184 48 bool VidermanAStripMatvecMultMPI::PostProcessingImpl() {
185 48 return true;
186 }
187
188 } // namespace viderman_a_strip_matvec_mult
189