GCC Code Coverage Report


Directory: ./
File: tasks/leonova_a_most_diff_neigh_vec_elems/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 95 95 100.0%
Functions: 11 11 100.0%
Branches: 56 82 68.3%

Line Branch Exec Source
1 #include "leonova_a_most_diff_neigh_vec_elems/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <array>
7 #include <cmath>
8 #include <cstdint>
9 #include <cstdlib>
10 #include <limits>
11 #include <tuple>
12 #include <vector>
13
14 #include "leonova_a_most_diff_neigh_vec_elems/common/include/common.hpp"
15
16 namespace leonova_a_most_diff_neigh_vec_elems {
17
18
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 LeonovaAMostDiffNeighVecElemsMPI::LeonovaAMostDiffNeighVecElemsMPI(const InType &in) {
19 SetTypeOfTask(GetStaticTypeOfTask());
20
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 GetInput() = in;
21 GetOutput() = std::tuple<int, int>(0, 0);
22 14 }
23
24 28 bool LeonovaAMostDiffNeighVecElemsMPI::ValidationImpl() {
25 28 int rank = 0;
26 28 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
27
28 28 bool is_valid = false;
29
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 if (rank == 0) {
30 14 is_valid = !GetInput().empty();
31 }
32
33 28 MPI_Bcast(&is_valid, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD);
34 28 return is_valid;
35 }
36
37 14 bool LeonovaAMostDiffNeighVecElemsMPI::PreProcessingImpl() {
38 14 return true;
39 }
40
41 14 bool LeonovaAMostDiffNeighVecElemsMPI::RunImpl() {
42 const auto &input_vec = GetInput();
43
44
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 if (!ValidationImpl()) {
45 return false;
46 }
47
48 14 int rank = 0;
49 14 int size = 0;
50 14 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
51 14 MPI_Comm_size(MPI_COMM_WORLD, &size);
52
53 14 int total_size = static_cast<int>(input_vec.size());
54 14 ProcessWithMultipleProcesses(rank, size, total_size, input_vec);
55 return true;
56 }
57
58
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 void LeonovaAMostDiffNeighVecElemsMPI::ProcessWithMultipleProcesses(int rank, int size, int total_size,
59 const std::vector<int> &input_vec) {
60 int actual_processes = std::min(size, total_size);
61 14 int local_max_diff = -1;
62 14 int local_first = 0;
63 14 int local_second = 0;
64
65
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 if (rank < actual_processes) {
66 13 ProcessLocalData(rank, actual_processes, total_size, input_vec, local_max_diff, local_first, local_second, size);
67 }
68
69 14 GatherAndProcessResults(rank, actual_processes, local_max_diff, local_first, local_second, size);
70 14 }
71
72 13 void LeonovaAMostDiffNeighVecElemsMPI::ProcessLocalData(int rank, int actual_processes, int total_size,
73 const std::vector<int> &input_vec, int &local_max_diff,
74 int &local_first, int &local_second, int size) {
75 13 int chunk_size = total_size / actual_processes;
76 13 int remainder = total_size % actual_processes;
77
78 13 std::vector<int> sizes(actual_processes);
79
1/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
13 std::vector<int> offsets(actual_processes);
80
81 int offset = 0;
82
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 13 times.
38 for (int i = 0; i < actual_processes; ++i) {
83
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 4 times.
46 sizes[i] = chunk_size + (i < remainder ? 1 : 0) + 1;
84 25 offsets[i] = offset;
85 25 offset += sizes[i] - 1;
86 }
87
88
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (actual_processes > 0) {
89 13 sizes[actual_processes - 1] = total_size - offsets[actual_processes - 1];
90 }
91
92
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 int my_size = (rank < actual_processes) ? sizes[rank] : 0;
93
94
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (my_size > 0) {
95
1/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
13 std::vector<int> local_data(my_size);
96
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 ReceiveLocalData(rank, actual_processes, input_vec, sizes, offsets, local_data, size);
97 13 FindLocalMaxDiff(local_data, local_max_diff, local_first, local_second);
98 }
99 13 }
100
101 13 void LeonovaAMostDiffNeighVecElemsMPI::ReceiveLocalData(int rank, int actual_processes,
102 const std::vector<int> &input_vec,
103 const std::vector<int> &sizes, const std::vector<int> &offsets,
104 std::vector<int> &local_data, int size) {
105 13 std::vector<int> send_counts(size, 0);
106
1/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
13 std::vector<int> displacements(size, 0);
107
1/4
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
13 std::vector<int> recv_counts(size, 0);
108
109
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 13 times.
38 for (int i = 0; i < actual_processes; ++i) {
110 25 send_counts[i] = sizes[i];
111 25 displacements[i] = offsets[i];
112 25 recv_counts[i] = sizes[i];
113 }
114
115
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (rank == 0) {
116
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (!local_data.empty()) {
117 7 std::copy(input_vec.begin() + offsets[0], input_vec.begin() + offsets[0] + sizes[0], local_data.begin());
118 }
119 }
120
121
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 int recv_count = static_cast<int>(local_data.size());
122
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
20 MPI_Scatterv((rank == 0) ? input_vec.data() : nullptr, send_counts.data(), displacements.data(), MPI_INT,
123 local_data.data(), recv_count, MPI_INT, 0, MPI_COMM_WORLD);
124 13 }
125
126
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
13 void LeonovaAMostDiffNeighVecElemsMPI::FindLocalMaxDiff(const std::vector<int> &local_data, int &local_max_diff,
127 int &local_first, int &local_second) {
128
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
13 if (local_data.size() == 1) {
129 2 local_max_diff = 0;
130 2 local_first = local_data[0];
131 2 local_second = local_data[0];
132 2 return;
133 }
134
135
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 11 times.
31 for (int index = 0; index < static_cast<int>(local_data.size()) - 1; ++index) {
136
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
20 int64_t diff = static_cast<int64_t>(local_data[index]) - static_cast<int64_t>(local_data[index + 1]);
137 20 int64_t curr_diff_ll = std::llabs(diff); // safe abs
138
139 int curr_diff = (curr_diff_ll <= static_cast<int64_t>(std::numeric_limits<int>::max()))
140 20 ? static_cast<int>(curr_diff_ll)
141 : std::numeric_limits<int>::max();
142
143
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8 times.
20 if (curr_diff > local_max_diff) {
144 12 local_max_diff = curr_diff;
145 12 local_first = local_data[index];
146 12 local_second = local_data[index + 1];
147 }
148 }
149 }
150
151 14 void LeonovaAMostDiffNeighVecElemsMPI::GatherAndProcessResults(int rank, int actual_processes, int local_max_diff,
152 int local_first, int local_second, int size) {
153 struct ProcessResult {
154 int diff;
155 int first;
156 int second;
157 };
158
159 14 ProcessResult local_result{.diff = local_max_diff, .first = local_first, .second = local_second};
160
1/2
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 std::vector<ProcessResult> all_results(size);
161
162
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Gather(&local_result, 3, MPI_INT, all_results.data(), 3, MPI_INT, 0, MPI_COMM_WORLD);
163
164
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
165 int global_max_diff = -1;
166 int best_index = -1;
167
168
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (int index = 0; index < actual_processes; ++index) {
169
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (all_results[index].diff > global_max_diff) {
170 global_max_diff = all_results[index].diff;
171 best_index = index;
172 }
173 }
174
175
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (best_index != -1) {
176 7 GetOutput() = std::make_tuple(all_results[best_index].first, all_results[best_index].second);
177 } else {
178 GetOutput() = std::make_tuple(0, 0);
179 }
180 }
181
182
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 BroadcastResult(rank);
183 14 }
184
185 14 void LeonovaAMostDiffNeighVecElemsMPI::BroadcastResult(int rank) {
186 14 std::array<int, 2> result_data{0, 0};
187
188
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
189 7 result_data[0] = std::get<0>(GetOutput());
190 7 result_data[1] = std::get<1>(GetOutput());
191 }
192
193 14 MPI_Bcast(result_data.data(), 2, MPI_INT, 0, MPI_COMM_WORLD);
194
195
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank != 0) {
196 GetOutput() = std::make_tuple(result_data[0], result_data[1]);
197 }
198 14 }
199
200 14 bool LeonovaAMostDiffNeighVecElemsMPI::PostProcessingImpl() {
201 14 return true;
202 }
203
204 } // namespace leonova_a_most_diff_neigh_vec_elems
205