GCC Code Coverage Report


Directory: ./
File: tasks/baranov_a_custom_allreduce/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 78 123 63.4%
Functions: 9 12 75.0%
Branches: 73 174 42.0%

Line Branch Exec Source
1 #include "baranov_a_custom_allreduce/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cmath>
6 #include <cstddef>
7 #include <cstdlib>
8 #include <cstring>
9 #include <exception>
10 #include <stdexcept>
11 #include <variant>
12 #include <vector>
13
14 #include "baranov_a_custom_allreduce/common/include/common.hpp"
15
16 namespace baranov_a_custom_allreduce {
17
18 void BaranovACustomAllreduceMPI::TreeBroadcast(void *buffer, int count, MPI_Datatype datatype, MPI_Comm comm,
19 int root) {
20 int rank = 0;
21 int size = 0;
22 MPI_Comm_rank(comm, &rank);
23 MPI_Comm_size(comm, &size);
24
25 if (count == 0) {
26 return;
27 }
28 if (rank == root) {
29 for (int i = 0; i < size; i++) {
30 if (i != root) {
31 MPI_Send(buffer, count, datatype, i, 0, comm);
32 }
33 }
34 } else {
35 MPI_Recv(buffer, count, datatype, root, 0, comm, MPI_STATUS_IGNORE);
36 }
37 }
38
39 void BaranovACustomAllreduceMPI::TreeReduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op,
40 MPI_Comm comm, int root) {
41 int rank = 0;
42 int size = 0;
43 MPI_Comm_rank(comm, &rank);
44 MPI_Comm_size(comm, &size);
45
46 if (count == 0) {
47 return;
48 }
49
50 int type_size = 0;
51 MPI_Type_size(datatype, &type_size);
52
53 std::memcpy(recvbuf, sendbuf, static_cast<std::size_t>(count) * static_cast<std::size_t>(type_size));
54 if (rank == root) {
55 for (int i = 0; i < size; i++) {
56 if (i != root) {
57 std::vector<unsigned char> temp_buf(static_cast<std::size_t>(count) * static_cast<std::size_t>(type_size));
58 if (temp_buf.empty()) {
59 throw std::runtime_error("Memory allocation failed");
60 }
61
62 MPI_Recv(temp_buf.data(), count, datatype, i, 0, comm, MPI_STATUS_IGNORE);
63 PerformOperation(temp_buf.data(), recvbuf, count, datatype, op);
64 }
65 }
66 } else {
67 MPI_Send(recvbuf, count, datatype, root, 0, comm);
68 std::memset(recvbuf, 0, static_cast<std::size_t>(count) * static_cast<std::size_t>(type_size));
69 }
70 }
71
72 13 void BaranovACustomAllreduceMPI::PerformOperation(void *inbuf, void *inoutbuf, int count, MPI_Datatype datatype,
73 MPI_Op op) {
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (op != MPI_SUM) {
75 throw std::runtime_error("Only MPI_SUM operation is supported");
76 }
77
78
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
13 if (datatype == MPI_INT) {
79 auto *in = static_cast<int *>(inbuf);
80 auto *inout = static_cast<int *>(inoutbuf);
81
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (int i = 0; i < count; i++) {
82 4 inout[i] += in[i];
83 }
84
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 } else if (datatype == MPI_FLOAT) {
85 auto *in = static_cast<float *>(inbuf);
86 auto *inout = static_cast<float *>(inoutbuf);
87
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 for (int i = 0; i < count; i++) {
88 3 inout[i] += in[i];
89 }
90
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 } else if (datatype == MPI_DOUBLE) {
91 auto *in = static_cast<double *>(inbuf);
92 auto *inout = static_cast<double *>(inoutbuf);
93
2/2
✓ Branch 0 taken 1037 times.
✓ Branch 1 taken 11 times.
1048 for (int i = 0; i < count; i++) {
94 1037 inout[i] += in[i];
95 }
96 } else {
97 throw std::runtime_error("Unsupported datatype");
98 }
99 13 }
100
101 namespace {
102 13 void ProcessRootReceive(std::vector<unsigned char> &temp_buf, int count, MPI_Datatype datatype, MPI_Op op,
103 MPI_Comm comm, int root, int size, int type_size) {
104
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 13 times.
39 for (int i = 0; i < size; i++) {
105
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
26 if (i != root) {
106
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 std::vector<unsigned char> recv_buf(static_cast<std::size_t>(count) * static_cast<std::size_t>(type_size));
107
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (recv_buf.empty()) {
108 throw std::runtime_error("Memory allocation failed");
109 }
110
111
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 MPI_Recv(recv_buf.data(), count, datatype, i, 0, comm, MPI_STATUS_IGNORE);
112
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 BaranovACustomAllreduceMPI::PerformOperation(recv_buf.data(), temp_buf.data(), count, datatype, op);
113 }
114 }
115 13 }
116
117 13 void ProcessRootSend(std::vector<unsigned char> &temp_buf, void *recvbuf, int count, MPI_Datatype datatype,
118 MPI_Comm comm, int root, int size, int type_size) {
119
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 13 times.
39 for (int i = 0; i < size; i++) {
120
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
26 if (i != root) {
121 13 MPI_Send(temp_buf.data(), count, datatype, i, 1, comm);
122 }
123 }
124 13 std::memcpy(recvbuf, temp_buf.data(), static_cast<std::size_t>(count) * static_cast<std::size_t>(type_size));
125 13 }
126
127 } // namespace
128
129 26 void BaranovACustomAllreduceMPI::CustomAllreduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype,
130 MPI_Op op, MPI_Comm comm, int root) {
131 26 int rank = 0;
132 26 int size = 0;
133 26 MPI_Comm_rank(comm, &rank);
134 26 MPI_Comm_size(comm, &size);
135
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (count == 0) {
137 return;
138 }
139
140 26 int type_size = 0;
141 26 MPI_Type_size(datatype, &type_size);
142
143
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 std::vector<unsigned char> temp_buf(static_cast<std::size_t>(count) * static_cast<std::size_t>(type_size));
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (temp_buf.empty()) {
145 throw std::runtime_error("Memory allocation failed");
146 }
147
148
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
26 std::memcpy(temp_buf.data(), sendbuf, static_cast<std::size_t>(count) * static_cast<std::size_t>(type_size));
149
150
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 13 times.
26 if (rank == root) {
151
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 ProcessRootReceive(temp_buf, count, datatype, op, comm, root, size, type_size);
152
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 ProcessRootSend(temp_buf, recvbuf, count, datatype, comm, root, size, type_size);
153 } else {
154
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 MPI_Send(sendbuf, count, datatype, root, 0, comm);
155
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 MPI_Recv(recvbuf, count, datatype, root, 1, comm, MPI_STATUS_IGNORE);
156 }
157 }
158
159 template <typename T>
160 std::vector<T> BaranovACustomAllreduceMPI::GetVectorFromVariant(const InTypeVariant &variant) {
161 try {
162 return std::get<std::vector<T>>(variant);
163 } catch (const std::bad_variant_access &) {
164 throw std::runtime_error("Wrong variant type accessed");
165 }
166 }
167
168 template std::vector<double> BaranovACustomAllreduceMPI::GetVectorFromVariant<double>(const InTypeVariant &variant);
169
170
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 BaranovACustomAllreduceMPI::BaranovACustomAllreduceMPI(const InType &in) {
171 SetTypeOfTask(GetStaticTypeOfTask());
172 GetInput() = in;
173
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 26 times.
28 if (std::holds_alternative<std::vector<int>>(in)) {
174
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 auto vec = std::get<std::vector<int>>(in);
175
2/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
4 GetOutput() = InTypeVariant{std::vector<int>(vec.size(), 0)};
176
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
26 } else if (std::holds_alternative<std::vector<float>>(in)) {
177
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 auto vec = std::get<std::vector<float>>(in);
178
2/6
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
4 GetOutput() = InTypeVariant{std::vector<float>(vec.size(), 0.0F)};
179 } else {
180
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 auto vec = std::get<std::vector<double>>(in);
181
3/6
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
48 GetOutput() = InTypeVariant{std::vector<double>(vec.size(), 0.0)};
182 }
183 28 }
184
185 28 bool BaranovACustomAllreduceMPI::ValidationImpl() {
186 28 return true;
187 }
188
189 28 bool BaranovACustomAllreduceMPI::PreProcessingImpl() {
190 28 return true;
191 }
192
193
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 bool BaranovACustomAllreduceMPI::RunImpl() {
194 try {
195 auto input = GetInput();
196 auto output = GetOutput();
197
198
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 26 times.
28 if (std::holds_alternative<std::vector<int>>(input)) {
199
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 auto data = std::get<std::vector<int>>(input);
200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (data.empty()) {
201 GetOutput() = InTypeVariant{std::vector<int>{}};
202 return true;
203 }
204
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 auto result_data = std::get<std::vector<int>>(output);
205
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CustomAllreduce(data.data(), result_data.data(), static_cast<int>(data.size()), MPI_INT, MPI_SUM, MPI_COMM_WORLD,
206 0);
207
208
1/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 GetOutput() = InTypeVariant{result_data};
209
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
26 } else if (std::holds_alternative<std::vector<float>>(input)) {
210
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 auto data = std::get<std::vector<float>>(input);
211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (data.empty()) {
212 GetOutput() = InTypeVariant{std::vector<float>{}};
213 return true;
214 }
215
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 auto result_data = std::get<std::vector<float>>(output);
216
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 CustomAllreduce(data.data(), result_data.data(), static_cast<int>(data.size()), MPI_FLOAT, MPI_SUM,
217 MPI_COMM_WORLD, 0);
218
1/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 GetOutput() = InTypeVariant{result_data};
219
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 } else if (std::holds_alternative<std::vector<double>>(input)) {
220
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 auto data = std::get<std::vector<double>>(input);
221
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 22 times.
24 if (data.empty()) {
222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GetOutput() = InTypeVariant{std::vector<double>{}};
223 return true;
224 }
225
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 auto result_data = std::get<std::vector<double>>(output);
226
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 CustomAllreduce(data.data(), result_data.data(), static_cast<int>(data.size()), MPI_DOUBLE, MPI_SUM,
227 MPI_COMM_WORLD, 0);
228
1/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
22 GetOutput() = InTypeVariant{result_data};
229 }
230 return true;
231 } catch (const std::exception &) {
232 return false;
233 }
234 }
235
236 28 bool BaranovACustomAllreduceMPI::PostProcessingImpl() {
237 28 return true;
238 }
239
240 } // namespace baranov_a_custom_allreduce
241