GCC Code Coverage Report


Directory: ./
File: tasks/alekseev_a_custom_reduce/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 76 80 95.0%
Functions: 6 8 75.0%
Branches: 53 82 64.6%

Line Branch Exec Source
1 #include "alekseev_a_custom_reduce/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cmath>
7 #include <vector>
8
9 namespace alekseev_a_custom_reduce {
10
11 namespace {
12
13 template <typename T>
14 92 void ReduceTree(const T *send_data, T *recv_data, int count, int rank, int size, int root, MPI_Comm comm,
15 MPI_Datatype mpi_type) {
16 constexpr int kMessageTag = 0;
17 92 const int virtual_rank = (rank - root + size) % size;
18
19 92 std::vector<T> accumulator(send_data, send_data + count);
20
1/4
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
92 std::vector<T> buffer(count);
21 MPI_Status status;
22
23
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 23 times.
138 for (int step = 1; step < size; step <<= 1) {
24
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
92 if ((virtual_rank & step) == 0) {
25 46 const int source_virtual = virtual_rank + step;
26
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
46 if (source_virtual < size) {
27
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 const int source_rank = (source_virtual + root) % size;
28
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 MPI_Recv(buffer.data(), count, mpi_type, source_rank, kMessageTag, comm, &status);
29
30
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
92 for (int i = 0; i < count; ++i) {
31 46 accumulator[i] += buffer[i];
32 }
33 }
34 } else {
35 46 const int dest_virtual = virtual_rank - step;
36
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 const int dest_rank = (dest_virtual + root) % size;
37
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 MPI_Send(accumulator.data(), count, mpi_type, dest_rank, kMessageTag, comm);
38 return;
39 }
40 }
41
42
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
46 if (rank == root && recv_data != nullptr) {
43 46 std::copy(accumulator.begin(), accumulator.end(), recv_data);
44 }
45 }
46
47 46 int CustomReduceImpl(const void *send_data, void *recv_data, int count, MPI_Datatype datatype, MPI_Op op, int root,
48 MPI_Comm comm) {
49
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (count < 0) {
50 return MPI_ERR_COUNT;
51 }
52
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (op != MPI_SUM) {
53 return MPI_ERR_OP;
54 }
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (count == 0) {
56 return MPI_SUCCESS;
57 }
58
59 46 int rank = 0;
60 46 int size = 0;
61 46 MPI_Comm_rank(comm, &rank);
62 46 MPI_Comm_size(comm, &size);
63
64
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (size <= 0) {
65 return MPI_ERR_COMM;
66 }
67
2/4
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
46 if (root < 0 || root >= size) {
68 return MPI_ERR_ROOT;
69 }
70
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (datatype == MPI_INT) {
72 ReduceTree(static_cast<const int *>(send_data), static_cast<int *>(recv_data), count, rank, size, root, comm,
73 MPI_INT);
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 } else if (datatype == MPI_FLOAT) {
75 ReduceTree(static_cast<const float *>(send_data), static_cast<float *>(recv_data), count, rank, size, root, comm,
76 MPI_FLOAT);
77
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 } else if (datatype == MPI_DOUBLE) {
78 46 ReduceTree(static_cast<const double *>(send_data), static_cast<double *>(recv_data), count, rank, size, root, comm,
79 MPI_DOUBLE);
80 } else {
81 return MPI_ERR_TYPE;
82 }
83
84 return MPI_SUCCESS;
85 }
86
87 } // namespace
88
89 46 bool AlekseevACustomReduceMPI::ValidationImpl() {
90 46 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank_);
91 46 MPI_Comm_size(MPI_COMM_WORLD, &world_size_);
92
93 46 int validation_flag = 1;
94
95
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 if (world_rank_ == 0) {
96 const auto &input = GetInput();
97
98
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (input.data.empty()) {
99 validation_flag = 0;
100 }
101
102
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
23 if (input.root < 0 || input.root >= world_size_) {
103 validation_flag = 0;
104 }
105 }
106
107 46 MPI_Bcast(&validation_flag, 1, MPI_INT, 0, MPI_COMM_WORLD);
108 46 return validation_flag == 1;
109 }
110
111 46 bool AlekseevACustomReduceMPI::PreProcessingImpl() {
112 46 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank_);
113 46 MPI_Comm_size(MPI_COMM_WORLD, &world_size_);
114
115
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 if (world_rank_ == 0) {
116 23 root_ = GetInput().root;
117 }
118 46 MPI_Bcast(&root_, 1, MPI_INT, 0, MPI_COMM_WORLD);
119
120 46 int global_size = 0;
121
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 if (world_rank_ == 0) {
122 23 global_size = static_cast<int>(GetInput().data.size());
123 }
124 46 MPI_Bcast(&global_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
125
126 46 std::vector<int> counts(world_size_);
127
1/4
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
46 std::vector<int> displacements(world_size_, 0);
128
129 46 const int base_chunk = global_size / world_size_;
130 46 const int remainder = global_size % world_size_;
131
132
2/2
✓ Branch 0 taken 92 times.
✓ Branch 1 taken 46 times.
138 for (int i = 0; i < world_size_; ++i) {
133
4/4
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 22 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 46 times.
162 counts[i] = base_chunk + (i < remainder ? 1 : 0);
134
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 46 times.
92 if (i > 0) {
135 46 displacements[i] = displacements[i - 1] + counts[i - 1];
136 }
137 }
138
139
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 local_size_ = counts[world_rank_];
140
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 local_data_.resize(local_size_);
141
142
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 const double *global_data = world_rank_ == 0 ? GetInput().data.data() : nullptr;
143
144
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
46 MPI_Scatterv(global_data, counts.data(), displacements.data(), MPI_DOUBLE, local_data_.data(), local_size_,
145 MPI_DOUBLE, 0, MPI_COMM_WORLD);
146
147 46 local_sum_ = 0.0;
148
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 46 times.
185 for (double value : local_data_) {
149 139 local_sum_ += value;
150 }
151
152
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 GetOutput() = 0.0;
153
154 46 return true;
155 }
156
157 46 bool AlekseevACustomReduceMPI::RunImpl() {
158 46 double global_sum = 0.0;
159
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 double *recv_buffer = world_rank_ == root_ ? &global_sum : nullptr;
160
161 46 const int reduce_result = CustomReduceImpl(&local_sum_, recv_buffer, 1, MPI_DOUBLE, MPI_SUM, root_, MPI_COMM_WORLD);
162
163
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 if (reduce_result != MPI_SUCCESS) {
164 return false;
165 }
166
167
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 23 times.
46 if (world_rank_ == root_) {
168 23 GetOutput() = global_sum;
169 }
170
171 return true;
172 }
173
174 46 bool AlekseevACustomReduceMPI::PostProcessingImpl() {
175 46 return true;
176 }
177
178 } // namespace alekseev_a_custom_reduce
179