GCC Code Coverage Report


Directory: ./
File: tasks/balchunayte_z_reduce/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 84 88 95.5%
Functions: 6 8 75.0%
Branches: 53 80 66.2%

Line Branch Exec Source
1 #include "balchunayte_z_reduce/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <vector>
7
8 namespace balchunayte_z_reduce {
9
10 namespace {
11
12 // Универсальное дерево-суммирование для типа T
13 template <typename T>
14 16 void TreeReduceSum(const T *send_buffer, T *recv_buffer, int count, int rank, int size, int root, MPI_Comm comm,
15 MPI_Datatype mpi_type) {
16 const int message_tag = 0;
17 16 MPI_Status status{};
18 16 const int virtual_rank = (rank - root + size) % size;
19
20 16 std::vector<T> accumulator(count);
21 16 std::copy(send_buffer, send_buffer + count, accumulator.begin());
22
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
16 std::vector<T> temp(count);
23
24
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
24 for (int step_size = 1; step_size < size; step_size *= 2) {
25
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
16 if (virtual_rank % (2 * step_size) == 0) {
26 8 const int source_virtual_rank = virtual_rank + step_size;
27
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 if (source_virtual_rank < size) {
28
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 const int source_rank = (source_virtual_rank + root) % size;
29
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 MPI_Recv(temp.data(), count, mpi_type, source_rank, message_tag, comm, &status);
30
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
16 for (int index = 0; index < count; ++index) {
31 8 accumulator[index] += temp[index];
32 }
33 }
34
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 } else if (virtual_rank % step_size == 0) {
35 8 const int target_virtual_rank = virtual_rank - step_size;
36 8 const int target_rank = (target_virtual_rank + root) % size;
37
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 MPI_Send(accumulator.data(), count, mpi_type, target_rank, message_tag, comm);
38 return;
39 }
40 }
41
42
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 if ((rank == root) && (recv_buffer != nullptr)) {
43 std::ranges::copy(accumulator, recv_buffer);
44 }
45 }
46
47 // Обёртка с нужной сигнатурой (как у MPI_Reduce, но только SUM + int/float/double)
48 8 int BalchunayteZReduce(const void *send_buffer, void *recv_buffer, int count, MPI_Datatype datatype, MPI_Op op,
49 int root, MPI_Comm comm) {
50
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (count < 0) {
51 return MPI_ERR_COUNT;
52 }
53
54 8 int rank = 0;
55 8 int size = 0;
56 8 MPI_Comm_rank(comm, &rank);
57 8 MPI_Comm_size(comm, &size);
58
59
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (size <= 0) {
60 return MPI_ERR_COMM;
61 }
62
63
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (op != MPI_SUM) {
64 return MPI_ERR_OP;
65 }
66
67
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (count == 0) {
68 return MPI_SUCCESS;
69 }
70
71
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (datatype == MPI_INT) {
72 const auto *typed_send_buffer = static_cast<const int *>(send_buffer);
73 auto *typed_recv_buffer = static_cast<int *>(recv_buffer);
74 TreeReduceSum(typed_send_buffer, typed_recv_buffer, count, rank, size, root, comm, MPI_INT);
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 } else if (datatype == MPI_FLOAT) {
76 const auto *typed_send_buffer = static_cast<const float *>(send_buffer);
77 auto *typed_recv_buffer = static_cast<float *>(recv_buffer);
78 TreeReduceSum(typed_send_buffer, typed_recv_buffer, count, rank, size, root, comm, MPI_FLOAT);
79
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 } else if (datatype == MPI_DOUBLE) {
80 const auto *typed_send_buffer = static_cast<const double *>(send_buffer);
81 auto *typed_recv_buffer = static_cast<double *>(recv_buffer);
82 8 TreeReduceSum(typed_send_buffer, typed_recv_buffer, count, rank, size, root, comm, MPI_DOUBLE);
83 } else {
84 return MPI_ERR_TYPE;
85 }
86
87 return MPI_SUCCESS;
88 }
89
90 } // namespace
91
92 8 bool BalchunayteZReduceMPI::ValidationImpl() {
93 8 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank_);
94 8 MPI_Comm_size(MPI_COMM_WORLD, &world_size_);
95
96 8 int valid_flag = 1;
97
98
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (world_rank_ == 0) {
99 const auto &input = GetInput();
100
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (input.data.empty()) {
102 valid_flag = 0;
103 }
104
105
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if ((input.root < 0) || (input.root >= world_size_)) {
106 valid_flag = 0;
107 }
108 }
109
110 8 MPI_Bcast(&valid_flag, 1, MPI_INT, 0, MPI_COMM_WORLD);
111 8 return valid_flag == 1;
112 }
113
114 8 bool BalchunayteZReduceMPI::PreProcessingImpl() {
115 8 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank_);
116 8 MPI_Comm_size(MPI_COMM_WORLD, &world_size_);
117
118
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (world_rank_ == 0) {
119 4 root_ = GetInput().root;
120 }
121 8 MPI_Bcast(&root_, 1, MPI_INT, 0, MPI_COMM_WORLD);
122
123 8 int global_size = 0;
124
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (world_rank_ == 0) {
125 4 global_size = static_cast<int>(GetInput().data.size());
126 }
127 8 MPI_Bcast(&global_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
128
129 8 std::vector<int> counts(world_size_, 0);
130
1/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
8 std::vector<int> displacements(world_size_, 0);
131
132 8 const int base_size = global_size / world_size_;
133 8 const int remainder = global_size % world_size_;
134
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
24 for (int rank_index = 0; rank_index < world_size_; ++rank_index) {
135
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2 times.
30 counts[rank_index] = base_size + ((rank_index < remainder) ? 1 : 0);
136 }
137
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 for (int rank_index = 1; rank_index < world_size_; ++rank_index) {
138 8 displacements[rank_index] = displacements[rank_index - 1] + counts[rank_index - 1];
139 }
140
141
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 local_size_ = counts[world_rank_];
142
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 local_data_.resize(local_size_);
143
144 const double *send_data = nullptr;
145
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (world_rank_ == 0) {
146 send_data = GetInput().data.data();
147 }
148
149
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Scatterv(send_data, counts.data(), displacements.data(), MPI_DOUBLE, local_data_.data(), local_size_, MPI_DOUBLE,
150 0, MPI_COMM_WORLD);
151
152 8 local_sum_ = 0.0;
153
2/2
✓ Branch 0 taken 1009 times.
✓ Branch 1 taken 8 times.
1017 for (int index = 0; index < local_size_; ++index) {
154 1009 local_sum_ += local_data_[index];
155 }
156
157
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 GetOutput() = 0.0;
158 8 return true;
159 }
160
161 8 bool BalchunayteZReduceMPI::RunImpl() {
162 8 double global_sum = 0.0;
163
164
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
12 const int reduce_status = BalchunayteZReduce(&local_sum_, (world_rank_ == root_) ? &global_sum : nullptr, 1,
165 MPI_DOUBLE, MPI_SUM, root_, MPI_COMM_WORLD);
166
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (reduce_status != MPI_SUCCESS) {
167 return false;
168 }
169
170 const int message_tag = 1;
171
172
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (world_rank_ == root_) {
173 4 GetOutput() = global_sum;
174
175
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (int rank_index = 0; rank_index < world_size_; ++rank_index) {
176
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (rank_index == root_) {
177 4 continue;
178 }
179 4 MPI_Send(&global_sum, 1, MPI_DOUBLE, rank_index, message_tag, MPI_COMM_WORLD);
180 }
181 } else {
182 4 double received_value = 0.0;
183 4 MPI_Status status{};
184 4 MPI_Recv(&received_value, 1, MPI_DOUBLE, root_, message_tag, MPI_COMM_WORLD, &status);
185 4 GetOutput() = received_value;
186 }
187
188 return true;
189 }
190
191 8 bool BalchunayteZReduceMPI::PostProcessingImpl() {
192 8 return true;
193 }
194
195 } // namespace balchunayte_z_reduce
196