GCC Code Coverage Report


Directory: ./
File: tasks/barkalova_m_min_val_matr/mpi/src/ops_mpi.cpp
Date: 2026-02-02 01:14:38
Exec Total Coverage
Lines: 125 133 94.0%
Functions: 14 14 100.0%
Branches: 73 102 71.6%

Line Branch Exec Source
1 #include "barkalova_m_min_val_matr/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <array>
7 #include <climits>
8 #include <cstddef>
9 #include <cstdint>
10 #include <utility>
11 #include <vector>
12
13 #include "barkalova_m_min_val_matr/common/include/common.hpp"
14
15 namespace barkalova_m_min_val_matr {
16
17
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 BarkalovaMMinValMatrMPI::BarkalovaMMinValMatrMPI(const InType &in) {
18 SetTypeOfTask(GetStaticTypeOfTask());
19
1/2
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
64 GetInput().resize(in.size());
20
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 64 times.
280 for (size_t i = 0; i < in.size(); ++i) {
21
1/2
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
216 GetInput()[i] = in[i];
22 }
23 GetOutput().clear();
24 64 }
25
26 64 bool BarkalovaMMinValMatrMPI::ValidationImpl() {
27 64 int rank = 0;
28 64 int size = 0;
29 64 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
30 64 MPI_Comm_size(MPI_COMM_WORLD, &size);
31
32 64 bool is_valid = true;
33
34
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 32 times.
64 if (rank == 0) {
35 const auto &matrix = GetInput();
36
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 2 times.
32 if (!matrix.empty()) {
37 size_t stolb = matrix[0].size();
38 30 is_valid = std::ranges::all_of(matrix, [stolb](const auto &row) { return row.size() == stolb; });
39 }
40 }
41
42 64 MPI_Bcast(&is_valid, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD);
43 64 return is_valid;
44 }
45
46
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 4 times.
64 bool BarkalovaMMinValMatrMPI::PreProcessingImpl() {
47
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 4 times.
64 if (!GetInput().empty()) {
48 size_t stolb = GetInput()[0].size();
49 60 GetOutput().resize(stolb, INT_MAX);
50 } else {
51 GetOutput().clear();
52 }
53 64 return true;
54 }
55
56 namespace {
57
58 60 bool ValidateMatrixSize(int rank, size_t rows, size_t stolb) {
59 60 bool size_valid = true;
60
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
60 if (rank == 0) {
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (rows > static_cast<size_t>(INT_MAX) || stolb > static_cast<size_t>(INT_MAX)) {
62 size_valid = false;
63 }
64
65
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
30 if (size_valid && rows > 0 && stolb > 0) {
66
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (rows > SIZE_MAX / stolb) {
67 size_valid = false;
68 } else {
69 30 size_t total = rows * stolb;
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (total > static_cast<size_t>(INT_MAX)) {
71 size_valid = false;
72 }
73 }
74 }
75 }
76 60 MPI_Bcast(&size_valid, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD);
77 60 return size_valid;
78 }
79
80 bool ValidateLocalSize(size_t rows, size_t col_stolb) {
81 60 if (rows == 0 || col_stolb == 0) {
82 return true;
83 }
84
85
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 if (rows > SIZE_MAX / col_stolb) {
86 return false;
87 }
88
89 58 size_t total = rows * col_stolb;
90 return total <= static_cast<size_t>(INT_MAX);
91 }
92
93 64 std::pair<size_t, size_t> GetMatrixDimensions(int rank, const std::vector<std::vector<int>> &matrix) {
94 size_t rows = 0;
95 size_t stolb = 0;
96
97
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 32 times.
64 if (rank == 0) {
98 rows = matrix.size();
99
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 2 times.
32 stolb = matrix.empty() ? 0 : matrix[0].size();
100 }
101
102 64 std::array<uint64_t, 2> dims = {rows, stolb};
103 64 MPI_Bcast(dims.data(), 2, MPI_UINT64_T, 0, MPI_COMM_WORLD);
104 64 return {dims[0], dims[1]};
105 }
106
107 120 std::pair<size_t, size_t> GetColumnRange(int rank, int size, size_t stolb) {
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (stolb == 0) {
109 return {0, 0};
110 }
111 120 size_t loc_stolb = stolb / static_cast<size_t>(size);
112 120 size_t ostatok = stolb % static_cast<size_t>(size);
113
114 size_t start_stolb = 0;
115
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 120 times.
180 for (int i = 0; i < rank; ++i) {
116 60 size_t i_cols = loc_stolb + (std::cmp_less(i, ostatok) ? 1 : 0);
117 60 start_stolb += i_cols;
118 }
119 120 size_t col_stolb = loc_stolb + (std::cmp_less(rank, ostatok) ? 1 : 0);
120 120 return {start_stolb, col_stolb};
121 }
122
123 30 std::vector<int> PrepareDataForScatterv(int rank, const std::vector<std::vector<int>> &matrix, size_t rows,
124 size_t stolb) {
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (rank != 0) {
126 return {};
127 }
128 30 std::vector<int> all_data(rows * stolb);
129
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 30 times.
156 for (size_t col = 0; col < stolb; ++col) {
130
2/2
✓ Branch 0 taken 396 times.
✓ Branch 1 taken 126 times.
522 for (size_t row = 0; row < rows; ++row) {
131 396 all_data[(col * rows) + row] = matrix[row][col];
132 }
133 }
134 return all_data;
135 }
136
137 58 void PrepareScattervParams(int size, size_t rows, size_t stolb, std::vector<int> &send_counts,
138 std::vector<int> &displacements) {
139
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (size == 0 || stolb == 0) {
140 send_counts.clear();
141 displacements.clear();
142 return;
143 }
144
145 58 size_t base_cols = stolb / static_cast<size_t>(size);
146 58 size_t extra_cols = stolb % static_cast<size_t>(size);
147
148 58 send_counts.resize(size);
149 58 displacements.resize(size);
150
151 size_t current_displacement = 0;
152
2/2
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 58 times.
174 for (int i = 0; i < size; i++) {
153 116 size_t i_cols = base_cols + (std::cmp_less(i, extra_cols) ? 1 : 0);
154 116 send_counts[i] = static_cast<int>(i_cols * rows);
155 116 displacements[i] = static_cast<int>(current_displacement);
156 116 current_displacement += i_cols * rows;
157 }
158 }
159
160 60 void DistributeDataScatterv(int rank, int size, const std::vector<int> &all_data, size_t rows, size_t stolb,
161 std::vector<int> &local_data, size_t &local_cols) {
162 60 auto [start_col, col_count] = GetColumnRange(rank, size, stolb);
163 60 local_cols = col_count;
164
165
3/4
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
60 if (local_cols == 0 || rows == 0) {
166 local_data.clear();
167 2 return;
168 }
169
170 58 local_data.resize(rows * local_cols);
171
172 58 std::vector<int> send_counts;
173 58 std::vector<int> displacements;
174
1/2
✓ Branch 1 taken 58 times.
✗ Branch 2 not taken.
58 PrepareScattervParams(size, rows, stolb, send_counts, displacements);
175
176
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 28 times.
58 int recv_count = static_cast<int>(local_data.size());
177 // распределяем матрицу по процессам
178
3/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 28 times.
✓ Branch 3 taken 58 times.
✗ Branch 4 not taken.
88 MPI_Scatterv(all_data.empty() ? nullptr : all_data.data(), send_counts.data(), displacements.data(), MPI_INT,
179 local_data.data(), recv_count, MPI_INT, 0, MPI_COMM_WORLD);
180 }
181
182 60 std::vector<int> CalculateLocalMins(const std::vector<int> &local_data, size_t rows, size_t local_cols) {
183
3/4
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
60 if (local_cols == 0 || local_data.empty()) {
184 2 return {};
185 }
186
187 58 std::vector<int> loc_min(local_cols, INT_MAX);
188
189
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 58 times.
184 for (size_t col = 0; col < local_cols; ++col) {
190 126 size_t col_offset = col * rows;
191
2/2
✓ Branch 0 taken 396 times.
✓ Branch 1 taken 126 times.
522 for (size_t row = 0; row < rows; ++row) {
192
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 189 times.
396 int value = local_data[col_offset + row];
193 396 loc_min[col] = std::min(loc_min[col], value);
194 }
195 }
196
197 return loc_min;
198 }
199
200 60 void PrepareGathervData(int size, size_t stolb, std::vector<int> &recv_counts, std::vector<int> &displacements) {
201 60 size_t loc_stolb = stolb / static_cast<size_t>(size);
202 60 size_t ostatok = stolb % static_cast<size_t>(size);
203
204 60 recv_counts.resize(size);
205 60 displacements.resize(size);
206
207 size_t current_displacement = 0;
208
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 60 times.
180 for (int i = 0; i < size; i++) {
209 120 size_t i_cols = loc_stolb + (std::cmp_less(i, ostatok) ? 1 : 0);
210 120 recv_counts[i] = static_cast<int>(i_cols);
211 120 displacements[i] = static_cast<int>(current_displacement);
212 120 current_displacement += i_cols;
213 }
214 60 }
215
216 60 void GatherAndBroadcastResults(const std::vector<int> &loc_min, int size, size_t stolb, size_t col_stolb,
217 std::vector<int> &res) {
218 60 res.resize(stolb, INT_MAX);
219
220 60 std::vector<int> recv_counts;
221 60 std::vector<int> displacements;
222
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 PrepareGathervData(size, stolb, recv_counts, displacements);
223
224
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 int send_count = static_cast<int>(col_stolb);
225
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 MPI_Gatherv(loc_min.data(), send_count, MPI_INT, res.data(), recv_counts.data(), displacements.data(), MPI_INT, 0,
226 MPI_COMM_WORLD);
227
228
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 MPI_Bcast(res.data(), static_cast<int>(stolb), MPI_INT, 0, MPI_COMM_WORLD);
229 60 }
230
231 } // namespace
232
233 64 bool BarkalovaMMinValMatrMPI::RunImpl() {
234 64 int rank = 0;
235 64 int size = 0;
236 64 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
237 64 MPI_Comm_size(MPI_COMM_WORLD, &size);
238
239 const auto &matrix = GetInput();
240 64 auto [rows, stolb] = GetMatrixDimensions(rank, matrix);
241
242
3/4
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
64 if (rows == 0 || stolb == 0) {
243 GetOutput().clear();
244 4 return true;
245 }
246
247
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
60 if (!ValidateMatrixSize(rank, rows, stolb)) {
248 GetOutput().clear();
249 return false;
250 }
251
252 60 auto [start_stolb, local_cols] = GetColumnRange(rank, size, stolb);
253
254
3/4
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 58 times.
118 if (!ValidateLocalSize(rows, local_cols)) {
255 GetOutput().clear();
256 return false;
257 }
258 60 std::vector<int> all_data;
259
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
60 if (rank == 0) {
260
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
60 all_data = PrepareDataForScatterv(rank, matrix, rows, stolb);
261 }
262
263 60 std::vector<int> local_data;
264
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 DistributeDataScatterv(rank, size, all_data, rows, stolb, local_data, local_cols);
265
266
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 std::vector<int> loc_min = CalculateLocalMins(local_data, rows, local_cols);
267
268
1/2
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
60 GatherAndBroadcastResults(loc_min, size, stolb, local_cols, GetOutput());
269
270 return true;
271 }
272
273 64 bool BarkalovaMMinValMatrMPI::PostProcessingImpl() {
274 64 return true;
275 }
276 } // namespace barkalova_m_min_val_matr
277