GCC Code Coverage Report


Directory: ./
File: tasks/chernov_t_convex_hull_binary_components/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 223 227 98.2%
Functions: 17 17 100.0%
Branches: 201 280 71.8%

Line Branch Exec Source
1 #include "chernov_t_convex_hull_binary_components/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <array>
7 #include <cstddef>
8 #include <cstdint>
9 #include <queue>
10 #include <utility>
11 #include <vector>
12
13 #include "chernov_t_convex_hull_binary_components/common/include/common.hpp"
14
15 namespace chernov_t_convex_hull_binary_components {
16
17
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 ChernovTConvexHullBinaryComponentsMPI::ChernovTConvexHullBinaryComponentsMPI(const InType &in) {
18 SetTypeOfTask(GetStaticTypeOfTask());
19 GetInput() = in;
20 18 GetOutput() = OutType{};
21
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Comm_rank(MPI_COMM_WORLD, &rank_);
22
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Comm_size(MPI_COMM_WORLD, &size_);
23 18 }
24
25 18 bool ChernovTConvexHullBinaryComponentsMPI::ValidationImpl() {
26
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank_ == 0) {
27 const auto &[w, h, p] = GetInput();
28
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
9 valid_ = (w > 0) && (h > 0) && (p.size() == static_cast<std::size_t>(w) * static_cast<std::size_t>(h));
29
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (valid_) {
30
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 9 times.
75 for (int px : p) {
31
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if (px != 0 && px != 1) {
32 valid_ = false;
33 break;
34 }
35 }
36 }
37 }
38 18 MPI_Bcast(&valid_, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD);
39 18 return valid_;
40 }
41
42 18 bool ChernovTConvexHullBinaryComponentsMPI::PreProcessingImpl() {
43
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (!valid_) {
44 return false;
45 }
46
47 18 std::array<int, 2> dims{0, 0};
48
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank_ == 0) {
49 9 dims[0] = std::get<0>(GetInput());
50 9 dims[1] = std::get<1>(GetInput());
51 }
52 18 MPI_Bcast(dims.data(), 2, MPI_INT, 0, MPI_COMM_WORLD);
53 18 width_ = dims[0];
54 18 height_ = dims[1];
55
56 18 int base_rows = height_ / size_;
57 18 int rem = height_ % size_;
58
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
18 start_row_ = (rank_ * base_rows) + std::min(rank_, rem);
59
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
18 end_row_ = start_row_ + base_rows + (rank_ < rem ? 1 : 0);
60 18 int local_rows = end_row_ - start_row_;
61
62
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank_ == 0) {
63 const auto &pixels = std::get<2>(GetInput());
64 9 std::vector<int> sendcounts(size_, 0);
65
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 std::vector<int> displs(size_, 0);
66 int offset = 0;
67
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 9 times.
27 for (int i = 0; i < size_; ++i) {
68
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
18 int rows_i = base_rows + (i < rem ? 1 : 0);
69 18 sendcounts[i] = rows_i * width_;
70 18 displs[i] = offset;
71 18 offset += sendcounts[i];
72 }
73
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 local_pixels_.resize(static_cast<std::size_t>(local_rows) * static_cast<std::size_t>(width_));
74
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 MPI_Scatterv(pixels.data(), sendcounts.data(), displs.data(), MPI_INT, local_pixels_.data(),
75 static_cast<int>(local_pixels_.size()), MPI_INT, 0, MPI_COMM_WORLD);
76 } else {
77 9 local_pixels_.resize(static_cast<std::size_t>(local_rows) * static_cast<std::size_t>(width_));
78 9 MPI_Scatterv(nullptr, nullptr, nullptr, MPI_INT, local_pixels_.data(), static_cast<int>(local_pixels_.size()),
79 MPI_INT, 0, MPI_COMM_WORLD);
80 }
81 return true;
82 }
83
84 18 void ChernovTConvexHullBinaryComponentsMPI::FindConnectedComponentsMpi() {
85 18 int local_rows = end_row_ - start_row_;
86
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
18 if (local_rows == 0) {
87 3 return;
88 }
89
90 15 bool has_top = (start_row_ > 0);
91 15 bool has_bottom = (end_row_ < height_);
92
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6 times.
24 int extended_rows = local_rows + (has_top ? 1 : 0) + (has_bottom ? 1 : 0);
93 15 std::vector<int> extended_pixels(static_cast<std::size_t>(extended_rows) * static_cast<std::size_t>(width_), 0);
94
95 int offset = has_top ? 1 : 0;
96
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 15 times.
34 for (int local_row = 0; local_row < local_rows; ++local_row) {
97 19 std::size_t src = static_cast<std::size_t>(local_row) * static_cast<std::size_t>(width_);
98
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 std::size_t dst = static_cast<std::size_t>(offset + local_row) * static_cast<std::size_t>(width_);
99 std::ranges::copy(local_pixels_.begin() + static_cast<std::ptrdiff_t>(src),
100
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 local_pixels_.begin() + static_cast<std::ptrdiff_t>(src + width_),
101 extended_pixels.begin() + static_cast<std::ptrdiff_t>(dst));
102 }
103
104
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 ExchangeBoundaryRows(has_top, has_bottom, extended_pixels, width_);
105
106 15 int global_y_offset = start_row_ - (has_top ? 1 : 0);
107
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 auto all_components = ProcessExtendedRegion(extended_pixels, extended_rows, width_, global_y_offset);
108
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 FilterLocalComponents(all_components);
109 15 }
110
111 15 void ChernovTConvexHullBinaryComponentsMPI::ExchangeBoundaryRows(bool has_top, bool has_bottom,
112 std::vector<int> &extended_pixels, int width) {
113 15 std::vector<MPI_Request> reqs(4, MPI_REQUEST_NULL);
114
1/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
15 std::vector<MPI_Status> statuses(4);
115 int req_count = 0;
116
117 15 std::vector<int> top_recv;
118 15 std::vector<int> bottom_recv;
119
120
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
15 if (has_top) {
121
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 top_recv.resize(width);
122
2/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
6 std::vector<int> top_send(local_pixels_.begin(), local_pixels_.begin() + width);
123
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Irecv(top_recv.data(), width, MPI_INT, rank_ - 1, 1, MPI_COMM_WORLD, &reqs[req_count]);
124
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Isend(top_send.data(), width, MPI_INT, rank_ - 1, 0, MPI_COMM_WORLD, &reqs[req_count + 1]);
125 req_count += 2;
126 }
127
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
15 if (has_bottom && rank_ + 1 < size_) {
128
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 bottom_recv.resize(width);
129
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<int> bottom_send(local_pixels_.end() - width, local_pixels_.end());
130
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Irecv(bottom_recv.data(), width, MPI_INT, rank_ + 1, 0, MPI_COMM_WORLD, &reqs[req_count]);
131
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Isend(bottom_send.data(), width, MPI_INT, rank_ + 1, 1, MPI_COMM_WORLD, &reqs[req_count + 1]);
132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 req_count += 2;
133 }
134
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
15 if (req_count > 0) {
135
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Waitall(req_count, reqs.data(), statuses.data());
136 }
137
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
15 if (has_top) {
138 std::ranges::copy(top_recv, extended_pixels.begin());
139 }
140
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
15 if (has_bottom && rank_ + 1 < size_) {
141 std::ranges::copy(bottom_recv, extended_pixels.end() - width);
142 }
143 15 }
144
145 30 std::vector<std::pair<int, int>> ChernovTConvexHullBinaryComponentsMPI::ExtractComponent(
146 int start_col, int start_ey, const std::vector<int> &extended_pixels, std::vector<std::vector<bool>> &visited,
147 int width, int extended_rows, int global_y_offset) {
148
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 std::vector<std::pair<int, int>> comp;
149 std::queue<std::pair<int, int>> q;
150 q.emplace(start_col, start_ey);
151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 visited[static_cast<std::size_t>(start_ey)][static_cast<std::size_t>(start_col)] = true;
152
153 30 constexpr std::array<std::pair<int, int>, 4> kDirs = {{{0, -1}, {0, 1}, {-1, 0}, {1, 0}}};
154
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 30 times.
85 while (!q.empty()) {
155 auto [cx, cy] = q.front();
156 q.pop();
157
1/2
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
55 comp.emplace_back(cx, global_y_offset + cy);
158
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 for (const auto &[dx, dy] : kDirs) {
159 220 int nx = cx + dx;
160 220 int ny = cy + dy;
161
8/8
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 187 times.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 158 times.
✓ Branch 5 taken 29 times.
✓ Branch 6 taken 129 times.
✓ Branch 7 taken 29 times.
220 if (nx >= 0 && nx < width && ny >= 0 && ny < extended_rows) {
162 129 std::size_t nidx =
163
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 67 times.
129 (static_cast<std::size_t>(ny) * static_cast<std::size_t>(width)) + static_cast<std::size_t>(nx);
164
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 37 times.
129 if (extended_pixels[nidx] == 1 && !visited[static_cast<std::size_t>(ny)][static_cast<std::size_t>(nx)]) {
165 visited[static_cast<std::size_t>(ny)][static_cast<std::size_t>(nx)] = true;
166 q.emplace(nx, ny);
167 }
168 }
169 }
170 }
171 30 return comp;
172 }
173
174 15 std::vector<std::vector<std::pair<int, int>>> ChernovTConvexHullBinaryComponentsMPI::ProcessExtendedRegion(
175 const std::vector<int> &extended_pixels, int extended_rows, int width, int global_y_offset) {
176
1/2
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 std::vector<std::vector<bool>> visited(extended_rows, std::vector<bool>(width, false));
177 15 std::vector<std::vector<std::pair<int, int>>> all_components;
178
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 15 times.
46 for (int ey = 0; ey < extended_rows; ++ey) {
179
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 31 times.
135 for (int col = 0; col < width; ++col) {
180 104 std::size_t idx =
181
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 49 times.
104 (static_cast<std::size_t>(ey) * static_cast<std::size_t>(width)) + static_cast<std::size_t>(col);
182
4/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 25 times.
104 if (extended_pixels[idx] == 1 && !visited[static_cast<std::size_t>(ey)][static_cast<std::size_t>(col)]) {
183
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 auto comp = ExtractComponent(col, ey, extended_pixels, visited, width, extended_rows, global_y_offset);
184 all_components.push_back(std::move(comp));
185 }
186 }
187 }
188 15 return all_components;
189 15 }
190
191 15 void ChernovTConvexHullBinaryComponentsMPI::FilterLocalComponents(
192 const std::vector<std::vector<std::pair<int, int>>> &all_components) {
193
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 15 times.
45 for (const auto &comp : all_components) {
194 30 std::vector<std::pair<int, int>> local_comp;
195
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 30 times.
85 for (auto [px, py] : comp) {
196
4/4
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 10 times.
55 if (py >= start_row_ && py < end_row_) {
197
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
35 local_comp.emplace_back(px, py);
198 }
199 }
200
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 8 times.
30 if (!local_comp.empty()) {
201 std::ranges::sort(local_comp);
202 auto [first, last] = std::ranges::unique(local_comp);
203 local_comp.erase(first, last);
204
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 local_hulls_.push_back(std::move(local_comp));
205 }
206 }
207 15 }
208
209
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 8 times.
22 std::vector<std::pair<int, int>> ChernovTConvexHullBinaryComponentsMPI::ConvexHull(
210 std::vector<std::pair<int, int>> pts) {
211
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 8 times.
22 if (pts.size() <= 1U) {
212 return pts;
213 }
214 std::ranges::sort(pts);
215 auto [first, last] = std::ranges::unique(pts);
216 pts.erase(first, last);
217
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (pts.size() <= 2U) {
218 return pts;
219 }
220
221
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 std::vector<std::pair<int, int>> hull;
222
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 hull.reserve(pts.size() + 1);
223
224
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 for (const auto &p : pts) {
225
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 9 times.
14 while (hull.size() >= 2) {
226 const auto &a = hull[hull.size() - 2];
227 const auto &b = hull[hull.size() - 1];
228 5 std::int64_t cross =
229 5 (static_cast<std::int64_t>(b.first - a.first) * static_cast<std::int64_t>(p.second - a.second)) -
230 5 (static_cast<std::int64_t>(b.second - a.second) * static_cast<std::int64_t>(p.first - a.first));
231
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (cross > 0) {
232 break;
233 }
234 hull.pop_back();
235 }
236 hull.push_back(p);
237 }
238
239 std::size_t lower_len = hull.size();
240
241
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2 times.
9 for (auto it = pts.rbegin() + 1; it != pts.rend(); ++it) {
242
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
12 while (hull.size() > lower_len) {
243 const auto &a = hull[hull.size() - 2];
244 const auto &b = hull[hull.size() - 1];
245 std::int64_t cross =
246 5 (static_cast<std::int64_t>(b.first - a.first) * static_cast<std::int64_t>(it->second - a.second)) -
247 5 (static_cast<std::int64_t>(b.second - a.second) * static_cast<std::int64_t>(it->first - a.first));
248
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (cross > 0) {
249 break;
250 }
251 hull.pop_back();
252 }
253 hull.push_back(*it);
254 }
255
256
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (hull.size() > 1) {
257 hull.pop_back();
258 }
259 return hull;
260 }
261
262 18 void ChernovTConvexHullBinaryComponentsMPI::ComputeConvexHulls() {
263
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 18 times.
40 for (auto &comp : local_hulls_) {
264
1/2
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
44 comp = ConvexHull(comp);
265 }
266 18 }
267
268 9 void ChernovTConvexHullBinaryComponentsMPI::GatherHullsOnRank0(std::vector<int> &all_sizes,
269 std::vector<int> &global_flat) {
270
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
18 all_sizes = std::vector<int>(local_hulls_.size());
271 global_flat.clear();
272
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 9 times.
23 for (size_t i = 0; i < local_hulls_.size(); ++i) {
273 14 all_sizes[i] = static_cast<int>(local_hulls_[i].size());
274
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 14 times.
33 for (const auto &p : local_hulls_[i]) {
275
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17 times.
19 global_flat.push_back(p.first);
276
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 global_flat.push_back(p.second);
277 }
278 }
279
280
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 for (int src = 1; src < size_; ++src) {
281 9 ReceiveHullsFromRank(src, all_sizes, global_flat);
282 }
283 9 }
284
285 18 void ChernovTConvexHullBinaryComponentsMPI::BroadcastResultToAllRanks(
286 const std::vector<std::vector<std::pair<int, int>>> &global_hulls) {
287 18 int total_hulls = static_cast<int>(global_hulls.size());
288 18 MPI_Bcast(&total_hulls, 1, MPI_INT, 0, MPI_COMM_WORLD);
289
290 18 std::vector<int> all_sizes(total_hulls);
291
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank_ == 0) {
292
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 9 times.
31 for (int i = 0; i < total_hulls; ++i) {
293 22 all_sizes[i] = static_cast<int>(global_hulls[static_cast<std::size_t>(i)].size());
294 }
295 }
296
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Bcast(all_sizes.data(), total_hulls, MPI_INT, 0, MPI_COMM_WORLD);
297
298 18 int total_pts = 0;
299
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 18 times.
62 for (int s : all_sizes) {
300 44 total_pts += s;
301 }
302
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Bcast(&total_pts, 1, MPI_INT, 0, MPI_COMM_WORLD);
303
304
1/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
18 std::vector<int> flat(static_cast<std::size_t>(total_pts) * 2);
305
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank_ == 0) {
306 flat.clear();
307
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 9 times.
31 for (const auto &h : global_hulls) {
308
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 22 times.
52 for (const auto &p : h) {
309
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 flat.push_back(p.first);
310
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 flat.push_back(p.second);
311 }
312 }
313 }
314
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Bcast(flat.data(), total_pts * 2, MPI_INT, 0, MPI_COMM_WORLD);
315
316 18 OutType result;
317 std::size_t idx = 0;
318
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 18 times.
62 for (int i = 0; i < total_hulls; ++i) {
319
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 int sz = all_sizes[i];
320
1/2
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
44 std::vector<std::pair<int, int>> hull(static_cast<std::size_t>(sz));
321
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 44 times.
104 for (int j = 0; j < sz; ++j, idx += 2) {
322 60 hull[static_cast<std::size_t>(j)] = {flat[idx], flat[idx + 1]};
323 }
324 result.push_back(std::move(hull));
325 }
326 18 GetOutput() = std::move(result);
327 36 }
328
329 18 void ChernovTConvexHullBinaryComponentsMPI::GatherAndBroadcastResult() {
330 18 std::vector<int> local_flat;
331 18 std::vector<int> local_sizes;
332
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 18 times.
40 for (const auto &hull : local_hulls_) {
333
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 local_sizes.push_back(static_cast<int>(hull.size()));
334
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 22 times.
52 for (const auto &p : hull) {
335
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 27 times.
30 local_flat.push_back(p.first);
336
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 13 times.
30 local_flat.push_back(p.second);
337 }
338 }
339
340
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank_ == 0) {
341 9 std::vector<int> all_sizes;
342 9 std::vector<int> global_flat;
343
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 GatherHullsOnRank0(all_sizes, global_flat);
344
345 9 OutType global_hulls;
346 std::size_t idx = 0;
347
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 9 times.
31 for (int sz : all_sizes) {
348
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 std::vector<std::pair<int, int>> hull(static_cast<std::size_t>(sz));
349
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 22 times.
52 for (int j = 0; j < sz; ++j, idx += 2) {
350 30 hull[static_cast<std::size_t>(j)] = {global_flat[idx], global_flat[idx + 1]};
351 }
352 global_hulls.push_back(std::move(hull));
353 }
354
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 BroadcastResultToAllRanks(global_hulls);
355 9 } else {
356
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 SendHullsToRank0(local_flat, local_sizes);
357
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
9 BroadcastResultToAllRanks({});
358 }
359 18 }
360
361 9 void ChernovTConvexHullBinaryComponentsMPI::SendHullsToRank0(const std::vector<int> &local_flat,
362 const std::vector<int> &local_sizes) {
363 9 int count = static_cast<int>(local_sizes.size());
364 9 MPI_Send(&count, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
365
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (count > 0) {
366 5 MPI_Send(local_sizes.data(), count, MPI_INT, 0, 1, MPI_COMM_WORLD);
367 5 int pts = static_cast<int>(local_flat.size() / 2);
368 5 MPI_Send(&pts, 1, MPI_INT, 0, 2, MPI_COMM_WORLD);
369
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (pts > 0) {
370 5 MPI_Send(local_flat.data(), static_cast<int>(local_flat.size()), MPI_INT, 0, 3, MPI_COMM_WORLD);
371 }
372 }
373 9 }
374
375 9 void ChernovTConvexHullBinaryComponentsMPI::ReceiveHullsFromRank(int src, std::vector<int> &all_sizes,
376 std::vector<int> &global_flat) {
377 9 int count = 0;
378 9 MPI_Recv(&count, 1, MPI_INT, src, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
379
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 4 times.
9 if (count > 0) {
380 5 std::vector<int> sizes(static_cast<std::size_t>(count));
381
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 MPI_Recv(sizes.data(), count, MPI_INT, src, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
382 5 all_sizes.insert(all_sizes.end(), sizes.begin(), sizes.end());
383 5 int pts = 0;
384
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 MPI_Recv(&pts, 1, MPI_INT, src, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
385
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (pts > 0) {
386
1/4
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
5 std::vector<int> pts_data(static_cast<std::size_t>(pts) * 2);
387
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 MPI_Recv(pts_data.data(), pts * 2, MPI_INT, src, 3, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
388
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 global_flat.insert(global_flat.end(), pts_data.begin(), pts_data.end());
389 }
390 }
391 9 }
392
393 18 bool ChernovTConvexHullBinaryComponentsMPI::RunImpl() {
394
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!valid_) {
395 GetOutput() = OutType{};
396 return true;
397 }
398 18 FindConnectedComponentsMpi();
399 18 ComputeConvexHulls();
400 18 GatherAndBroadcastResult();
401 18 return true;
402 }
403
404
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3 times.
18 bool ChernovTConvexHullBinaryComponentsMPI::PostProcessingImpl() {
405 local_pixels_.clear();
406 local_hulls_.clear();
407 18 return true;
408 }
409
410 } // namespace chernov_t_convex_hull_binary_components
411