GCC Code Coverage Report


Directory: ./
File: tasks/krykov_e_multistep_sad/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 87 90 96.7%
Functions: 9 9 100.0%
Branches: 63 96 65.6%

Line Branch Exec Source
1 #include "krykov_e_multistep_sad/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cmath>
7 #include <limits>
8 #include <vector>
9
10 #include "krykov_e_multistep_sad/common/include/common.hpp"
11
12 namespace krykov_e_multistep_sad {
13
14 namespace {
15
16 constexpr double kEps = 1e-4;
17 constexpr int kMaxIter = 1000;
18
19 4941 double EvaluateCenter(const Function2D &f, Region &r) {
20 4941 const double xc = 0.5 * (r.x_min + r.x_max);
21
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4941 times.
4941 const double yc = 0.5 * (r.y_min + r.y_max);
22 4941 r.value = f(xc, yc);
23 4941 return r.value;
24 }
25
26 int ComputeStartIndex(int rank, int per_proc, int remainder) {
27 538 return (rank * per_proc) + std::min(rank, remainder);
28 }
29
30 int ComputeEndIndex(int start, int per_proc, int rank, int remainder) {
31
2/2
✓ Branch 0 taken 402 times.
✓ Branch 1 taken 136 times.
538 return start + per_proc + ((rank < remainder) ? 1 : 0);
32 }
33
34 Region SplitXLeft(const Region &r, double xm) {
35 128 return Region{.x_min = r.x_min, .x_max = xm, .y_min = r.y_min, .y_max = r.y_max, .value = 0.0};
36 }
37
38 Region SplitXRight(const Region &r, double xm) {
39 128 return Region{.x_min = xm, .x_max = r.x_max, .y_min = r.y_min, .y_max = r.y_max, .value = 0.0};
40 }
41
42 Region SplitYBottom(const Region &r, double ym) {
43 133 return Region{.x_min = r.x_min, .x_max = r.x_max, .y_min = r.y_min, .y_max = ym, .value = 0.0};
44 }
45
46 Region SplitYTop(const Region &r, double ym) {
47 133 return Region{.x_min = r.x_min, .x_max = r.x_max, .y_min = ym, .y_max = r.y_max, .value = 0.0};
48 }
49
50 538 Region FindLocalBest(const Function2D &f, std::vector<Region> &regions, int begin, int end) {
51 538 Region best{.x_min = 0.0, .x_max = 0.0, .y_min = 0.0, .y_max = 0.0, .value = std::numeric_limits<double>::max()};
52
53
2/2
✓ Branch 0 taken 4664 times.
✓ Branch 1 taken 538 times.
5202 for (int i = begin; i < end; ++i) {
54 4664 EvaluateCenter(f, regions[i]);
55
2/2
✓ Branch 0 taken 3210 times.
✓ Branch 1 taken 1454 times.
4664 if (regions[i].value < best.value) {
56 3210 best = regions[i];
57 }
58 }
59
60 538 return best;
61 }
62
63 bool IsRegionSmallEnough(const Region &r) {
64 269 return std::max(r.x_max - r.x_min, r.y_max - r.y_min) < kEps;
65 }
66
67 261 void ReplaceWithSplit(std::vector<Region> &regions, const Region &best) {
68 261 const double dx = best.x_max - best.x_min;
69 261 const double dy = best.y_max - best.y_min;
70
71 261 auto it = std::ranges::remove_if(regions, [&](const Region &r) {
72
11/16
✓ Branch 0 taken 405 times.
✓ Branch 1 taken 3897 times.
✓ Branch 2 taken 338 times.
✓ Branch 3 taken 67 times.
✓ Branch 4 taken 261 times.
✓ Branch 5 taken 77 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 261 times.
✓ Branch 8 taken 43 times.
✓ Branch 9 taken 50 times.
✓ Branch 10 taken 43 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 43 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
4395 return r.x_min == best.x_min && r.x_max == best.x_max && r.y_min == best.y_min && r.y_max == best.y_max;
73 });
74 regions.erase(it.begin(), it.end());
75
76
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 133 times.
261 if (dx >= dy) {
77 128 const double xm = 0.5 * (best.x_min + best.x_max);
78 128 regions.push_back(SplitXLeft(best, xm));
79 128 regions.push_back(SplitXRight(best, xm));
80 } else {
81 133 const double ym = 0.5 * (best.y_min + best.y_max);
82 133 regions.push_back(SplitYBottom(best, ym));
83 133 regions.push_back(SplitYTop(best, ym));
84 }
85 261 }
86
87 8 Region FinalBestRegion(const Function2D &f, std::vector<Region> &regions) {
88
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 8 times.
277 for (auto &r : regions) {
89 269 EvaluateCenter(f, r);
90 }
91 8 return *std::ranges::min_element(regions, {}, &Region::value);
92 }
93
94 } // namespace
95
96
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 KrykovEMultistepSADMPI::KrykovEMultistepSADMPI(const InType &in) {
97 SetTypeOfTask(GetStaticTypeOfTask());
98 GetInput() = in;
99 16 }
100
101
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 bool KrykovEMultistepSADMPI::ValidationImpl() {
102 const auto &[f, x1, x2, y1, y2] = GetInput();
103
3/6
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
16 return static_cast<bool>(f) && (x1 < x2) && (y1 < y2);
104 }
105
106 16 bool KrykovEMultistepSADMPI::PreProcessingImpl() {
107 16 return true;
108 }
109
110 16 bool KrykovEMultistepSADMPI::RunImpl() {
111 16 int size = 0;
112 16 int rank = 0;
113 16 MPI_Comm_size(MPI_COMM_WORLD, &size);
114 16 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
115
116 const auto &[f, x_min, x_max, y_min, y_max] = GetInput();
117
118 16 std::vector<Region> regions;
119
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (rank == 0) {
120
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 regions.push_back(Region{.x_min = x_min, .x_max = x_max, .y_min = y_min, .y_max = y_max, .value = 0.0});
121
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 EvaluateCenter(f, regions.front());
122 }
123
124 16 int stop_flag = 0;
125
126
3/4
✓ Branch 0 taken 554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 538 times.
✓ Branch 3 taken 16 times.
554 for (int iter = 0; (iter < kMaxIter) && (stop_flag == 0); ++iter) {
127
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 269 times.
538 int n_regions = (rank == 0) ? static_cast<int>(regions.size()) : 0;
128
1/2
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
538 MPI_Bcast(&n_regions, 1, MPI_INT, 0, MPI_COMM_WORLD);
129
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 538 times.
538 if (n_regions == 0) {
131 stop_flag = 1;
132 MPI_Bcast(&stop_flag, 1, MPI_INT, 0, MPI_COMM_WORLD);
133 break;
134 }
135
136
1/2
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
538 std::vector<Region> local_regions(n_regions);
137
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 269 times.
538 if (rank == 0) {
138 std::ranges::copy(regions, local_regions.begin());
139 }
140
141
1/2
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
538 MPI_Bcast(local_regions.data(), n_regions * static_cast<int>(sizeof(Region)), MPI_BYTE, 0, MPI_COMM_WORLD);
142
143 538 const int per_proc = n_regions / size;
144 538 const int remainder = n_regions % size;
145
2/2
✓ Branch 0 taken 402 times.
✓ Branch 1 taken 136 times.
538 const int begin = ComputeStartIndex(rank, per_proc, remainder);
146 const int end = ComputeEndIndex(begin, per_proc, rank, remainder);
147
148
1/2
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
538 const Region local_best = FindLocalBest(f, local_regions, begin, end);
149
150 struct {
151 double value;
152 int rank;
153 538 } local_val{.value = local_best.value, .rank = rank}, global_val{};
154
155
1/2
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
538 MPI_Allreduce(&local_val, &global_val, 1, MPI_DOUBLE_INT, MPI_MINLOC, MPI_COMM_WORLD);
156
157 538 Region global_best = local_best;
158
1/2
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
538 MPI_Bcast(&global_best, static_cast<int>(sizeof(Region)), MPI_BYTE, global_val.rank, MPI_COMM_WORLD);
159
160
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 269 times.
538 if (rank == 0) {
161 269 stop_flag = static_cast<int>(IsRegionSmallEnough(global_best));
162
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 8 times.
269 if (stop_flag == 0) {
163
1/2
✓ Branch 1 taken 261 times.
✗ Branch 2 not taken.
261 ReplaceWithSplit(regions, global_best);
164 }
165 }
166
167
1/2
✓ Branch 1 taken 538 times.
✗ Branch 2 not taken.
538 MPI_Bcast(&stop_flag, 1, MPI_INT, 0, MPI_COMM_WORLD);
168 }
169
170 16 double x = 0.0;
171 16 double y = 0.0;
172 16 double value = 0.0;
173
174
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (rank == 0) {
175
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 const Region best = FinalBestRegion(f, regions);
176 8 x = 0.5 * (best.x_min + best.x_max);
177 8 y = 0.5 * (best.y_min + best.y_max);
178 8 value = best.value;
179 }
180
181
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 MPI_Bcast(&x, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
182
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 MPI_Bcast(&y, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
183
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 MPI_Bcast(&value, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD);
184
185
3/6
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
32 GetOutput() = {x, y, value};
186 16 return true;
187 }
188
189 16 bool KrykovEMultistepSADMPI::PostProcessingImpl() {
190 16 return true;
191 }
192
193 } // namespace krykov_e_multistep_sad
194