GCC Code Coverage Report


Directory: ./
File: tasks/papulina_y_gauss_filter_block/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 139 141 98.6%
Functions: 12 12 100.0%
Branches: 75 106 70.8%

Line Branch Exec Source
1 #include "papulina_y_gauss_filter_block/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <array>
7 #include <cmath>
8 #include <cstddef>
9 #include <vector>
10
11 #include "papulina_y_gauss_filter_block/common/include/common.hpp"
12
13 namespace papulina_y_gauss_filter_block {
14
15
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
62 PapulinaYGaussFilterMPI::PapulinaYGaussFilterMPI(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17 GetInput() = in;
18 62 GetOutput() = Picture();
19 62 }
20
21 62 bool PapulinaYGaussFilterMPI::ValidationImpl() {
22 62 int rank = 0;
23 62 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
24 62 int flag = 1;
25
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 31 times.
62 if (rank == 0) {
26 31 flag = static_cast<int>(!(GetInput().pixels.empty()));
27 }
28 62 MPI_Bcast(&flag, 1, MPI_INT, 0, MPI_COMM_WORLD);
29 62 return flag > 0;
30 }
31
32 62 bool PapulinaYGaussFilterMPI::PreProcessingImpl() {
33 62 int rank = 0;
34 62 MPI_Comm_size(MPI_COMM_WORLD, &procNum_);
35 62 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
36
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 31 times.
62 if (rank == 0) {
37 Pic_ = GetInput(); // считываем картинку в нулевой процесс
38 31 height_ = Pic_.height;
39 31 width_ = Pic_.width;
40 31 channels_ = Pic_.channels;
41 }
42 // отправляем height_ и width_
43 62 MPI_Bcast(&height_, 1, MPI_INT, 0, MPI_COMM_WORLD);
44 62 MPI_Bcast(&width_, 1, MPI_INT, 0, MPI_COMM_WORLD);
45 62 MPI_Bcast(&channels_, 1, MPI_INT, 0, MPI_COMM_WORLD);
46 // определяем размеры сетки процессов
47
1/2
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
62 for (int k = static_cast<int>(std::sqrt(procNum_)); k > 0; k--) {
48
1/2
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
62 if (procNum_ % k == 0) { // ищем наибольший делитель
49 62 grid_rows_ = k;
50 62 grid_cols_ = procNum_ / k;
51 62 break;
52 }
53 }
54
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 if (grid_rows_ == 0) {
55 grid_rows_ = 1;
56 grid_cols_ = procNum_;
57 }
58 // размер базового блока
59 62 block_rows_ = height_ / grid_rows_;
60 62 block_cols_ = width_ / grid_cols_;
61 62 extra_rows_ = height_ % grid_rows_;
62 62 extra_cols_ = width_ % grid_cols_;
63
64 62 return true;
65 }
66
67 62 bool PapulinaYGaussFilterMPI::RunImpl() {
68 62 int rank = 0;
69 62 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
70
71 // координаты процесса в сетке
72 62 int row = rank / grid_cols_;
73 62 int col = rank % grid_cols_;
74
75 // размеры блока конкретного процесса
76
1/2
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
62 int my_block_rows = block_rows_ + (row < extra_rows_ ? 1 : 0);
77
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 25 times.
62 int my_block_cols = block_cols_ + (col < extra_cols_ ? 1 : 0);
78
79 // рассширенный блок с учетом всех соседей
80 62 int expanded_rows = my_block_rows + (2 * overlap_);
81 62 int expanded_cols = my_block_cols + (2 * overlap_);
82
83 // координаты начала блока конкретного процесса в сетке
84 62 int start_row = (row * block_rows_) + std::min(row, extra_rows_);
85 62 int start_col = (col * block_cols_) + std::min(col, extra_cols_);
86
87 Block block(my_block_rows, my_block_cols, expanded_rows, expanded_cols, start_row, start_col);
88
89 62 std::vector<unsigned char> my_block(static_cast<size_t>(expanded_rows * expanded_cols * channels_), 0);
90
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 31 times.
62 if (rank == 0) {
91 31 CalculateBlock(block, my_block);
92
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 DataDistribution();
93 } else {
94
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 MPI_Recv(my_block.data(), static_cast<int>(my_block.size()), MPI_UNSIGNED_CHAR, 0, 0, MPI_COMM_WORLD,
95 MPI_STATUS_IGNORE);
96 }
97
98
1/4
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
62 std::vector<unsigned char> filtered_block(static_cast<size_t>(expanded_rows * expanded_cols * channels_), 0);
99 62 NewBlock(block, my_block, filtered_block);
100
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
62 GetResult(rank, block, filtered_block);
101
102 62 return true;
103 }
104 31 void PapulinaYGaussFilterMPI::DataDistribution() {
105 31 int rank = 0;
106 31 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
107
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 31 times.
62 for (int pr = 1; pr < procNum_; pr++) {
108 31 int p_row = pr / grid_cols_;
109 31 int p_col = pr % grid_cols_;
110
111
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 int p_block_rows = block_rows_ + (p_row < extra_rows_ ? 1 : 0);
112
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 int p_block_cols = block_cols_ + (p_col < extra_cols_ ? 1 : 0);
113
114 31 int p_start_row = (p_row * block_rows_) + std::min(p_row, extra_rows_);
115 31 int p_start_col = (p_col * block_cols_) + std::min(p_col, extra_cols_);
116
117 31 int p_expanded_rows = p_block_rows + (2 * overlap_);
118 31 int p_expanded_cols = p_block_cols + (2 * overlap_);
119 Block block(p_block_rows, p_block_cols, p_expanded_rows, p_expanded_cols, p_start_row, p_start_col);
120 31 std::vector<unsigned char> p_block(static_cast<size_t>(p_expanded_rows * p_expanded_cols * channels_), 0);
121
122 31 CalculateBlock(block, p_block);
123
124
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 MPI_Send(p_block.data(), static_cast<int>(p_block.size()), MPI_UNSIGNED_CHAR, pr, 0, MPI_COMM_WORLD);
125 }
126 31 }
127 22121 void PapulinaYGaussFilterMPI::ClampCoordinates(int &global_i, int &global_j, int height, int width) {
128
4/4
✓ Branch 0 taken 20819 times.
✓ Branch 1 taken 1302 times.
✓ Branch 2 taken 20802 times.
✓ Branch 3 taken 1319 times.
42940 global_i = std::max(0, std::min(height - 1, global_i));
129
4/4
✓ Branch 0 taken 20847 times.
✓ Branch 1 taken 1274 times.
✓ Branch 2 taken 20910 times.
✓ Branch 3 taken 1211 times.
42968 global_j = std::max(0, std::min(width - 1, global_j));
130 22121 }
131 62 void PapulinaYGaussFilterMPI::CalculateBlock(const Block &block, std::vector<unsigned char> &my_block) {
132
2/2
✓ Branch 0 taken 1178 times.
✓ Branch 1 taken 62 times.
1240 for (int i = -overlap_; i < block.my_block_rows + overlap_; i++) {
133
2/2
✓ Branch 0 taken 22121 times.
✓ Branch 1 taken 1178 times.
23299 for (int j = -overlap_; j < block.my_block_cols + overlap_; j++) {
134 22121 int global_i = block.start_row + i;
135 22121 int global_j = block.start_col + j;
136
137 22121 ClampCoordinates(global_i, global_j, height_, width_);
138
139
2/2
✓ Branch 0 taken 32137 times.
✓ Branch 1 taken 22121 times.
54258 for (int ch = 0; ch < channels_; ch++) {
140 32137 int local_idx = (((i + overlap_) * block.expanded_cols + (j + overlap_)) * channels_) + ch;
141 32137 int global_idx = ((global_i * width_ + global_j) * channels_) + ch;
142 32137 my_block[local_idx] = Pic_.pixels[global_idx];
143 }
144 }
145 }
146 62 }
147
148 62 void PapulinaYGaussFilterMPI::NewBlock(const Block &block, const std::vector<unsigned char> &my_block,
149 std::vector<unsigned char> &filtered_block) const {
150 static constexpr std::array<float, 9> kErnel = {1.0F / 16, 2.0F / 16, 1.0F / 16, 2.0F / 16, 4.0F / 16,
151 2.0F / 16, 1.0F / 16, 2.0F / 16, 1.0F / 16};
152
153 62 const int expanded_cols = block.expanded_cols;
154
155
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 62 times.
160 for (int ch = 0; ch < channels_; ++ch) {
156
2/2
✓ Branch 0 taken 1514 times.
✓ Branch 1 taken 98 times.
1612 for (int i = overlap_; i < block.expanded_rows - overlap_; ++i) {
157
2/2
✓ Branch 0 taken 27203 times.
✓ Branch 1 taken 1514 times.
28717 for (int j = overlap_; j < block.expanded_cols - overlap_; ++j) {
158 27203 float sum = 0.0F;
159 const float *kernel_ptr = kErnel.data();
160
161
2/2
✓ Branch 0 taken 81609 times.
✓ Branch 1 taken 27203 times.
108812 for (int ki = -1; ki <= 1; ++ki) {
162
2/2
✓ Branch 0 taken 244827 times.
✓ Branch 1 taken 81609 times.
326436 for (int kj = -1; kj <= 1; ++kj) {
163 244827 const int idx = (((i + ki) * expanded_cols + (j + kj)) * channels_) + ch;
164 244827 sum += static_cast<float>(my_block[idx]) * (*kernel_ptr);
165 244827 ++kernel_ptr;
166 }
167 }
168
169
2/4
✓ Branch 0 taken 27203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27203 times.
✗ Branch 3 not taken.
54406 sum = std::max(0.0F, std::min(255.0F, sum));
170 27203 const int dst_idx = ((i * expanded_cols + j) * channels_) + ch;
171 27203 filtered_block[dst_idx] = static_cast<unsigned char>(std::lround(sum));
172 }
173 }
174 }
175 62 }
176 62 void PapulinaYGaussFilterMPI::GetResult(const int &rank, const Block &block,
177 const std::vector<unsigned char> &filtered_block) {
178 62 std::vector<unsigned char> my_result(static_cast<size_t>(block.my_block_rows * block.my_block_cols * channels_));
179 62 ExtractBlock(block, filtered_block, my_result);
180
1/4
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
62 std::vector<unsigned char> final_image(static_cast<size_t>(height_ * width_ * channels_), 0);
181
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 31 times.
62 if (rank == 0) {
182 31 FillImage(block, my_result, final_image);
183
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 31 times.
62 for (int src = 1; src < procNum_; src++) {
184 31 int src_row = src / grid_cols_;
185 31 int src_col = src % grid_cols_;
186
187
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 int src_block_rows = block_rows_ + (src_row < extra_rows_ ? 1 : 0);
188
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 int src_block_cols = block_cols_ + (src_col < extra_cols_ ? 1 : 0);
189
190
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 int src_start_row = (src_row * block_rows_) + std::min(src_row, extra_rows_);
191
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 int src_start_col = (src_col * block_cols_) + std::min(src_col, extra_cols_);
192
193 Block src_block(src_block_rows, src_block_cols, src_block_rows, src_block_cols, src_start_row, src_start_col);
194
195
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 std::vector<unsigned char> src_result(static_cast<size_t>(src_block_rows * src_block_cols * channels_));
196
197
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 MPI_Recv(src_result.data(), src_block_rows * src_block_cols * channels_, MPI_UNSIGNED_CHAR, src, 0,
198 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
199 31 FillImage(src_block, src_result, final_image);
200 }
201 } else {
202
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 MPI_Send(my_result.data(), block.my_block_rows * block.my_block_cols * channels_, MPI_UNSIGNED_CHAR, 0, 0,
203 MPI_COMM_WORLD);
204 }
205
1/2
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
62 MPI_Bcast(final_image.data(), height_ * width_ * channels_, MPI_UNSIGNED_CHAR, 0, MPI_COMM_WORLD);
206
2/6
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 62 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
124 GetOutput() = Picture(height_, width_, channels_, final_image);
207 62 }
208 62 void PapulinaYGaussFilterMPI::ExtractBlock(const Block &block, const std::vector<unsigned char> &filtered_block,
209 std::vector<unsigned char> &my_result) const {
210
2/2
✓ Branch 0 taken 1054 times.
✓ Branch 1 taken 62 times.
1116 for (int i = 0; i < block.my_block_rows; i++) {
211
2/2
✓ Branch 0 taken 18711 times.
✓ Branch 1 taken 1054 times.
19765 for (int j = 0; j < block.my_block_cols; j++) {
212
2/2
✓ Branch 0 taken 27203 times.
✓ Branch 1 taken 18711 times.
45914 for (int ch = 0; ch < channels_; ch++) {
213 27203 int src_idx = (((i + overlap_) * block.expanded_cols + (j + overlap_)) * channels_) + ch;
214 27203 int dst_idx = (((i * block.my_block_cols) + j) * channels_) + ch;
215 27203 my_result[dst_idx] = filtered_block[src_idx];
216 }
217 }
218 }
219 62 }
220 62 void PapulinaYGaussFilterMPI::FillImage(const Block &block, const std::vector<unsigned char> &my_result,
221 std::vector<unsigned char> &final_image) const {
222
2/2
✓ Branch 0 taken 1054 times.
✓ Branch 1 taken 62 times.
1116 for (int i = 0; i < block.my_block_rows; i++) {
223
2/2
✓ Branch 0 taken 18711 times.
✓ Branch 1 taken 1054 times.
19765 for (int j = 0; j < block.my_block_cols; j++) {
224 18711 int global_i = block.start_row + i;
225 18711 int global_j = block.start_col + j;
226
227
2/2
✓ Branch 0 taken 27203 times.
✓ Branch 1 taken 18711 times.
45914 for (int ch = 0; ch < channels_; ch++) {
228 27203 int src_idx = ((i * block.my_block_cols + j) * channels_) + ch;
229 27203 int dst_idx = ((global_i * width_ + global_j) * channels_) + ch;
230 27203 final_image[dst_idx] = my_result[src_idx];
231 }
232 }
233 }
234 62 }
235 62 bool PapulinaYGaussFilterMPI::PostProcessingImpl() {
236 62 return true;
237 }
238
239 } // namespace papulina_y_gauss_filter_block
240