GCC Code Coverage Report


Directory: ./
File: tasks/artyushkina_string_matrix/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 0 94 0.0%
Functions: 0 11 0.0%
Branches: 0 100 0.0%

Line Branch Exec Source
1 #include "artyushkina_string_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 "artyushkina_string_matrix/common/include/common.hpp"
14
15 namespace artyushkina_string_matrix {
16
17 ArtyushkinaStringMatrixMPI::ArtyushkinaStringMatrixMPI(const InType &in) {
18 SetTypeOfTask(GetStaticTypeOfTask());
19
20 if (!in.empty()) {
21 GetInput() = in;
22 } else {
23 GetInput() = InType{};
24 }
25
26 GetOutput() = OutType{};
27 }
28
29 bool ArtyushkinaStringMatrixMPI::ValidationImpl() {
30 const auto &input = GetInput();
31 if (input.empty()) {
32 return false;
33 }
34
35 const std::size_t cols = input[0].size();
36 if (cols == 0) {
37 return false;
38 }
39
40 return std::ranges::all_of(input, [cols](const auto &row) { return row.size() == cols; });
41 }
42
43 bool ArtyushkinaStringMatrixMPI::PreProcessingImpl() {
44 GetOutput().clear();
45 return true;
46 }
47
48 std::vector<int> ArtyushkinaStringMatrixMPI::FlattenMatrix(const std::vector<std::vector<int>> &matrix) {
49 if (matrix.empty() || matrix[0].empty()) {
50 return {};
51 }
52
53 const std::size_t rows = matrix.size();
54 const std::size_t cols = matrix[0].size();
55
56 std::vector<int> flat;
57 flat.reserve(rows * cols);
58
59 for (const auto &row : matrix) {
60 flat.insert(flat.end(), row.begin(), row.end());
61 }
62
63 return flat;
64 }
65
66 std::pair<int, int> ArtyushkinaStringMatrixMPI::PrepareDimensions(const std::vector<std::vector<int>> &matrix, int rank,
67 int &size) {
68 int total_rows = static_cast<int>(matrix.size());
69 int total_cols = (total_rows > 0) ? static_cast<int>(matrix[0].size()) : 0;
70
71 if (rank == 0 && total_rows > 0 && total_rows < size) {
72 size = std::min(total_rows, size);
73 }
74
75 if (size == 0) {
76 size = 1;
77 }
78
79 std::array<int, 2> dimensions = {total_rows, total_cols};
80 MPI_Bcast(dimensions.data(), 2, MPI_INT, 0, MPI_COMM_WORLD);
81
82 return {dimensions[0], dimensions[1]};
83 }
84
85 std::pair<int, int> ArtyushkinaStringMatrixMPI::CalculateProcessInfo(int total_rows, int size, int rank) {
86 if (size <= 0) {
87 size = 1;
88 }
89
90 const int rows_per_process = total_rows / size;
91 const int remainder = total_rows % size;
92
93 const int my_rows = rows_per_process + ((rank < remainder) ? 1 : 0);
94
95 int offset = 0;
96 for (int i = 0; i < rank; ++i) {
97 const int rows_for_i = rows_per_process + ((i < remainder) ? 1 : 0);
98 offset += rows_for_i;
99 }
100
101 return {my_rows, offset};
102 }
103
104 std::vector<int> ArtyushkinaStringMatrixMPI::ScatterData(const std::vector<std::vector<int>> &matrix, int total_rows,
105 int total_cols, int size, int rank, int my_rows) {
106 if (size <= 0) {
107 size = 1;
108 }
109
110 std::vector<int> local_data(static_cast<std::size_t>(my_rows) * static_cast<std::size_t>(total_cols));
111
112 if (rank == 0) {
113 std::vector<int> flat_matrix = FlattenMatrix(matrix);
114
115 const int rows_per_process = total_rows / size;
116 const int remainder = total_rows % size;
117
118 std::vector<int> send_counts(size);
119 std::vector<int> displacements(size);
120
121 int offset = 0;
122 for (int i = 0; i < size; ++i) {
123 const int rows_for_i = rows_per_process + ((i < remainder) ? 1 : 0);
124 send_counts[i] = rows_for_i * total_cols;
125 displacements[i] = offset * total_cols;
126 offset += rows_for_i;
127 }
128
129 MPI_Scatterv(flat_matrix.data(), send_counts.data(), displacements.data(), MPI_INT, local_data.data(),
130 my_rows * total_cols, MPI_INT, 0, MPI_COMM_WORLD);
131 } else {
132 MPI_Scatterv(nullptr, nullptr, nullptr, MPI_INT, local_data.data(), my_rows * total_cols, MPI_INT, 0,
133 MPI_COMM_WORLD);
134 }
135
136 return local_data;
137 }
138
139 std::vector<int> ArtyushkinaStringMatrixMPI::ComputeLocalMinima(const std::vector<int> &local_data, int my_rows,
140 int total_cols) {
141 std::vector<int> local_minima(static_cast<std::size_t>(my_rows), INT_MAX);
142
143 for (int i = 0; i < my_rows; ++i) {
144 for (int j = 0; j < total_cols; ++j) {
145 const int index = (i * total_cols) + j;
146 const int val = local_data[static_cast<std::size_t>(index)];
147 local_minima[static_cast<std::size_t>(i)] = std::min(val, local_minima[static_cast<std::size_t>(i)]);
148 }
149 }
150
151 return local_minima;
152 }
153
154 std::vector<int> ArtyushkinaStringMatrixMPI::GatherResults(const std::vector<int> &local_minima, int total_rows,
155 int size, int rank, int my_rows) {
156 std::vector<int> global_minima;
157
158 if (rank == 0) {
159 global_minima.resize(static_cast<std::size_t>(total_rows));
160 }
161
162 if (size <= 0) {
163 size = 1;
164 }
165
166 const int rows_per_process = total_rows / size;
167 const int remainder = total_rows % size;
168
169 std::vector<int> recv_counts(size);
170 std::vector<int> displacements_recv(size);
171
172 int rows_so_far = 0;
173 for (int i = 0; i < size; ++i) {
174 const int rows_for_i = rows_per_process + ((i < remainder) ? 1 : 0);
175 recv_counts[i] = rows_for_i;
176 displacements_recv[i] = rows_so_far;
177 rows_so_far += rows_for_i;
178 }
179
180 MPI_Gatherv(local_minima.data(), my_rows, MPI_INT, global_minima.data(), recv_counts.data(),
181 displacements_recv.data(), MPI_INT, 0, MPI_COMM_WORLD);
182
183 return global_minima;
184 }
185
186 bool ArtyushkinaStringMatrixMPI::RunImpl() {
187 int rank = 0;
188 int size = 1;
189 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
190 MPI_Comm_size(MPI_COMM_WORLD, &size);
191
192 const auto &matrix = GetInput();
193
194 if (matrix.empty()) {
195 if (rank == 0) {
196 GetOutput().clear();
197 }
198 return true;
199 }
200
201 auto [total_rows, total_cols] = PrepareDimensions(matrix, rank, size);
202 auto [my_rows, offset] = CalculateProcessInfo(total_rows, size, rank);
203
204 std::vector<int> local_data = ScatterData(matrix, total_rows, total_cols, size, rank, my_rows);
205
206 std::vector<int> local_minima = ComputeLocalMinima(local_data, my_rows, total_cols);
207
208 std::vector<int> global_minima = GatherResults(local_minima, total_rows, size, rank, my_rows);
209
210 if (rank == 0) {
211 GetOutput() = std::move(global_minima);
212 } else {
213 GetOutput().clear();
214 }
215
216 return true;
217 }
218
219 bool ArtyushkinaStringMatrixMPI::PostProcessingImpl() {
220 return true;
221 }
222
223 } // namespace artyushkina_string_matrix
224