| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "akhmetov_daniil_mesh_torus/mpi/include/ops_mpi.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cmath> | ||
| 7 | #include <iterator> | ||
| 8 | #include <utility> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "akhmetov_daniil_mesh_torus/common/include/common.hpp" | ||
| 12 | |||
| 13 | namespace akhmetov_daniil_mesh_torus { | ||
| 14 | |||
| 15 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | MeshTorusMpi::MeshTorusMpi(const InType &in) { |
| 16 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 17 | GetInput() = in; | ||
| 18 | 10 | GetOutput() = {}; | |
| 19 | 10 | } | |
| 20 | |||
| 21 | 10 | std::pair<int, int> MeshTorusMpi::ComputeGrid(int size) { | |
| 22 | 10 | int rows = static_cast<int>(std::sqrt(static_cast<double>(size))); | |
| 23 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
10 | while (rows > 1 && (size % rows != 0)) { |
| 24 | ✗ | --rows; | |
| 25 | } | ||
| 26 | 10 | if (rows <= 0) { | |
| 27 | rows = 1; | ||
| 28 | } | ||
| 29 | 10 | int cols = size / rows; | |
| 30 | 10 | if (cols <= 0) { | |
| 31 | cols = 1; | ||
| 32 | } | ||
| 33 | 10 | return {rows, cols}; | |
| 34 | } | ||
| 35 | |||
| 36 | ✗ | int MeshTorusMpi::RankFromCoords(int row, int col, int rows, int cols) { | |
| 37 | 10 | int rr = ((row % rows) + rows) % rows; | |
| 38 | 10 | int cc = ((col % cols) + cols) % cols; | |
| 39 | 10 | return (rr * cols) + cc; | |
| 40 | } | ||
| 41 | |||
| 42 | ✗ | std::pair<int, int> MeshTorusMpi::CoordsFromRank(int rank, int cols) { | |
| 43 | 10 | int r = rank / cols; | |
| 44 | 10 | int c = rank % cols; | |
| 45 | ✗ | return {r, c}; | |
| 46 | } | ||
| 47 | |||
| 48 | 10 | std::vector<int> MeshTorusMpi::BuildPath(int rows, int cols, int source, int dest) { | |
| 49 | 10 | std::vector<int> path; | |
| 50 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (rows <= 0 || cols <= 0) { |
| 51 | path.push_back(source); | ||
| 52 | return path; | ||
| 53 | } | ||
| 54 | |||
| 55 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | auto [sr, sc] = CoordsFromRank(source, cols); |
| 56 | auto [dr, dc] = CoordsFromRank(dest, cols); | ||
| 57 | |||
| 58 | int cur_r = sr; | ||
| 59 | int cur_c = sc; | ||
| 60 | path.push_back(source); | ||
| 61 | |||
| 62 | 10 | int diff_c = dc - sc; | |
| 63 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | int right_dist = (diff_c >= 0) ? diff_c : diff_c + cols; |
| 64 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | int left_dist = (diff_c <= 0) ? -diff_c : cols - diff_c; |
| 65 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | int step_c = (right_dist <= left_dist) ? 1 : -1; |
| 66 | 10 | int steps_c = (right_dist <= left_dist) ? right_dist : left_dist; | |
| 67 | |||
| 68 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | for (int i = 0; i < steps_c; ++i) { |
| 69 | 10 | cur_c += step_c; | |
| 70 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | path.push_back(RankFromCoords(cur_r, cur_c, rows, cols)); |
| 71 | } | ||
| 72 | |||
| 73 | 10 | int diff_r = dr - sr; | |
| 74 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | int down_dist = (diff_r >= 0) ? diff_r : diff_r + rows; |
| 75 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | int up_dist = (diff_r <= 0) ? -diff_r : rows - diff_r; |
| 76 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | int step_r = (down_dist <= up_dist) ? 1 : -1; |
| 77 | 10 | int steps_r = (down_dist <= up_dist) ? down_dist : up_dist; | |
| 78 | |||
| 79 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | for (int i = 0; i < steps_r; ++i) { |
| 80 | ✗ | cur_r += step_r; | |
| 81 | ✗ | path.push_back(RankFromCoords(cur_r, cur_c, rows, cols)); | |
| 82 | } | ||
| 83 | |||
| 84 | return path; | ||
| 85 | } | ||
| 86 | |||
| 87 | 10 | bool MeshTorusMpi::ValidationImpl() { | |
| 88 | 10 | int initialized = 0; | |
| 89 | 10 | MPI_Initialized(&initialized); | |
| 90 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (initialized == 0) { |
| 91 | return false; | ||
| 92 | } | ||
| 93 | 10 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank_); | |
| 94 | 10 | MPI_Comm_size(MPI_COMM_WORLD, &world_size_); | |
| 95 | |||
| 96 | 10 | int is_valid = 0; | |
| 97 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if (world_rank_ == 0) { |
| 98 | const auto &in = GetInput(); | ||
| 99 |
4/8✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
5 | if (in.source >= 0 && in.dest >= 0 && in.source < world_size_ && in.dest < world_size_) { |
| 100 | 5 | is_valid = 1; | |
| 101 | } | ||
| 102 | } | ||
| 103 | 10 | MPI_Bcast(&is_valid, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 104 | 10 | return is_valid != 0; | |
| 105 | } | ||
| 106 | |||
| 107 | 10 | bool MeshTorusMpi::PreProcessingImpl() { | |
| 108 | 10 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank_); | |
| 109 | 10 | MPI_Comm_size(MPI_COMM_WORLD, &world_size_); | |
| 110 | |||
| 111 | 10 | auto [r, c] = MeshTorusMpi::ComputeGrid(world_size_); | |
| 112 | 10 | rows_ = r; | |
| 113 | 10 | cols_ = c; | |
| 114 | |||
| 115 | local_in_ = GetInput(); | ||
| 116 | 10 | local_out_ = OutType{}; | |
| 117 | 10 | return true; | |
| 118 | } | ||
| 119 | |||
| 120 | 10 | bool MeshTorusMpi::RunImpl() { | |
| 121 | 10 | int source = 0; | |
| 122 | 10 | int dest = 0; | |
| 123 | 10 | BroadcastSourceDest(source, dest); | |
| 124 | |||
| 125 | 10 | int payload_size = 0; | |
| 126 | 10 | BroadcastPayloadSize(source, payload_size); | |
| 127 | |||
| 128 | 10 | std::vector<int> payload_buf = PreparePayloadBuffer(source, payload_size); | |
| 129 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | std::vector<int> path = MeshTorusMpi::BuildPath(rows_, cols_, source, dest); |
| 130 | |||
| 131 | 10 | std::vector<int> recv_payload; | |
| 132 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | ProcessPathCommunication(source, dest, path, payload_buf, recv_payload); |
| 133 | |||
| 134 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | SetOutput(dest, recv_payload, path); |
| 135 | 10 | return true; | |
| 136 | } | ||
| 137 | |||
| 138 | 10 | void MeshTorusMpi::BroadcastSourceDest(int &source, int &dest) { | |
| 139 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if (world_rank_ == 0) { |
| 140 | const auto &in = GetInput(); | ||
| 141 | 5 | source = in.source; | |
| 142 | 5 | dest = in.dest; | |
| 143 | } | ||
| 144 | 10 | MPI_Bcast(&source, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 145 | 10 | MPI_Bcast(&dest, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 146 | 10 | } | |
| 147 | |||
| 148 | 10 | void MeshTorusMpi::BroadcastPayloadSize(int source, int &payload_size) const { | |
| 149 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if (world_rank_ == source) { |
| 150 | 5 | payload_size = static_cast<int>(local_in_.payload.size()); | |
| 151 | } | ||
| 152 | 10 | MPI_Bcast(&payload_size, 1, MPI_INT, source, MPI_COMM_WORLD); | |
| 153 | 10 | } | |
| 154 | |||
| 155 | 10 | [[nodiscard]] std::vector<int> MeshTorusMpi::PreparePayloadBuffer(int source, int payload_size) const { | |
| 156 | 10 | std::vector<int> payload_buf(payload_size); | |
| 157 |
3/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | if (world_rank_ == source && payload_size > 0) { |
| 158 | 5 | std::copy(local_in_.payload.begin(), local_in_.payload.end(), payload_buf.begin()); // NOLINT(modernize-use-ranges) | |
| 159 | } | ||
| 160 | 10 | return payload_buf; | |
| 161 | } | ||
| 162 | |||
| 163 | // NOLINTNEXTLINE(readability-function-cognitive-complexity) | ||
| 164 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | void MeshTorusMpi::ProcessPathCommunication(int source, int dest, const std::vector<int> &path, |
| 165 | const std::vector<int> &payload_buf, std::vector<int> &recv_payload) const { | ||
| 166 | 10 | const int path_size = static_cast<int>(path.size()); | |
| 167 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | auto it = std::find(path.begin(), path.end(), world_rank_); // NOLINT(modernize-use-ranges) |
| 168 | const bool on_path = (it != path.end()); | ||
| 169 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | const int my_index = on_path ? static_cast<int>(std::distance(path.begin(), it)) : -1; |
| 170 | |||
| 171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (source == dest) { |
| 172 | ✗ | if (world_rank_ == source) { | |
| 173 | ✗ | recv_payload = payload_buf; | |
| 174 | } | ||
| 175 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | } else if (world_rank_ == source) { |
| 176 | 5 | recv_payload = payload_buf; | |
| 177 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (path_size > 1) { |
| 178 | 5 | int next_rank = path[1]; | |
| 179 | 5 | int size_to_send = static_cast<int>(payload_buf.size()); | |
| 180 | 5 | MPI_Send(&size_to_send, 1, MPI_INT, next_rank, 0, MPI_COMM_WORLD); | |
| 181 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (size_to_send > 0) { |
| 182 | 5 | MPI_Send(recv_payload.data(), size_to_send, MPI_INT, next_rank, 1, MPI_COMM_WORLD); | |
| 183 | } | ||
| 184 | } | ||
| 185 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | } else if (on_path) { |
| 186 | 5 | int prev_rank = path[my_index - 1]; | |
| 187 | 5 | int recv_size = 0; | |
| 188 | 5 | MPI_Recv(&recv_size, 1, MPI_INT, prev_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | |
| 189 | 5 | recv_payload.resize(recv_size); | |
| 190 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (recv_size > 0) { |
| 191 | 5 | MPI_Recv(recv_payload.data(), recv_size, MPI_INT, prev_rank, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | |
| 192 | } | ||
| 193 | |||
| 194 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
5 | if (world_rank_ != dest && my_index + 1 < path_size) { |
| 195 | ✗ | int next_rank = path[my_index + 1]; | |
| 196 | ✗ | MPI_Send(&recv_size, 1, MPI_INT, next_rank, 0, MPI_COMM_WORLD); | |
| 197 | ✗ | if (recv_size > 0) { | |
| 198 | ✗ | MPI_Send(recv_payload.data(), recv_size, MPI_INT, next_rank, 1, MPI_COMM_WORLD); | |
| 199 | } | ||
| 200 | } | ||
| 201 | } | ||
| 202 | 10 | } | |
| 203 | |||
| 204 | 10 | void MeshTorusMpi::SetOutput(int dest, const std::vector<int> &recv_payload, const std::vector<int> &path) { | |
| 205 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if (world_rank_ == dest) { |
| 206 | 5 | local_out_.payload = recv_payload; | |
| 207 | 5 | local_out_.path = path; | |
| 208 | GetOutput() = local_out_; | ||
| 209 | } else { | ||
| 210 | 5 | GetOutput() = OutType{}; | |
| 211 | } | ||
| 212 | 10 | } | |
| 213 | |||
| 214 | 10 | bool MeshTorusMpi::PostProcessingImpl() { | |
| 215 | 10 | return true; | |
| 216 | } | ||
| 217 | |||
| 218 | } // namespace akhmetov_daniil_mesh_torus | ||
| 219 |