GCC Code Coverage Report


Directory: ./
File: tasks/tsibareva_e_edge_select_sobel/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 0 127 0.0%
Functions: 0 14 0.0%
Branches: 0 100 0.0%

Line Branch Exec Source
1 #include "tsibareva_e_edge_select_sobel/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cmath>
7 #include <cstddef>
8 #include <vector>
9
10 #include "tsibareva_e_edge_select_sobel/common/include/common.hpp"
11
12 namespace tsibareva_e_edge_select_sobel {
13
14 const std::vector<std::vector<int>> kSobelX = {{-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1}};
15
16 const std::vector<std::vector<int>> kSobelY = {{-1, -2, -1}, {0, 0, 0}, {1, 2, 1}};
17
18 TsibarevaEEdgeSelectSobelMPI::TsibarevaEEdgeSelectSobelMPI(const InType &in) {
19 SetTypeOfTask(GetStaticTypeOfTask());
20
21 int world_rank = 0;
22 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
23 if (world_rank == 0) {
24 GetInput() = in;
25 input_pixels_ = std::get<0>(GetInput());
26 height_ = std::get<1>(GetInput());
27 width_ = std::get<2>(GetInput());
28 threshold_ = std::get<3>(GetInput());
29 }
30
31 GetOutput() = std::vector<int>();
32 }
33
34 bool TsibarevaEEdgeSelectSobelMPI::ValidationImpl() {
35 return true;
36 }
37
38 bool TsibarevaEEdgeSelectSobelMPI::PreProcessingImpl() {
39 return true;
40 }
41
42 bool TsibarevaEEdgeSelectSobelMPI::RunImpl() {
43 int world_rank = 0;
44 int world_size = 0;
45 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
46 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
47
48 BroadcastParameters();
49
50 DistributeRows();
51
52 std::vector<int> local_result = LocalGradientsComputing();
53
54 GatherResults(local_result);
55
56 return true;
57 }
58
59 bool TsibarevaEEdgeSelectSobelMPI::PostProcessingImpl() {
60 return true;
61 }
62
63 void TsibarevaEEdgeSelectSobelMPI::BroadcastParameters() {
64 int world_rank = 0;
65 int world_size = 0;
66 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
67 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
68
69 MPI_Bcast(&height_, 1, MPI_INT, 0, MPI_COMM_WORLD);
70 MPI_Bcast(&width_, 1, MPI_INT, 0, MPI_COMM_WORLD);
71 MPI_Bcast(&threshold_, 1, MPI_INT, 0, MPI_COMM_WORLD);
72 }
73
74 void TsibarevaEEdgeSelectSobelMPI::RowDistributionComputing(int world_rank, int world_size, int &base_rows,
75 int &remainder, int &real_rows, int &need_top_halo,
76 int &need_bottom_halo, int &total_rows) {
77 // базовое (основное) количество строк на процесс
78 base_rows = height_ / world_size;
79 remainder = height_ % world_size;
80
81 // предварительное количество строк на процесс
82 real_rows = base_rows + (world_rank < remainder ? 1 : 0);
83 local_height_ = real_rows;
84
85 // отдельно подсчитаны флаги, какому процессу требуется верхняя соседняя строка, какому - нижняя соседняя строка
86 need_top_halo = (world_rank > 0) ? 1 : 0;
87 need_bottom_halo = (world_rank < (world_size - 1)) ? 1 : 0;
88
89 // итоговое количество строк на процесс
90 total_rows = real_rows + need_top_halo + need_bottom_halo;
91 local_height_with_halo_ = total_rows;
92 local_pixels_.resize(static_cast<size_t>(total_rows) * width_, 0);
93 }
94
95 void TsibarevaEEdgeSelectSobelMPI::SendParameters(int world_rank, int world_size, int base_rows, int remainder,
96 std::vector<int> &real_rows_per_proc, std::vector<int> &send_counts,
97 std::vector<int> &send_displs) const {
98 if (world_rank == 0) {
99 int current_row = 0;
100 for (int dest = 0; dest < world_size; ++dest) {
101 int dest_real_rows = base_rows + (dest < remainder ? 1 : 0);
102 real_rows_per_proc[dest] = dest_real_rows;
103
104 int dest_need_top_halo = (dest > 0) ? 1 : 0;
105 int dest_need_bottom_halo = (dest < (world_size - 1)) ? 1 : 0;
106 int start_row_with_halo = current_row - dest_need_top_halo;
107
108 int end_row_with_halo = current_row + dest_real_rows + dest_need_bottom_halo - 1;
109 end_row_with_halo = std::min(end_row_with_halo, height_ - 1);
110
111 int actual_rows = end_row_with_halo - start_row_with_halo + 1;
112
113 send_counts[dest] = actual_rows * width_;
114 send_displs[dest] = start_row_with_halo * width_;
115
116 current_row += dest_real_rows;
117 }
118 }
119 }
120
121 void TsibarevaEEdgeSelectSobelMPI::DataDistribution(int world_rank, const std::vector<int> &send_counts,
122 const std::vector<int> &send_displs) {
123 MPI_Scatterv(world_rank == 0 ? input_pixels_.data() : nullptr, send_counts.data(), send_displs.data(), MPI_INT,
124 local_pixels_.data(), static_cast<int>(local_pixels_.size()), MPI_INT, 0, MPI_COMM_WORLD);
125 }
126
127 void TsibarevaEEdgeSelectSobelMPI::DistributeRows() {
128 int world_rank = 0;
129 int world_size = 0;
130 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
131 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
132
133 int base_rows = 0;
134 int remainder = 0;
135 int real_rows = 0;
136 int need_top_halo = 0;
137 int need_bottom_halo = 0;
138 int total_rows = 0;
139
140 RowDistributionComputing(world_rank, world_size, base_rows, remainder, real_rows, need_top_halo, need_bottom_halo,
141 total_rows);
142
143 std::vector<int> send_counts(world_size, 0);
144 std::vector<int> send_displs(world_size, 0);
145 std::vector<int> real_rows_per_proc(world_size, 0);
146
147 SendParameters(world_rank, world_size, base_rows, remainder, real_rows_per_proc, send_counts, send_displs);
148
149 DataDistribution(world_rank, send_counts, send_displs);
150 }
151
152 std::vector<int> TsibarevaEEdgeSelectSobelMPI::LocalGradientsComputing() {
153 int world_rank = 0;
154 int world_size = 0;
155 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
156 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
157
158 std::vector<int> local_result;
159 if (local_height_ > 0) {
160 local_result.resize(static_cast<size_t>(local_height_) * width_, 0);
161
162 for (int local_y = 0; local_y < local_height_; ++local_y) {
163 int y = local_y + ((world_rank > 0) ? 1 : 0);
164
165 for (int col = 0; col < width_; ++col) {
166 int gx = GradientX(col, y);
167 int gy = GradientY(col, y);
168
169 int mag = static_cast<int>(std::sqrt((gx * gx) + (gy * gy) + 0.0));
170 local_result[(static_cast<size_t>(local_y) * width_) + col] = (mag <= threshold_) ? 0 : mag;
171 }
172 }
173 }
174
175 return local_result;
176 }
177
178 int TsibarevaEEdgeSelectSobelMPI::GradientX(int x, int y) {
179 int sum = 0;
180
181 for (int ky = -1; ky <= 1; ++ky) {
182 for (int kx = -1; kx <= 1; ++kx) {
183 int nx = x + kx;
184 int ny = y + ky;
185
186 if (nx >= 0 && nx < width_ && ny >= 0 && ny < local_height_with_halo_) {
187 int pixel = local_pixels_[(static_cast<size_t>(ny) * width_) + nx];
188 sum += pixel * kSobelX[ky + 1][kx + 1];
189 }
190 }
191 }
192
193 return sum;
194 }
195
196 int TsibarevaEEdgeSelectSobelMPI::GradientY(int x, int y) {
197 int sum = 0;
198
199 for (int ky = -1; ky <= 1; ++ky) {
200 for (int kx = -1; kx <= 1; ++kx) {
201 int nx = x + kx;
202 int ny = y + ky;
203
204 if (nx >= 0 && nx < width_ && ny >= 0 && ny < local_height_with_halo_) {
205 int pixel = local_pixels_[(static_cast<size_t>(ny) * width_) + nx];
206 sum += pixel * kSobelY[ky + 1][kx + 1];
207 }
208 }
209 }
210
211 return sum;
212 }
213
214 void TsibarevaEEdgeSelectSobelMPI::GatherResults(const std::vector<int> &local_result) {
215 int world_rank = 0;
216 int world_size = 0;
217 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
218 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
219
220 std::vector<int> local_result_sizes(world_size);
221 int local_size = static_cast<int>(local_result.size());
222 MPI_Allgather(&local_size, 1, MPI_INT, local_result_sizes.data(), 1, MPI_INT, MPI_COMM_WORLD);
223
224 std::vector<int> displs(world_size);
225 int total_size = 0;
226 for (int i = 0; i < world_size; ++i) {
227 displs[i] = total_size;
228 total_size += local_result_sizes[i];
229 }
230
231 GetOutput().resize(static_cast<size_t>(total_size));
232
233 MPI_Allgatherv(local_result.empty() ? nullptr : local_result.data(), local_size, MPI_INT, GetOutput().data(),
234 local_result_sizes.data(), displs.data(), MPI_INT, MPI_COMM_WORLD);
235 }
236
237 } // namespace tsibareva_e_edge_select_sobel
238