GCC Code Coverage Report


Directory: ./
File: tasks/borunov_v_block_partitioning/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 114 114 100.0%
Functions: 9 9 100.0%
Branches: 37 52 71.2%

Line Branch Exec Source
1 #include "borunov_v_block_partitioning/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 "borunov_v_block_partitioning/common/include/common.hpp"
12
13 namespace borunov_v_block_partitioning {
14
15
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 BorunovVBlockPartitioningMPI::BorunovVBlockPartitioningMPI(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 GetInput() = in;
18 28 }
19
20 28 bool BorunovVBlockPartitioningMPI::ValidationImpl() {
21 28 int rank = 0;
22 28 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
23
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 if (rank == 0) {
24
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (GetInput().size() < 3) {
25 return false;
26 }
27 14 int w = GetInput()[0];
28 14 int h = GetInput()[1];
29 14 const std::size_t pixels = static_cast<std::size_t>(w) * static_cast<std::size_t>(h);
30 14 const std::size_t expected_size = static_cast<std::size_t>(2) + pixels;
31 14 return GetInput().size() == expected_size;
32 }
33 return true;
34 }
35
36 28 bool BorunovVBlockPartitioningMPI::PreProcessingImpl() {
37 28 int rank = 0;
38 28 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
39
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 if (rank == 0) {
40 14 int w = GetInput()[0];
41 14 int h = GetInput()[1];
42 14 GetOutput().assign(static_cast<std::size_t>(w) * static_cast<std::size_t>(h), 0);
43 }
44 28 return true;
45 }
46
47 namespace {
48
49 28 void BroadcastDims(int &width, int &height) {
50 28 MPI_Bcast(&width, 1, MPI_INT, 0, MPI_COMM_WORLD);
51 28 MPI_Bcast(&height, 1, MPI_INT, 0, MPI_COMM_WORLD);
52 28 }
53
54 28 void ComputeSendCountsDispls(int width, int height, int size, std::vector<int> &send_counts, std::vector<int> &displs) {
55 28 send_counts.assign(static_cast<std::size_t>(size), 0);
56 28 displs.assign(static_cast<std::size_t>(size), 0);
57
58 28 const int rows_per_proc = height / size;
59 28 const int remainder = height % size;
60 int current_displ = 0;
61
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 28 times.
84 for (int i = 0; i < size; ++i) {
62
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 12 times.
56 const int proc_rows = rows_per_proc + (i < remainder ? 1 : 0);
63 56 send_counts[i] = proc_rows * width;
64 56 displs[i] = current_displ;
65 56 current_displ += send_counts[i];
66 }
67 28 }
68
69 28 void ComputeSendCountsDisplsWithHalo(int width, int height, const std::vector<int> &send_counts,
70 const std::vector<int> &displs, std::vector<int> &send_counts_halo,
71 std::vector<int> &displs_halo) {
72 28 const int size = static_cast<int>(send_counts.size());
73 28 send_counts_halo.assign(static_cast<std::size_t>(size), 0);
74 28 displs_halo.assign(static_cast<std::size_t>(size), 0);
75
76
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 28 times.
84 for (int i = 0; i < size; ++i) {
77 56 const int row_start = displs[i] / width;
78 56 const int rows = send_counts[i] / width;
79 56 const int start_with_halo = std::max(0, row_start - 1);
80 56 const int end_with_halo = std::min(height, row_start + rows + 1);
81 56 send_counts_halo[i] = (end_with_halo - start_with_halo) * width;
82 56 displs_halo[i] = start_with_halo * width;
83 }
84 28 }
85
86 28 void ApplyKernelToLocalPartition(const int *local_pixels, int width, int height, int base_global_row,
87 int global_row_start, int global_row_end, std::vector<int> &local_res) {
88 const std::array<std::array<float, 3>, 3> kernel = {{
89 {1.0F / 16.0F, 2.0F / 16.0F, 1.0F / 16.0F},
90 {2.0F / 16.0F, 4.0F / 16.0F, 2.0F / 16.0F},
91 {1.0F / 16.0F, 2.0F / 16.0F, 1.0F / 16.0F},
92 }};
93
94
2/2
✓ Branch 0 taken 948 times.
✓ Branch 1 taken 28 times.
976 for (int gi = global_row_start; gi < global_row_end; ++gi) {
95 948 const int local_i = gi - global_row_start;
96
2/2
✓ Branch 0 taken 150238 times.
✓ Branch 1 taken 948 times.
151186 for (int j = 0; j < width; ++j) {
97 150238 const int x0 = std::clamp(j - 1, 0, width - 1);
98 const int x1 = j;
99 150238 const int x2 = std::clamp(j + 1, 0, width - 1);
100
101 150238 const int y0 = std::clamp(gi - 1, 0, height - 1);
102 const int y1 = gi;
103 150238 const int y2 = std::clamp(gi + 1, 0, height - 1);
104
105 150238 const int y0_local = y0 - base_global_row;
106 150238 const int y1_local = y1 - base_global_row;
107 150238 const int y2_local = y2 - base_global_row;
108
109 float sum = 0.0F;
110
111 150238 sum += static_cast<float>(local_pixels[(y0_local * width) + x0]) * kernel[0][0];
112 150238 sum += static_cast<float>(local_pixels[(y0_local * width) + x1]) * kernel[0][1];
113 150238 sum += static_cast<float>(local_pixels[(y0_local * width) + x2]) * kernel[0][2];
114
115 150238 sum += static_cast<float>(local_pixels[(y1_local * width) + x0]) * kernel[1][0];
116 150238 sum += static_cast<float>(local_pixels[(y1_local * width) + x1]) * kernel[1][1];
117 150238 sum += static_cast<float>(local_pixels[(y1_local * width) + x2]) * kernel[1][2];
118
119 150238 sum += static_cast<float>(local_pixels[(y2_local * width) + x0]) * kernel[2][0];
120 150238 sum += static_cast<float>(local_pixels[(y2_local * width) + x1]) * kernel[2][1];
121 150238 sum += static_cast<float>(local_pixels[(y2_local * width) + x2]) * kernel[2][2];
122
123 150238 local_res[(local_i * width) + j] = static_cast<int>(std::round(sum));
124 }
125 }
126 28 }
127
128 } // namespace
129
130 28 bool BorunovVBlockPartitioningMPI::RunImpl() {
131 28 int size = 0;
132 28 int rank = 0;
133 28 MPI_Comm_size(MPI_COMM_WORLD, &size);
134 28 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
135
136 28 int width = 0;
137 28 int height = 0;
138
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 if (rank == 0) {
139 14 width = GetInput()[0];
140 14 height = GetInput()[1];
141 }
142 28 BroadcastDims(width, height);
143
144 28 std::vector<int> send_counts;
145 28 std::vector<int> displs;
146
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 ComputeSendCountsDispls(width, height, size, send_counts, displs);
147
148 28 std::vector<int> send_counts_halo;
149 28 std::vector<int> displs_halo;
150
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 ComputeSendCountsDisplsWithHalo(width, height, send_counts, displs, send_counts_halo, displs_halo);
151
152
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 const int local_pixels_count = send_counts_halo[rank];
153
3/6
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
28 std::vector<int> local_pixels(static_cast<std::size_t>(local_pixels_count));
154
155
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
28 MPI_Scatterv(rank == 0 ? (GetInput().data() + 2) : nullptr, send_counts_halo.data(), displs_halo.data(), MPI_INT,
156 local_pixels.data(), local_pixels_count, MPI_INT, 0, MPI_COMM_WORLD);
157
158
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 const int my_rows = send_counts[rank] / width;
159 28 const int row_start = displs[rank] / width;
160 28 const int row_end = row_start + my_rows;
161
162 28 const int base_global_row = displs_halo[rank] / width;
163
164
1/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
28 std::vector<int> local_res(static_cast<std::size_t>(my_rows) * static_cast<std::size_t>(width));
165 28 ApplyKernelToLocalPartition(local_pixels.data(), width, height, base_global_row, row_start, row_end, local_res);
166
167 28 const int local_count = static_cast<int>(local_res.size());
168
3/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
✓ Branch 3 taken 28 times.
✗ Branch 4 not taken.
42 MPI_Gatherv(local_res.data(), local_count, MPI_INT, rank == 0 ? GetOutput().data() : nullptr, send_counts.data(),
169 displs.data(), MPI_INT, 0, MPI_COMM_WORLD);
170
171 28 return true;
172 }
173
174 28 bool BorunovVBlockPartitioningMPI::PostProcessingImpl() {
175 28 int rank = 0;
176 28 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
177
178 28 int width = 0;
179 28 int height = 0;
180
181
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 if (rank == 0) {
182 14 width = GetInput()[0];
183 14 height = GetInput()[1];
184 }
185
186 28 MPI_Bcast(&width, 1, MPI_INT, 0, MPI_COMM_WORLD);
187 28 MPI_Bcast(&height, 1, MPI_INT, 0, MPI_COMM_WORLD);
188
189 28 const int total_pixels = width * height;
190
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
28 if (rank != 0) {
191 14 GetOutput().assign(static_cast<std::size_t>(total_pixels), 0);
192 }
193
194 28 MPI_Bcast(GetOutput().data(), total_pixels, MPI_INT, 0, MPI_COMM_WORLD);
195
196 28 return true;
197 }
198
199 } // namespace borunov_v_block_partitioning
200