GCC Code Coverage Report


Directory: ./
File: tasks/shkrebko_m_hypercube/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 88 100 88.0%
Functions: 10 11 90.9%
Branches: 42 78 53.8%

Line Branch Exec Source
1 #include "shkrebko_m_hypercube/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cmath>
6 #include <cstddef>
7 #include <vector>
8
9 #include "shkrebko_m_hypercube/common/include/common.hpp"
10
11 namespace shkrebko_m_hypercube {
12
13 namespace {
14
15 3 int CalcNextRank(int current_rank, int destination_rank, int world_size) {
16
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (current_rank == destination_rank) {
17 return current_rank;
18 }
19
20 3 int ndims = static_cast<int>(log2(world_size));
21
22
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 for (int dim = 0; dim < ndims; dim++) {
23 int current_bit = (current_rank >> dim) & 1;
24 int dest_bit = (destination_rank >> dim) & 1;
25
26
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (current_bit != dest_bit) {
27 3 int next_rank = current_rank ^ (1 << dim);
28 3 return next_rank;
29 }
30 }
31
32 return current_rank;
33 }
34
35 9 void SendHypercubeData(const HypercubeData &data, int dest_rank, int tag) {
36 9 MPI_Send(&data.value, 1, MPI_INT, dest_rank, tag, MPI_COMM_WORLD);
37 9 MPI_Send(&data.destination, 1, MPI_INT, dest_rank, tag + 1, MPI_COMM_WORLD);
38 9 MPI_Send(&data.finish, 1, MPI_C_BOOL, dest_rank, tag + 2, MPI_COMM_WORLD);
39 9 int path_size = static_cast<int>(data.path.size());
40 9 MPI_Send(&path_size, 1, MPI_INT, dest_rank, tag + 3, MPI_COMM_WORLD);
41
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (path_size > 0) {
42 9 MPI_Send(data.path.data(), path_size, MPI_INT, dest_rank, tag + 4, MPI_COMM_WORLD);
43 }
44 9 }
45
46 9 void RecvHypercubeData(HypercubeData &data, int src_rank, int tag, MPI_Status *status = MPI_STATUS_IGNORE) {
47 9 MPI_Recv(&data.value, 1, MPI_INT, src_rank, tag, MPI_COMM_WORLD, status);
48 9 MPI_Recv(&data.destination, 1, MPI_INT, src_rank, tag + 1, MPI_COMM_WORLD, status);
49 9 MPI_Recv(&data.finish, 1, MPI_C_BOOL, src_rank, tag + 2, MPI_COMM_WORLD, status);
50 9 int path_size = 0;
51 9 MPI_Recv(&path_size, 1, MPI_INT, src_rank, tag + 3, MPI_COMM_WORLD, status);
52 9 data.path.resize(path_size);
53
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (path_size > 0) {
54 9 MPI_Recv(data.path.data(), path_size, MPI_INT, src_rank, tag + 4, MPI_COMM_WORLD, status);
55 }
56 9 }
57
58 void ArtificialDelay() {
59
2/2
✓ Branch 0 taken 60000 times.
✓ Branch 1 taken 6 times.
60006 for (int i = 0; i < 10000; i++) {
60 60000 volatile int dummy = 0;
61
2/2
✓ Branch 0 taken 600000000 times.
✓ Branch 1 taken 60000 times.
600060000 for (int j = 0; j < 10000; j++) {
62 600000000 dummy += i * j;
63 }
64 }
65 }
66
67 HypercubeData HandleSingleProcessCase(int rank, const HypercubeData &init_data) {
68 HypercubeData result = init_data;
69 result.path.push_back(rank);
70 result.finish = true;
71 return result;
72 }
73
74 3 HypercubeData HandleRootProcess(int rank, int world_size, const HypercubeData &init_data) {
75 HypercubeData local_data = init_data;
76 local_data.path.push_back(rank);
77 3 local_data.finish = false;
78
79
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (local_data.destination != rank) {
80 3 int next_rank = CalcNextRank(rank, local_data.destination, world_size);
81
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 SendHypercubeData(local_data, next_rank, 0);
82
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 RecvHypercubeData(local_data, MPI_ANY_SOURCE, 1);
83 } else {
84 local_data.finish = true;
85 }
86
87
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (int i = 1; i < world_size; i++) {
88
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 SendHypercubeData(local_data, i, 0);
89 }
90
91 3 return local_data;
92 }
93
94 3 HypercubeData HandleNonRootProcess(int rank, int world_size) {
95 3 HypercubeData local_data;
96 MPI_Status status;
97
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 RecvHypercubeData(local_data, MPI_ANY_SOURCE, 0, &status);
98
99
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (!local_data.finish) {
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 local_data.path.push_back(rank);
101
102
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rank == local_data.destination) {
103 3 local_data.finish = true;
104
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 SendHypercubeData(local_data, 0, 1);
105
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 RecvHypercubeData(local_data, 0, 0, &status);
106 } else {
107 int next_rank = CalcNextRank(rank, local_data.destination, world_size);
108 SendHypercubeData(local_data, next_rank, 0);
109 RecvHypercubeData(local_data, 0, 0, &status);
110 }
111 }
112
113 3 return local_data;
114 }
115
116 } // namespace
117
118
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 ShkrebkoMHypercubeMPI::ShkrebkoMHypercubeMPI(const InType &in) {
119 SetTypeOfTask(GetStaticTypeOfTask());
120
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GetInput() = in;
121 6 GetOutput() = HypercubeData();
122 6 }
123
124 6 bool ShkrebkoMHypercubeMPI::ValidationImpl() {
125 6 int world_size = 0;
126 6 int world_rank = 0;
127 6 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
128 6 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
129
130 bool is_valid = true;
131
132
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (world_rank == 0) {
133
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (GetInput().size() < 2) {
134 is_valid = false;
135 }
136
137 if (is_valid) {
138 3 int destination = GetInput()[1];
139
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (destination < 0 || destination >= world_size) {
140 is_valid = false;
141 }
142
143
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (GetInput()[0] <= 0) {
144 is_valid = false;
145 }
146 }
147 }
148
149
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 int valid_int = is_valid ? 1 : 0;
150 6 MPI_Bcast(&valid_int, 1, MPI_INT, 0, MPI_COMM_WORLD);
151
152 6 return valid_int == 1;
153 }
154
155
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 bool ShkrebkoMHypercubeMPI::PreProcessingImpl() {
156
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (GetInput().size() >= 2) {
157 6 GetOutput().value = GetInput()[0];
158 6 GetOutput().destination = GetInput()[1];
159 } else {
160 GetOutput().value = 1;
161 GetOutput().destination = 0;
162 }
163 6 return true;
164 }
165
166 6 bool ShkrebkoMHypercubeMPI::RunImpl() {
167 6 int world_rank = 0;
168 6 int world_size = 0;
169 6 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
170 6 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
171
172 ArtificialDelay();
173
174
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (world_size == 1) {
175 GetOutput() = HandleSingleProcessCase(world_rank, GetOutput());
176 MPI_Barrier(MPI_COMM_WORLD);
177 return true;
178 }
179
180 6 HypercubeData result;
181
182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (world_rank == 0) {
183
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 result = HandleRootProcess(world_rank, world_size, GetOutput());
184 } else {
185
1/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 result = HandleNonRootProcess(world_rank, world_size);
186 }
187
188 GetOutput() = result;
189
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Barrier(MPI_COMM_WORLD);
190 return true;
191 }
192
193 6 bool ShkrebkoMHypercubeMPI::PostProcessingImpl() {
194
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (std::size_t i = 1; i < GetOutput().path.size(); i++) {
195
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 int prev = GetOutput().path[i - 1];
196 6 int curr = GetOutput().path[i];
197
198 6 int diff = prev ^ curr;
199
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if ((diff & (diff - 1)) != 0) {
200 return false;
201 }
202 }
203
204 return true;
205 }
206
207 } // namespace shkrebko_m_hypercube
208