GCC Code Coverage Report


Directory: ./
File: tasks/Terekhov_D_Min_Column_Matrix/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 68 74 91.9%
Functions: 10 10 100.0%
Branches: 49 80 61.3%

Line Branch Exec Source
1 #include "Terekhov_D_Min_Column_Matrix/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 <ranges> // IWYU pragma: keep
10 #include <utility>
11 #include <vector>
12
13 #include "Terekhov_D_Min_Column_Matrix/common/include/common.hpp"
14
15 namespace terekhov_d_a_test_task_processes {
16
17 namespace {
18
19 22 std::vector<int> ScatterMatrixData(const std::vector<std::vector<int>> &matrix, int total_rows, int total_cols,
20 int size, int rank, int my_rows) {
21
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (size <= 0 || total_rows <= 0 || total_cols <= 0) {
22 return {};
23 }
24
25 22 const std::size_t local_size = static_cast<std::size_t>(my_rows) * static_cast<std::size_t>(total_cols);
26 22 std::vector<int> local_data(local_size, 0);
27
28
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
22 if (rank == 0) {
29
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 std::vector<int> flat_matrix = TerekhovDTestTaskMPI::FlattenMatrix(matrix);
30
31 11 const int rows_per_process = total_rows / size;
32 11 const int remainder = total_rows % size;
33
34
1/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
11 std::vector<int> send_counts(size);
35
1/4
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
11 std::vector<int> displacements(size);
36
37 int current_displ = 0;
38
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 11 times.
33 for (int i = 0; i < size; ++i) {
39
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 7 times.
22 const int rows_for_i = rows_per_process + (i < remainder ? 1 : 0);
40 22 send_counts[i] = rows_for_i * total_cols;
41 22 displacements[i] = current_displ;
42 22 current_displ += rows_for_i * total_cols;
43 }
44
45
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 MPI_Scatterv(flat_matrix.data(), send_counts.data(), displacements.data(), MPI_INT, local_data.data(),
46 my_rows * total_cols, MPI_INT, 0, MPI_COMM_WORLD);
47 } else {
48
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 MPI_Scatterv(nullptr, nullptr, nullptr, MPI_INT, local_data.data(), my_rows * total_cols, MPI_INT, 0,
49 MPI_COMM_WORLD);
50 }
51
52 return local_data;
53 }
54
55 22 std::vector<int> ComputeLocalColumnMinima(const std::vector<int> &local_data, int my_rows, int total_cols) {
56 22 std::vector<int> local_minima(static_cast<std::size_t>(total_cols), INT_MAX);
57
58
3/4
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
22 if (my_rows > 0 && !local_data.empty()) {
59
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 19 times.
44 for (int i = 0; i < my_rows; ++i) {
60
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 25 times.
75 for (int j = 0; j < total_cols; ++j) {
61 50 const int idx = (i * total_cols) + j;
62
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 46 times.
50 const int val = local_data[static_cast<std::size_t>(idx)];
63
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 46 times.
54 local_minima[static_cast<std::size_t>(j)] = std::min(val, local_minima[static_cast<std::size_t>(j)]);
64 }
65 }
66 }
67
68 22 return local_minima;
69 }
70
71 22 std::vector<int> ReduceGlobalMinima(const std::vector<int> &local_minima, int total_cols) {
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (total_cols <= 0) {
73 return {};
74 }
75
76
1/2
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
22 std::vector<int> global_minima(static_cast<std::size_t>(total_cols), INT_MAX);
77
78
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 MPI_Allreduce(local_minima.data(), global_minima.data(), total_cols, MPI_INT, MPI_MIN, MPI_COMM_WORLD);
79
80 return global_minima;
81 }
82
83 } // namespace
84
85
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 TerekhovDTestTaskMPI::TerekhovDTestTaskMPI(const InType &in) {
86 SetTypeOfTask(GetStaticTypeOfTask());
87
88
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (!in.empty()) {
89
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 GetInput() = in;
90 } else {
91 GetInput() = InType{};
92 }
93
94 22 GetOutput() = OutType{};
95 22 }
96
97
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 bool TerekhovDTestTaskMPI::ValidationImpl() {
98 const auto &input = GetInput();
99
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (input.empty()) {
100 return false;
101 }
102
103 const std::size_t cols = input[0].size();
104
1/2
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
22 if (cols == 0) {
105 return false;
106 }
107
108 return std::ranges::all_of(input, [cols](const auto &row) { return row.size() == cols; });
109 }
110
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 bool TerekhovDTestTaskMPI::PreProcessingImpl() {
112 GetOutput().clear();
113 22 return true;
114 }
115
116
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 std::vector<int> TerekhovDTestTaskMPI::FlattenMatrix(const std::vector<std::vector<int>> &matrix) {
117
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if (matrix.empty() || matrix[0].empty()) {
118 return {};
119 }
120
121 const std::size_t rows = matrix.size();
122 const std::size_t cols = matrix[0].size();
123
124 11 std::vector<int> flat;
125
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 flat.reserve(rows * cols);
126
127
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 11 times.
36 for (const auto &row : matrix) {
128 25 flat.insert(flat.end(), row.begin(), row.end());
129 }
130
131 return flat;
132 }
133
134 22 std::pair<int, int> TerekhovDTestTaskMPI::PrepareDimensions(const std::vector<std::vector<int>> &matrix, int rank) {
135 int total_rows = 0;
136 int total_cols = 0;
137
138
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
22 if (rank == 0) {
139 11 total_rows = static_cast<int>(matrix.size());
140
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 total_cols = (total_rows > 0) ? static_cast<int>(matrix[0].size()) : 0;
141 }
142
143 22 std::array<int, 2> dimensions = {total_rows, total_cols};
144 22 MPI_Bcast(dimensions.data(), 2, MPI_INT, 0, MPI_COMM_WORLD);
145
146 22 return {dimensions[0], dimensions[1]};
147 }
148
149 22 bool TerekhovDTestTaskMPI::RunImpl() {
150 22 int rank = 0;
151 22 int size = 1;
152 22 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
153 22 MPI_Comm_size(MPI_COMM_WORLD, &size);
154
155 const auto &matrix = GetInput();
156
157 22 auto [total_rows, total_cols] = PrepareDimensions(matrix, rank);
158
159
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (total_rows == 0 || total_cols == 0) {
160 GetOutput() = OutType{};
161 return true;
162 }
163
164 22 const int rows_per_process = total_rows / size;
165 22 const int remainder = total_rows % size;
166
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 7 times.
22 const int my_rows = rows_per_process + (rank < remainder ? 1 : 0);
167
168 22 std::vector<int> local_data = ScatterMatrixData(matrix, total_rows, total_cols, size, rank, my_rows);
169
170
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 std::vector<int> local_minima = ComputeLocalColumnMinima(local_data, my_rows, total_cols);
171
172
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 std::vector<int> global_minima = ReduceGlobalMinima(local_minima, total_cols);
173
174 GetOutput() = std::move(global_minima);
175
176 return true;
177 }
178
179 22 bool TerekhovDTestTaskMPI::PostProcessingImpl() {
180 22 return true;
181 }
182
183 } // namespace terekhov_d_a_test_task_processes
184