| 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 |