GCC Code Coverage Report


Directory: ./
File: tasks/kopilov_d_vertical_gauss_filter/all/src/ops_all.cpp
Date: 2026-06-04 20:25:32
Exec Total Coverage
Lines: 151 151 100.0%
Functions: 15 15 100.0%
Branches: 114 168 67.9%

Line Branch Exec Source
1 #include "kopilov_d_vertical_gauss_filter/all/include/ops_all.hpp"
2
3 #include <mpi.h>
4 #include <oneapi/tbb/blocked_range2d.h>
5 #include <oneapi/tbb/parallel_for.h>
6
7 #include <array>
8 #include <cstddef>
9 #include <cstdint>
10 #include <vector>
11
12 #include "kopilov_d_vertical_gauss_filter/common/include/common.hpp"
13
14 namespace kopilov_d_vertical_gauss_filter {
15
16 namespace {
17 const int kDivisor = 16;
18 const std::array<std::array<int, 3>, 3> kGaussKernel = {{{1, 2, 1}, {2, 4, 2}, {1, 2, 1}}};
19
20 uint8_t GetPixelWithHalo(const uint8_t *local_data, int col_with_halo, int row, int lw_with_halo, int height) {
21 int cur_row = row;
22 351 if (cur_row < 0) {
23 cur_row = -cur_row - 1;
24
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 273 times.
312 } else if (cur_row >= height) {
25 39 cur_row = (2 * height) - cur_row - 1;
26 }
27 351 auto idx = (static_cast<size_t>(cur_row) * static_cast<size_t>(lw_with_halo)) + static_cast<size_t>(col_with_halo);
28 351 return local_data[idx];
29 }
30
31 39 uint8_t ApplyFilter(const uint8_t *data, int col, int row, int lw_halo, int height) {
32 int pixel_sum = 0;
33
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 39 times.
156 for (size_t ky = 0; ky < 3; ++ky) {
34
2/2
✓ Branch 0 taken 351 times.
✓ Branch 1 taken 117 times.
468 for (size_t kx = 0; kx < 3; ++kx) {
35 351 int cur_col = col + static_cast<int>(kx);
36 351 int cur_row = row + static_cast<int>(ky) - 1;
37
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 312 times.
702 pixel_sum += kGaussKernel.at(ky).at(kx) * GetPixelWithHalo(data, cur_col, cur_row, lw_halo, height);
38 }
39 }
40 39 return static_cast<uint8_t>(pixel_sum / kDivisor);
41 }
42
43 9 int FindLeftNeighbor(int rank, const std::vector<int> &counts) {
44
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 for (int p_idx = rank - 1; p_idx >= 0; --p_idx) {
45
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
4 if (counts.at(static_cast<size_t>(p_idx)) > 0) {
46 return p_idx;
47 }
48 }
49 return MPI_PROC_NULL;
50 }
51
52 9 int FindRightNeighbor(int rank, int size, const std::vector<int> &counts) {
53
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 for (int p_idx = rank + 1; p_idx < size; ++p_idx) {
54
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 4 times.
5 if (counts.at(static_cast<size_t>(p_idx)) > 0) {
55 return p_idx;
56 }
57 }
58 return MPI_PROC_NULL;
59 }
60
61 10 void ExchangeHalo(int world_rank, int world_size, int height, int local_w, int lw_with_halo,
62 std::vector<uint8_t> &local_input, const std::vector<int> &counts) {
63
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (local_w <= 0) {
64 1 return;
65 }
66
67 9 std::vector<uint8_t> send_left(static_cast<size_t>(height));
68
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 std::vector<uint8_t> send_right(static_cast<size_t>(height));
69
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 std::vector<uint8_t> recv_left(static_cast<size_t>(height));
70
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 std::vector<uint8_t> recv_right(static_cast<size_t>(height));
71
72
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 9 times.
34 for (int row_idx = 0; row_idx < height; ++row_idx) {
73 25 send_left[static_cast<size_t>(row_idx)] =
74 25 local_input[(static_cast<size_t>(row_idx) * static_cast<size_t>(lw_with_halo)) + 1];
75 25 send_right[static_cast<size_t>(row_idx)] =
76 25 local_input[(static_cast<size_t>(row_idx) * static_cast<size_t>(lw_with_halo)) + static_cast<size_t>(local_w)];
77 }
78
79
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 int left_proc = FindLeftNeighbor(world_rank, counts);
80
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 int right_proc = FindRightNeighbor(world_rank, world_size, counts);
81
82
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 MPI_Sendrecv(send_left.data(), height, MPI_UNSIGNED_CHAR, left_proc, 1, recv_right.data(), height, MPI_UNSIGNED_CHAR,
83 right_proc, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
84
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 MPI_Sendrecv(send_right.data(), height, MPI_UNSIGNED_CHAR, right_proc, 2, recv_left.data(), height, MPI_UNSIGNED_CHAR,
85 left_proc, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
86
87
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 9 times.
34 for (int row_idx = 0; row_idx < height; ++row_idx) {
88 25 auto base_idx = static_cast<size_t>(row_idx) * static_cast<size_t>(lw_with_halo);
89
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 13 times.
25 if (left_proc != MPI_PROC_NULL) {
90 12 local_input[base_idx + 0] = recv_left[static_cast<size_t>(row_idx)];
91 } else {
92 13 local_input[base_idx + 0] = local_input[base_idx + 1];
93 }
94
95
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 13 times.
25 if (right_proc != MPI_PROC_NULL) {
96 12 local_input[base_idx + static_cast<size_t>(local_w + 1)] = recv_right[static_cast<size_t>(row_idx)];
97 } else {
98 13 local_input[base_idx + static_cast<size_t>(local_w + 1)] = local_input[base_idx + static_cast<size_t>(local_w)];
99 }
100 }
101 }
102
103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 void MasterDistribute(int world_size, int width, int height, const std::vector<int> &counts,
104 const std::vector<int> &displs, const uint8_t *full_data, uint8_t *local_data, int lw_with_halo) {
105 5 int p0_w = counts.at(0);
106
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
18 for (int row_idx = 0; row_idx < height; ++row_idx) {
107
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 13 times.
36 for (int col_idx = 0; col_idx < p0_w; ++col_idx) {
108 23 local_data[(static_cast<size_t>(row_idx) * static_cast<size_t>(lw_with_halo)) +
109 23 static_cast<size_t>(col_idx + 1)] =
110 23 full_data[(static_cast<size_t>(row_idx) * static_cast<size_t>(width)) + static_cast<size_t>(col_idx)];
111 }
112 }
113
114
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 for (int proc_idx = 1; proc_idx < world_size; ++proc_idx) {
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 int cur_w = counts.at(static_cast<size_t>(proc_idx));
116
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (cur_w == 0) {
117 1 continue;
118 }
119 4 std::vector<uint8_t> buf(static_cast<size_t>(cur_w) * static_cast<size_t>(height));
120
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 for (int row_idx = 0; row_idx < height; ++row_idx) {
121
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 12 times.
28 for (int col_idx = 0; col_idx < cur_w; ++col_idx) {
122 16 buf[(static_cast<size_t>(row_idx) * static_cast<size_t>(cur_w)) + static_cast<size_t>(col_idx)] =
123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 full_data[(static_cast<size_t>(row_idx) * static_cast<size_t>(width)) +
124 16 static_cast<size_t>(displs.at(static_cast<size_t>(proc_idx)) + col_idx)];
125 }
126 }
127
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 MPI_Send(buf.data(), static_cast<int>(buf.size()), MPI_UNSIGNED_CHAR, proc_idx, 0, MPI_COMM_WORLD);
128 }
129 5 }
130
131 5 void WorkerReceive(int my_w, int height, uint8_t *local_data, int lw_with_halo) {
132
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (my_w <= 0) {
133 1 return;
134 }
135
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 std::vector<uint8_t> buf(static_cast<size_t>(my_w) * static_cast<size_t>(height));
136
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 MPI_Recv(buf.data(), static_cast<int>(buf.size()), MPI_UNSIGNED_CHAR, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
137
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 for (int row_idx = 0; row_idx < height; ++row_idx) {
138
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 12 times.
28 for (int col_idx = 0; col_idx < my_w; ++col_idx) {
139 16 local_data[(static_cast<size_t>(row_idx) * static_cast<size_t>(lw_with_halo)) +
140 16 static_cast<size_t>(col_idx + 1)] =
141 16 buf[(static_cast<size_t>(row_idx) * static_cast<size_t>(my_w)) + static_cast<size_t>(col_idx)];
142 }
143 }
144 }
145
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 void MasterGather(int world_size, int width, int height, const std::vector<int> &counts, const std::vector<int> &displs,
147 const std::vector<uint8_t> &local_out, uint8_t *full_data) {
148 5 int p0_w = counts.at(0);
149
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 5 times.
18 for (int row_idx = 0; row_idx < height; ++row_idx) {
150
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 13 times.
36 for (int col_idx = 0; col_idx < p0_w; ++col_idx) {
151 23 full_data[(static_cast<size_t>(row_idx) * static_cast<size_t>(width)) + static_cast<size_t>(col_idx)] =
152 23 local_out[(static_cast<size_t>(row_idx) * static_cast<size_t>(p0_w)) + static_cast<size_t>(col_idx)];
153 }
154 }
155
156
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 for (int proc_idx = 1; proc_idx < world_size; ++proc_idx) {
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 int cur_w = counts.at(static_cast<size_t>(proc_idx));
158
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (cur_w == 0) {
159 1 continue;
160 }
161
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 std::vector<uint8_t> buf(static_cast<size_t>(cur_w) * static_cast<size_t>(height));
162
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 MPI_Recv(buf.data(), static_cast<int>(buf.size()), MPI_UNSIGNED_CHAR, proc_idx, 3, MPI_COMM_WORLD,
163 MPI_STATUS_IGNORE);
164
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
16 for (int row_idx = 0; row_idx < height; ++row_idx) {
165
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 12 times.
28 for (int col_idx = 0; col_idx < cur_w; ++col_idx) {
166 32 full_data[(static_cast<size_t>(row_idx) * static_cast<size_t>(width)) +
167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 static_cast<size_t>(displs.at(static_cast<size_t>(proc_idx)) + col_idx)] =
168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
16 buf[(static_cast<size_t>(row_idx) * static_cast<size_t>(cur_w)) + static_cast<size_t>(col_idx)];
169 }
170 }
171 }
172 5 }
173
174 5 void WorkerGather(int local_w, const std::vector<uint8_t> &local_out) {
175
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (local_w <= 0) {
176 return;
177 }
178 4 MPI_Send(local_out.data(), static_cast<int>(local_out.size()), MPI_UNSIGNED_CHAR, 0, 3, MPI_COMM_WORLD);
179 }
180
181 10 void ComputeTBB(int local_w, int global_height, int lw_halo, const uint8_t *in_data, uint8_t *out_data) {
182
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 if (local_w <= 0) {
183 return;
184 }
185 48 tbb::parallel_for(tbb::blocked_range2d<int>(0, global_height, 0, local_w), [&](const tbb::blocked_range2d<int> &r) {
186
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 39 times.
78 for (int row_idx = r.rows().begin(); row_idx != r.rows().end(); ++row_idx) {
187
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 39 times.
78 for (int col_idx = r.cols().begin(); col_idx != r.cols().end(); ++col_idx) {
188 39 out_data[(static_cast<size_t>(row_idx) * static_cast<size_t>(local_w)) + static_cast<size_t>(col_idx)] =
189 39 ApplyFilter(in_data, col_idx, row_idx, lw_halo, global_height);
190 }
191 }
192 39 });
193 }
194
195 } // namespace
196
197
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 KopilovDVerticalGaussFilterALL::KopilovDVerticalGaussFilterALL(const InType &in) {
198 SetTypeOfTask(GetStaticTypeOfTask());
199 GetInput() = in;
200 10 GetOutput() = OutType{};
201 10 }
202
203 10 bool KopilovDVerticalGaussFilterALL::ValidationImpl() {
204 10 int rank = 0;
205 10 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
206 10 int res = 0;
207
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (rank == 0) {
208 const auto &in = GetInput();
209
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 if (in.width > 0 && in.height > 0 &&
210
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 in.data.size() == static_cast<size_t>(in.width) * static_cast<size_t>(in.height)) {
211 5 res = 1;
212 }
213 }
214 10 MPI_Bcast(&res, 1, MPI_INT, 0, MPI_COMM_WORLD);
215 10 return res == 1;
216 }
217
218 10 bool KopilovDVerticalGaussFilterALL::PreProcessingImpl() {
219 10 return true;
220 }
221
222 10 bool KopilovDVerticalGaussFilterALL::RunImpl() {
223 10 int world_size = 0;
224 10 int world_rank = 0;
225 10 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
226 10 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
227
228 10 int global_width = 0;
229 10 int global_height = 0;
230
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (world_rank == 0) {
231 5 global_width = GetInput().width;
232 5 global_height = GetInput().height;
233 }
234 10 MPI_Bcast(&global_width, 1, MPI_INT, 0, MPI_COMM_WORLD);
235 10 MPI_Bcast(&global_height, 1, MPI_INT, 0, MPI_COMM_WORLD);
236
237
2/4
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 if (global_width <= 0 || global_height <= 0) {
238 return true;
239 }
240
241 10 std::vector<int> counts(static_cast<size_t>(world_size));
242
1/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
10 std::vector<int> displs(static_cast<size_t>(world_size));
243 int offset = 0;
244
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10 times.
30 for (int i = 0; i < world_size; ++i) {
245
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 6 times.
34 counts[static_cast<size_t>(i)] = (global_width / world_size) + (i < (global_width % world_size) ? 1 : 0);
246 20 displs[static_cast<size_t>(i)] = offset;
247 20 offset += counts[static_cast<size_t>(i)];
248 }
249
250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 int local_w = counts.at(static_cast<size_t>(world_rank));
251 10 int lw_halo = local_w + 2;
252
1/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
10 std::vector<uint8_t> l_in(static_cast<size_t>(lw_halo) * static_cast<size_t>(global_height), 0);
253
1/4
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
10 std::vector<uint8_t> l_out(static_cast<size_t>(local_w) * static_cast<size_t>(global_height));
254
255
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (world_rank == 0) {
256
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 MasterDistribute(world_size, global_width, global_height, counts, displs, GetInput().data.data(), l_in.data(),
257 lw_halo);
258 } else {
259
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 WorkerReceive(local_w, global_height, l_in.data(), lw_halo);
260 }
261
262
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 ExchangeHalo(world_rank, world_size, global_height, local_w, lw_halo, l_in, counts);
263
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 ComputeTBB(local_w, global_height, lw_halo, l_in.data(), l_out.data());
264
265
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (world_rank == 0) {
266 5 GetOutput().width = global_width;
267 5 GetOutput().height = global_height;
268
2/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
5 GetOutput().data.assign(static_cast<size_t>(global_width) * static_cast<size_t>(global_height), 0);
269
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 MasterGather(world_size, global_width, global_height, counts, displs, l_out, GetOutput().data.data());
270 } else {
271
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 WorkerGather(local_w, l_out);
272 }
273
274 return true;
275 }
276
277 10 bool KopilovDVerticalGaussFilterALL::PostProcessingImpl() {
278 10 return true;
279 }
280
281 } // namespace kopilov_d_vertical_gauss_filter
282