GCC Code Coverage Report


Directory: ./
File: tasks/akhmetov_daniil_mesh_torus/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 112 124 90.3%
Functions: 12 14 85.7%
Branches: 44 86 51.2%

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