GCC Code Coverage Report


Directory: ./
File: tasks/moskaev_v_hypercub/mpi/src/ops_mpi.cpp
Date: 2026-02-02 01:14:38
Exec Total Coverage
Lines: 130 152 85.5%
Functions: 12 13 92.3%
Branches: 57 84 67.9%

Line Branch Exec Source
1 #include "moskaev_v_hypercub/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cmath>
6 #include <iostream>
7 #include <random>
8
9 #include "moskaev_v_hypercub/common/include/common.hpp"
10
11 namespace moskaev_v_hypercub {
12
13 namespace {
14
15 int CalculateHops(int src, int dest) {
16 int diff = src ^ dest;
17 int hops = 0;
18
19
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 while (diff != 0) {
20 4 hops++;
21 4 diff &= (diff - 1);
22 }
23
24 return hops;
25 }
26
27 4 int HypercubeSum(int local_value, int rank, int size) {
28 4 int result = local_value;
29 int dims = 0;
30
31
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 while ((1 << dims) < size) {
32 4 dims++;
33 }
34
35
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (int dim = 0; dim < dims; dim++) {
36 4 int partner = rank ^ (1 << dim);
37
38
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (partner < size) {
39 4 int recv_value = 0;
40
41
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (rank < partner) {
42 2 MPI_Send(&result, 1, MPI_INT, partner, dim, MPI_COMM_WORLD);
43 2 MPI_Recv(&recv_value, 1, MPI_INT, partner, dim, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
44 } else {
45 2 MPI_Recv(&recv_value, 1, MPI_INT, partner, dim, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
46 2 MPI_Send(&result, 1, MPI_INT, partner, dim, MPI_COMM_WORLD);
47 }
48
49 4 result += recv_value;
50 }
51
52 4 MPI_Barrier(MPI_COMM_WORLD);
53 }
54
55 4 return result;
56 }
57
58 bool CheckIfPowerOfTwo(int size) {
59
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 return size > 0 && (size & (size - 1)) == 0;
60 }
61
62 int CalculateHypercubeDimensions(int size) {
63 int dimensions = 0;
64
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 while ((1 << dimensions) < size) {
65 6 dimensions++;
66 }
67 return dimensions;
68 }
69
70 6 bool VerifySingleNeighbor(int rank, int neighbor, int dim) {
71 6 int send_val = (rank * 1000) + dim;
72 6 int recv_val = 0;
73
74 6 MPI_Sendrecv(&send_val, 1, MPI_INT, neighbor, 100, &recv_val, 1, MPI_INT, neighbor, 100, MPI_COMM_WORLD,
75 MPI_STATUS_IGNORE);
76
77 6 int expected = (neighbor * 1000) + dim;
78 6 return recv_val == expected;
79 }
80
81 6 bool VerifyAllNeighbors(int rank, int size, int dimensions) {
82
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (int dim = 0; dim < dimensions; dim++) {
83 6 int neighbor = rank ^ (1 << dim);
84
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
6 if (neighbor < size && !VerifySingleNeighbor(rank, neighbor, dim)) {
85 return false;
86 }
87 }
88 return true;
89 }
90
91
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 void TestTopologyLogic(int rank, int size, HypercubeTestResult &result) {
92 bool topology_ok = CheckIfPowerOfTwo(size);
93
94 if (topology_ok) {
95 int dimensions = CalculateHypercubeDimensions(size);
96 6 topology_ok = VerifyAllNeighbors(rank, size, dimensions);
97 }
98
99
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 int local_topology_ok = topology_ok ? 1 : 0;
100 6 int global_topology_ok = 0;
101
102 6 MPI_Reduce(&local_topology_ok, &global_topology_ok, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD);
103
104
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank == 0) {
105 3 result.topology_verified = (global_topology_ok == 1);
106
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (result.topology_verified) {
107 3 result.total_tests_passed++;
108 3 std::cout << "Topology: PASSED" << "\n";
109 } else {
110 std::cout << "Topology: FAILED (not a valid hypercube)" << "\n";
111 }
112 }
113
114 6 MPI_Bcast(&global_topology_ok, 1, MPI_INT, 0, MPI_COMM_WORLD);
115 6 result.topology_verified = (global_topology_ok == 1);
116
117
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 if (rank != 0 && result.topology_verified) {
118 3 result.total_tests_passed++;
119 }
120 6 }
121
122 4 void TestCommunicationLogic(int rank, int size, HypercubeTestResult &result) {
123 bool comm_ok = true;
124 4 int max_hops = 0;
125
126
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if (rank == 0 || rank == size - 1) {
127 4 int test_value = 12345;
128 4 int hops = CalculateHops(0, size - 1);
129
130
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (rank == 0) {
131 2 MPI_Send(&test_value, 1, MPI_INT, size - 1, 200, MPI_COMM_WORLD);
132 comm_ok = true;
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (rank == size - 1) {
134 2 int recv_value = 0;
135 2 MPI_Recv(&recv_value, 1, MPI_INT, 0, 200, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
136 2 comm_ok = (recv_value == 12345);
137 }
138
139 2 max_hops = hops;
140 }
141
142
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 int local_comm_ok = comm_ok ? 1 : 0;
143 4 int global_comm_ok = 0;
144 4 MPI_Reduce(&local_comm_ok, &global_comm_ok, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD);
145
146 4 int global_max_hops = 0;
147 4 MPI_Reduce(&max_hops, &global_max_hops, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD);
148
149
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (rank == 0) {
150 2 result.communication_ok = (global_comm_ok == 1);
151 2 result.max_hops_required = global_max_hops;
152
153
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (result.communication_ok) {
154 2 result.total_tests_passed++;
155 4 std::cout << "Communication: PASSED (max hops: " << global_max_hops << ")" << "\n";
156 } else {
157 std::cout << "Communication: FAILED" << "\n";
158 }
159 }
160
161 4 MPI_Bcast(&global_comm_ok, 1, MPI_INT, 0, MPI_COMM_WORLD);
162 4 result.communication_ok = (global_comm_ok == 1);
163 4 MPI_Bcast(&global_max_hops, 1, MPI_INT, 0, MPI_COMM_WORLD);
164 4 result.max_hops_required = global_max_hops;
165
166
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if (rank != 0 && result.communication_ok) {
167 2 result.total_tests_passed++;
168 }
169 4 }
170
171 4 void TestComputationLogic(const InType &input, int rank, int size, HypercubeTestResult &result) {
172 4 std::mt19937 gen(input.seed + rank);
173 std::uniform_int_distribution<int> dist(1, 100);
174
175 int local_sum = 0;
176
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 4 times.
44 for (int i = 0; i < input.test_size; i++) {
177 40 local_sum += dist(gen);
178 }
179
180 4 int global_sum = HypercubeSum(local_sum, rank, size);
181
182
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (rank == 0) {
183 2 std::mt19937 check_gen(input.seed);
184 int expected_sum = 0;
185
186
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (int proc_rank = 0; proc_rank < size; proc_rank++) {
187 4 std::mt19937 proc_gen(input.seed + proc_rank);
188
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 4 times.
44 for (int i = 0; i < input.test_size; i++) {
189 40 expected_sum += dist(proc_gen);
190 }
191 }
192
193 2 result.computation_ok = std::abs(global_sum - expected_sum) <= 10;
194
195
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (result.computation_ok) {
196 2 result.total_tests_passed++;
197 6 std::cout << "Computation: PASSED (sum: " << global_sum << ", expected: " << expected_sum << ")" << "\n";
198 } else {
199 std::cout << "Computation: FAILED (sum: " << global_sum << ", expected: " << expected_sum << ")" << "\n";
200 }
201 }
202
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 int comp_ok = (rank == 0 && result.computation_ok) ? 1 : 0;
204 4 MPI_Bcast(&comp_ok, 1, MPI_INT, 0, MPI_COMM_WORLD);
205 4 result.computation_ok = (comp_ok == 1);
206
207
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 if (rank != 0 && result.computation_ok) {
208 2 result.total_tests_passed++;
209 }
210 4 }
211
212 6 void FinalizeResultsLogic(int rank, HypercubeTestResult &result) {
213 6 int final_total_passed = result.total_tests_passed;
214 6 MPI_Bcast(&final_total_passed, 1, MPI_INT, 0, MPI_COMM_WORLD);
215
216
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank != 0) {
217 3 result.total_tests_passed = final_total_passed;
218 }
219
220 if (rank == 0) {
221 6 std::cout << "Total tests passed: " << result.total_tests_passed << "/3" << "\n";
222 }
223 6 }
224
225 void SyncResultToAllProcesses(HypercubeTestResult &result, int rank) {
226 struct SyncData {
227 int total_tests_passed;
228 int topology_verified;
229 int communication_ok;
230 int computation_ok;
231 int max_hops_required;
232 };
233
234 SyncData data{};
235
236 if (rank == 0) {
237 data.total_tests_passed = result.total_tests_passed;
238 data.topology_verified = result.topology_verified ? 1 : 0;
239 data.communication_ok = result.communication_ok ? 1 : 0;
240 data.computation_ok = result.computation_ok ? 1 : 0;
241 data.max_hops_required = result.max_hops_required;
242 }
243
244 MPI_Bcast(&data, sizeof(SyncData), MPI_BYTE, 0, MPI_COMM_WORLD);
245
246 if (rank != 0) {
247 result.total_tests_passed = data.total_tests_passed;
248 result.topology_verified = data.topology_verified == 1;
249 result.communication_ok = data.communication_ok == 1;
250 result.computation_ok = data.computation_ok == 1;
251 result.max_hops_required = data.max_hops_required;
252 }
253 }
254
255 } // namespace
256
257 6 MoskaevVTestMPI::MoskaevVTestMPI(const InType &in) {
258 SetTypeOfTask(GetStaticTypeOfTask());
259 6 GetInput() = in;
260 6 GetOutput() = HypercubeTestResult();
261 6 }
262
263 6 bool MoskaevVTestMPI::ValidationImpl() {
264 6 return GetInput().test_size > 0;
265 }
266
267 6 bool MoskaevVTestMPI::PreProcessingImpl() {
268 6 return true;
269 }
270
271 6 bool MoskaevVTestMPI::RunImpl() {
272 6 int rank = 0;
273 6 int size = 0;
274 6 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
275 6 MPI_Comm_size(MPI_COMM_WORLD, &size);
276
277 6 HypercubeTestResult result;
278
279 6 TestTopologyLogic(rank, size, result);
280
281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!result.topology_verified) {
282 SyncResultToAllProcesses(result, rank);
283 GetOutput() = result;
284 return false;
285 }
286
287
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (GetInput().test_communication) {
288 4 TestCommunicationLogic(rank, size, result);
289 }
290
291
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (GetInput().test_computation) {
292 4 TestComputationLogic(GetInput(), rank, size, result);
293 }
294
295 6 FinalizeResultsLogic(rank, result);
296
297 6 GetOutput() = result;
298
299 6 return result.total_tests_passed > 0;
300 }
301
302 6 bool MoskaevVTestMPI::PostProcessingImpl() {
303 6 return GetOutput().total_tests_passed > 0;
304 }
305
306 } // namespace moskaev_v_hypercub
307