GCC Code Coverage Report


Directory: ./
File: tasks/baldin_a_gauss_filter/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 112 112 100.0%
Functions: 8 8 100.0%
Branches: 56 86 65.1%

Line Branch Exec Source
1 #include "baldin_a_gauss_filter/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 <vector>
10
11 #include "baldin_a_gauss_filter/common/include/common.hpp"
12
13 namespace baldin_a_gauss_filter {
14
15
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 BaldinAGaussFilterMPI::BaldinAGaussFilterMPI(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17 GetInput() = in;
18 30 }
19
20 30 bool BaldinAGaussFilterMPI::ValidationImpl() {
21 30 int rank = 0;
22 30 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
23
24
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (rank == 0) {
25 const auto &im = GetInput();
26 15 bool size_match = (im.pixels.size() == (static_cast<size_t>(im.width) * im.height * im.channels));
27
4/8
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
15 return (im.width > 0 && im.height > 0 && im.channels > 0 && size_match);
28 }
29 return true;
30 }
31
32 30 bool BaldinAGaussFilterMPI::PreProcessingImpl() {
33 30 return true;
34 }
35
36 namespace {
37
38 30 void CalculatePartitions(int size, int height, int width, int channels, std::vector<int> &counts,
39 std::vector<int> &displs, std::vector<int> &real_counts) {
40 30 const int rows_per_proc = height / size;
41 30 const int remainder = height % size;
42
43 int current_global_row = 0;
44 30 const int row_size_bytes = width * channels;
45
46
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 30 times.
90 for (int i = 0; i < size; i++) {
47
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 14 times.
60 int rows = rows_per_proc + ((i < remainder) ? 1 : 0);
48 60 real_counts[i] = rows;
49
50 60 int send_start_row = std::max(0, current_global_row - 1);
51 60 int send_end_row = std::min(height - 1, current_global_row + rows);
52
53 60 int rows_to_send = send_end_row - send_start_row + 1;
54
55 60 counts[i] = rows_to_send * row_size_bytes;
56 60 displs[i] = send_start_row * row_size_bytes;
57
58 current_global_row += rows;
59 }
60 30 }
61
62 30 void ComputeHorizontalPass(int rows, int width, int channels, const std::vector<uint8_t> &src,
63 std::vector<uint16_t> &dst) {
64 30 constexpr std::array<int, 3> kKernel = {1, 2, 1};
65
66
2/2
✓ Branch 0 taken 980 times.
✓ Branch 1 taken 30 times.
1010 for (int row = 0; row < rows; row++) {
67
2/2
✓ Branch 0 taken 74639 times.
✓ Branch 1 taken 980 times.
75619 for (int col = 0; col < width; col++) {
68
2/2
✓ Branch 0 taken 178659 times.
✓ Branch 1 taken 74639 times.
253298 for (int ch = 0; ch < channels; ch++) {
69 int sum = 0;
70
2/2
✓ Branch 0 taken 535977 times.
✓ Branch 1 taken 178659 times.
714636 for (int k = -1; k <= 1; k++) {
71 535977 int n_col = std::clamp(col + k, 0, width - 1);
72 535977 sum += src[(((row * width) + n_col) * channels) + ch] * kKernel.at(k + 1);
73 }
74 178659 dst[(((row * width) + col) * channels) + ch] = static_cast<uint16_t>(sum);
75 }
76 }
77 }
78 30 }
79
80 30 void ComputeVerticalPass(int real_rows, int recv_rows, int width, int channels, int row_offset,
81 const std::vector<uint16_t> &src, std::vector<uint8_t> &dst) {
82 30 constexpr std::array<int, 3> kKernel = {1, 2, 1};
83
84
2/2
✓ Branch 0 taken 953 times.
✓ Branch 1 taken 30 times.
983 for (int i = 0; i < real_rows; i++) {
85 953 int local_row = row_offset + i;
86
87
2/2
✓ Branch 0 taken 72793 times.
✓ Branch 1 taken 953 times.
73746 for (int col = 0; col < width; col++) {
88
2/2
✓ Branch 0 taken 174263 times.
✓ Branch 1 taken 72793 times.
247056 for (int ch = 0; ch < channels; ch++) {
89 int sum = 0;
90
2/2
✓ Branch 0 taken 522789 times.
✓ Branch 1 taken 174263 times.
697052 for (int k = -1; k <= 1; k++) {
91 522789 int neighbor_row = local_row + k;
92 522789 neighbor_row = std::clamp(neighbor_row, 0, recv_rows - 1);
93
94 522789 sum += src[(((neighbor_row * width) + col) * channels) + ch] * kKernel.at(k + 1);
95 }
96 174263 dst[(((i * width) + col) * channels) + ch] = static_cast<uint8_t>(sum / 16);
97 }
98 }
99 }
100 30 }
101
102 } // namespace
103
104 30 bool BaldinAGaussFilterMPI::RunImpl() {
105 ImageData &input = GetInput();
106
107 30 int rank = 0;
108 30 int size = 0;
109 30 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
110 30 MPI_Comm_size(MPI_COMM_WORLD, &size);
111
112 30 int width = 0;
113 30 int height = 0;
114 30 int channels = 0;
115
116
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (rank == 0) {
117 15 width = input.width;
118 15 height = input.height;
119 15 channels = input.channels;
120 }
121 30 MPI_Bcast(&width, 1, MPI_INT, 0, MPI_COMM_WORLD);
122 30 MPI_Bcast(&height, 1, MPI_INT, 0, MPI_COMM_WORLD);
123 30 MPI_Bcast(&channels, 1, MPI_INT, 0, MPI_COMM_WORLD);
124
125 30 std::vector<int> counts(size);
126
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<int> displs(size);
127
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<int> real_counts(size);
128
129 30 CalculatePartitions(size, height, width, channels, counts, displs, real_counts);
130
131
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 int my_real_rows = real_counts[rank];
132 30 int my_recv_rows = counts[rank] / (width * channels);
133
134 30 size_t row_size_bytes = static_cast<size_t>(width) * channels;
135
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<uint8_t> local_buffer(static_cast<size_t>(my_recv_rows) * row_size_bytes);
136
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<uint16_t> horiz_buffer(static_cast<size_t>(my_recv_rows) * row_size_bytes);
137
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<uint8_t> result_buffer(static_cast<size_t>(my_real_rows) * row_size_bytes);
138
139
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
45 MPI_Scatterv(rank == 0 ? input.pixels.data() : nullptr, counts.data(), displs.data(), MPI_UINT8_T,
140
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 local_buffer.data(), counts[rank], MPI_UINT8_T, 0, MPI_COMM_WORLD);
141
142 30 ComputeHorizontalPass(my_recv_rows, width, channels, local_buffer, horiz_buffer);
143
144 30 int row_offset = (rank == 0) ? 0 : 1;
145 30 ComputeVerticalPass(my_real_rows, my_recv_rows, width, channels, row_offset, horiz_buffer, result_buffer);
146
147
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (rank == 0) {
148 15 GetOutput().width = width;
149 15 GetOutput().height = height;
150 15 GetOutput().channels = channels;
151
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 GetOutput().pixels.resize(static_cast<size_t>(width) * height * channels);
152 }
153
154
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<int> recv_counts(size);
155
1/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
30 std::vector<int> recv_displs(size);
156
157
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (rank == 0) {
158 int current_disp = 0;
159 15 int row_bytes_int = width * channels;
160
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 15 times.
45 for (int i = 0; i < size; i++) {
161 30 recv_counts[i] = real_counts[i] * row_bytes_int;
162 30 recv_displs[i] = current_disp;
163 30 current_disp += recv_counts[i];
164 }
165 }
166
167
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 MPI_Gatherv(result_buffer.data(), static_cast<int>(result_buffer.size()), MPI_UINT8_T,
168
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 (rank == 0 ? GetOutput().pixels.data() : nullptr), recv_counts.data(), recv_displs.data(), MPI_UINT8_T, 0,
169 MPI_COMM_WORLD);
170
171 30 return true;
172 }
173
174 30 bool BaldinAGaussFilterMPI::PostProcessingImpl() {
175 30 int rank = 0;
176 30 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
177
178 30 int width = 0;
179 30 int height = 0;
180 30 int channels = 0;
181
182
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (rank == 0) {
183 15 width = GetOutput().width;
184 15 height = GetOutput().height;
185 15 channels = GetOutput().channels;
186 }
187
188 30 MPI_Bcast(&width, 1, MPI_INT, 0, MPI_COMM_WORLD);
189 30 MPI_Bcast(&height, 1, MPI_INT, 0, MPI_COMM_WORLD);
190 30 MPI_Bcast(&channels, 1, MPI_INT, 0, MPI_COMM_WORLD);
191
192 30 size_t total_size = static_cast<size_t>(width) * height * channels;
193
194
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
30 if (rank != 0) {
195 15 GetOutput().width = width;
196 15 GetOutput().height = height;
197 15 GetOutput().channels = channels;
198 15 GetOutput().pixels.resize(total_size);
199 }
200
201 30 MPI_Bcast(static_cast<void *>(GetOutput().pixels.data()), static_cast<int>(total_size), MPI_UINT8_T, 0,
202 MPI_COMM_WORLD);
203
204 30 return true;
205 }
206
207 } // namespace baldin_a_gauss_filter
208