GCC Code Coverage Report


Directory: ./
File: tasks/kondakov_v_min_val_in_matrix_str/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 88 90 97.8%
Functions: 10 10 100.0%
Branches: 65 106 61.3%

Line Branch Exec Source
1 #include "kondakov_v_min_val_in_matrix_str/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cassert>
7 #include <cstddef>
8 #include <cstdint>
9 #include <limits>
10 #include <stdexcept>
11 #include <utility>
12 #include <vector>
13
14 #include "kondakov_v_min_val_in_matrix_str/common/include/common.hpp"
15
16 namespace kondakov_v_min_val_in_matrix_str {
17
18
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 KondakovVMinValMatrixMPI::KondakovVMinValMatrixMPI(const InType &in) {
19 SetTypeOfTask(GetStaticTypeOfTask());
20
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 InType tmp = in;
21 GetInput().swap(tmp);
22 GetOutput().clear();
23
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 GetOutput().resize(in.size());
24 10 }
25
26
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 bool KondakovVMinValMatrixMPI::ValidationImpl() {
27 const auto &matrix = GetInput();
28
29
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 if (matrix.empty()) {
30 return true;
31 }
32
33 size_t cols = matrix[0].size();
34
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 return std::ranges::all_of(matrix, [cols](const auto &row) { return !row.empty() && row.size() == cols; });
35 }
36
37 10 bool KondakovVMinValMatrixMPI::PreProcessingImpl() {
38 10 return true;
39 }
40
41 10 bool KondakovVMinValMatrixMPI::RunImpl() {
42 10 int n = 0;
43 10 int rank = 0;
44 10 MPI_Comm_size(MPI_COMM_WORLD, &n);
45 10 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
46
47 10 auto [total_rows, cols] = BroadcastMatrixDimensions();
48
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8 times.
10 if (total_rows == 0) {
49 GetOutput().clear();
50 2 return true;
51 }
52
53
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 int local_row_count = static_cast<int>(total_rows / n) + (std::cmp_less(rank, total_rows % n) ? 1 : 0);
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (static_cast<uint64_t>(local_row_count) * cols > static_cast<uint64_t>(std::numeric_limits<int>::max())) {
55 throw std::runtime_error("Local matrix slice too large (exceeds INT_MAX elements)");
56 }
57
58 8 auto local_flat = ScatterMatrixData(total_rows, cols, n, rank);
59
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 auto local_minima = ComputeLocalMinima(local_flat, cols, local_row_count);
60
3/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
16 GetOutput() = GatherMinima(local_minima, total_rows, n, rank);
61
62 return true;
63 }
64
65 10 std::pair<size_t, size_t> KondakovVMinValMatrixMPI::BroadcastMatrixDimensions() {
66 10 int rank = 0;
67 10 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
68
69 size_t total_rows = 0;
70 size_t cols = 0;
71
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (rank == 0) {
72 const auto &in_data = GetInput();
73 total_rows = in_data.size();
74
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 cols = (total_rows > 0) ? in_data[0].size() : 0;
75 }
76
77 10 uint64_t total_rows_u64 = total_rows;
78 10 uint64_t cols_u64 = cols;
79 10 MPI_Bcast(&total_rows_u64, 1, MPI_UINT64_T, 0, MPI_COMM_WORLD);
80 10 MPI_Bcast(&cols_u64, 1, MPI_UINT64_T, 0, MPI_COMM_WORLD);
81 10 return {static_cast<size_t>(total_rows_u64), static_cast<size_t>(cols_u64)};
82 }
83
84 8 std::vector<int> KondakovVMinValMatrixMPI::ScatterMatrixData(size_t total_rows, size_t cols, int n, int rank) {
85 8 std::vector<int> send_counts(n, 0);
86
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 std::vector<int> send_displs(n, 0);
87
88
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 PrepareSendInfo(rank, total_rows, cols, n, send_counts, send_displs);
89
90
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Bcast(send_counts.data(), n, MPI_INT, 0, MPI_COMM_WORLD);
91
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Bcast(send_displs.data(), n, MPI_INT, 0, MPI_COMM_WORLD);
92
93 8 int local_row_count = static_cast<int>(total_rows / n);
94
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (std::cmp_less(rank, total_rows % n)) {
95 3 ++local_row_count;
96 }
97
98
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 std::vector<int> local_flat(local_row_count * cols);
99
100
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank == 0) {
101 const auto &in_data = GetInput();
102
1/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
4 std::vector<int> flat_data(total_rows * cols);
103 size_t idx = 0;
104
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
11 for (const auto &row : in_data) {
105 std::ranges::copy(row, flat_data.begin() + static_cast<std::vector<int>::difference_type>(idx));
106 7 idx += row.size();
107 }
108 assert(idx == total_rows * cols);
109
110
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 MPI_Scatterv(flat_data.data(), send_counts.data(), send_displs.data(), MPI_INT, local_flat.data(),
111 static_cast<int>(local_flat.size()), MPI_INT, 0, MPI_COMM_WORLD);
112 } else {
113
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 MPI_Scatterv(nullptr, send_counts.data(), send_displs.data(), MPI_INT, local_flat.data(),
114 static_cast<int>(local_flat.size()), MPI_INT, 0, MPI_COMM_WORLD);
115 }
116
117 8 return local_flat;
118 }
119
120 8 void KondakovVMinValMatrixMPI::PrepareSendInfo(int rank, size_t total_rows, size_t cols, int n,
121 std::vector<int> &send_counts, std::vector<int> &send_displs) {
122
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank != 0) {
123 return;
124 }
125
126 4 int extra = static_cast<int>(total_rows % n);
127
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (int i = 0; i < n; ++i) {
128 8 int rows_i = static_cast<int>(total_rows / n);
129
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
8 if (i < extra) {
130 3 ++rows_i;
131 }
132 8 uint64_t count = static_cast<uint64_t>(rows_i) * cols;
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (count > static_cast<uint64_t>(std::numeric_limits<int>::max())) {
134 throw std::runtime_error("Matrix too large for MPI (slice exceeds INT_MAX)");
135 }
136 8 send_counts[i] = static_cast<int>(count);
137 }
138
139
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (int i = 1; i < n; ++i) {
140 4 send_displs[i] = send_displs[i - 1] + send_counts[i - 1];
141 }
142 }
143
144 8 std::vector<int> KondakovVMinValMatrixMPI::ComputeLocalMinima(const std::vector<int> &local_flat, size_t cols,
145 int local_row_count) {
146 8 std::vector<int> local_minima(local_row_count);
147
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8 times.
15 for (int i = 0; i < local_row_count; ++i) {
148 7 int min_val = std::numeric_limits<int>::max();
149 7 const int *row = local_flat.data() + (i * cols);
150
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 7 times.
26 for (size_t j = 0; j < cols; ++j) {
151
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 9 times.
29 min_val = std::min(min_val, row[j]);
152 }
153 7 local_minima[i] = min_val;
154 }
155 8 return local_minima;
156 }
157
158 8 std::vector<int> KondakovVMinValMatrixMPI::GatherMinima(const std::vector<int> &local_minima, size_t total_rows, int n,
159 int rank) {
160 8 std::vector<int> recv_counts(n);
161
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 std::vector<int> displs(n);
162
163
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (n > 0 && rank == 0) {
164 4 int extra = static_cast<int>(total_rows % n);
165
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (int i = 0; i < n; ++i) {
166
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
13 recv_counts[i] = static_cast<int>(total_rows / n) + ((i < extra) ? 1 : 0);
167 }
168 4 displs[0] = 0;
169
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (int i = 1; i < n; ++i) {
170 4 displs[i] = displs[i - 1] + recv_counts[i - 1];
171 }
172 }
173
174
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Bcast(recv_counts.data(), n, MPI_INT, 0, MPI_COMM_WORLD);
175
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Bcast(displs.data(), n, MPI_INT, 0, MPI_COMM_WORLD);
176
177
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 std::vector<int> global_minima(total_rows);
178
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
12 MPI_Gatherv(local_minima.data(), static_cast<int>(local_minima.size()), MPI_INT,
179 rank == 0 ? global_minima.data() : nullptr, recv_counts.data(), displs.data(), MPI_INT, 0,
180 MPI_COMM_WORLD);
181
182
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Bcast(global_minima.data(), static_cast<int>(total_rows), MPI_INT, 0, MPI_COMM_WORLD);
183 8 return global_minima;
184 }
185
186 10 bool KondakovVMinValMatrixMPI::PostProcessingImpl() {
187 10 return true;
188 }
189
190 } // namespace kondakov_v_min_val_in_matrix_str
191