GCC Code Coverage Report


Directory: ./
File: tasks/chaschin_v_sobel_operator/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 107 107 100.0%
Functions: 7 7 100.0%
Branches: 58 86 67.4%

Line Branch Exec Source
1 #include "chaschin_v_sobel_operator/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cmath>
7 #include <cstddef>
8 #include <tuple>
9 #include <utility>
10 #include <vector>
11
12 #include "chaschin_v_sobel_operator/common/include/common.hpp"
13
14 namespace chaschin_v_sobel_operator {
15
16
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 ChaschinVSobelOperatorMPI::ChaschinVSobelOperatorMPI(const InType &in) {
17 SetTypeOfTask(GetStaticTypeOfTask());
18 auto in_copy = in;
19
20 GetInput() = std::move(in_copy);
21 GetOutput().clear();
22
23 38 int height = std::get<1>(in);
24 38 int width = std::get<2>(in);
25
26 Size_ = std::make_tuple(height, width);
27 38 }
28
29 38 bool ChaschinVSobelOperatorMPI::ValidationImpl() {
30 const auto &in = GetInput();
31
32 const auto &image = std::get<0>(in);
33
34 38 return !image.empty();
35 }
36
37 19 std::vector<float> ChaschinVSobelOperatorMPI::PreprocessToGrayscaleWithOverlap(
38 const std::vector<std::vector<Pixel>> &image, int n_procs, std::vector<int> &sendcounts, std::vector<int> &displs) {
39 19 int n = static_cast<int>(image.size());
40 19 int m = static_cast<int>(image[0].size());
41
42 19 int padded_m = m + 2;
43
44 19 sendcounts.resize(n_procs);
45 19 displs.resize(n_procs, 0);
46 19 int base = n / n_procs;
47 19 int rem = n % n_procs;
48
49 int total_real_rows = 0;
50 19 std::vector<int> l_r(n_procs + 2, 0);
51
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 19 times.
57 for (int rank = 0; rank < n_procs; ++rank) {
52 38 bool local_tale = (rank < rem);
53 38 int local_rows = (base + 2) + static_cast<int>(local_tale);
54 38 sendcounts[rank] = (local_rows)*padded_m;
55 38 displs[rank] = total_real_rows * padded_m;
56 38 total_real_rows += local_rows;
57 }
58
59
1/4
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
19 std::vector<float> buffer((n + 2 + (static_cast<size_t>(n_procs) - 1) * 2) * static_cast<size_t>(padded_m), 0.0F);
60
61
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 19 times.
76 for (int rank = 0; rank < n_procs + 1; ++rank) {
62 57 bool local_tale = (rank < rem);
63 57 l_r[rank + 1] = l_r[rank] + (base) + static_cast<int>(local_tale);
64 }
65
66
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 19 times.
57 for (int ii = 0; ii < n_procs; ii++) {
67
2/2
✓ Branch 0 taken 440 times.
✓ Branch 1 taken 38 times.
478 for (int xx = -1; xx < (sendcounts[ii] / padded_m) - 1; xx++) {
68
2/2
✓ Branch 0 taken 10540 times.
✓ Branch 1 taken 440 times.
10980 for (int yy = 0; yy < m; yy++) {
69 float val = 0.0F;
70
4/4
✓ Branch 0 taken 10176 times.
✓ Branch 1 taken 364 times.
✓ Branch 2 taken 9812 times.
✓ Branch 3 taken 364 times.
10540 if ((xx + l_r[ii] >= 0) && (xx + l_r[ii] < n)) {
71 9812 const Pixel &p = image[xx + l_r[ii]][yy];
72 9812 val = (0.299F * static_cast<float>(p.r)) + (0.587F * static_cast<float>(p.g)) +
73 9812 (0.114F * static_cast<float>((p.b)));
74 }
75 10540 buffer[displs[ii] + ((xx + 1) * padded_m) + yy + 1] = val;
76 }
77 }
78 }
79 19 return buffer;
80 }
81
82 38 bool ChaschinVSobelOperatorMPI::PreProcessingImpl() {
83 const auto &in = GetInput();
84
85 38 int rank = 0;
86 38 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
87
88
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 19 times.
38 if (rank == 0) {
89 const auto &image = std::get<0>(in);
90
91 19 int n_procs = 0;
92 19 MPI_Comm_size(MPI_COMM_WORLD, &n_procs);
93
94 19 std::vector<int> sendcounts;
95 19 std::vector<int> displs;
96
97
1/4
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
19 PreProcessGray_ = PreprocessToGrayscaleWithOverlap(image, n_procs, sendcounts, displs);
98
99
1/2
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
19 ScatterSendCounts_ = sendcounts;
100
1/2
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
19 ScatterDispls_ = displs;
101 }
102
103 38 return true;
104 }
105
106 9084 float ChaschinVSobelOperatorMPI::SobelAt(const std::vector<float> &img, int i, int j, int stride) {
107 9084 std::vector<float> k_kx = {-1.0F, 0.0F, 1.0F, -2.0F, 0.0F, 2.0F, -1.0F, 0.0F, 1.0F};
108
1/4
✓ Branch 1 taken 9084 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9084 std::vector<float> k_ky = {-1.0F, -2.0F, -1.0F, 0.0F, 0.0F, 0.0F, 1.0F, 2.0F, 1.0F};
109
110 float gx = 0.0F;
111 float gy = 0.0F;
112
113
2/2
✓ Branch 0 taken 27252 times.
✓ Branch 1 taken 9084 times.
36336 for (int di = -1; di <= 1; ++di) {
114 27252 int ni = i + di;
115
2/2
✓ Branch 0 taken 81756 times.
✓ Branch 1 taken 27252 times.
109008 for (int dj = -1; dj <= 1; ++dj) {
116 81756 int nj = j + dj;
117 81756 auto idx = (static_cast<size_t>(di + 1) * static_cast<size_t>(3)) + static_cast<size_t>(dj + 1);
118
119 81756 float val = img[(static_cast<size_t>(ni) * stride) + static_cast<size_t>(nj)];
120 81756 gx += val * k_kx[idx];
121 81756 gy += val * k_ky[idx];
122 }
123 }
124
125
1/2
✓ Branch 0 taken 9084 times.
✗ Branch 1 not taken.
18168 return std::sqrt((gx * gx) + (gy * gy));
126 }
127
128 38 bool ChaschinVSobelOperatorMPI::RunImpl() {
129 38 int rank = 0;
130 38 int size = 0;
131 38 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
132 38 MPI_Comm_size(MPI_COMM_WORLD, &size);
133
134 38 int n = std::get<0>(Size_);
135 38 int m = std::get<1>(Size_);
136
137 const auto &in = PreProcessGray_;
138
139 38 int base = n / size;
140 38 int rem = n % size;
141 38 int padded_m = m + 2;
142
143
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 19 times.
38 if (rank != 0) {
144 19 ScatterSendCounts_.resize(size);
145 }
146
147 38 MPI_Bcast(ScatterSendCounts_.data(), size, MPI_INT, 0, MPI_COMM_WORLD);
148
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 int recvcount = ScatterSendCounts_[rank];
149 38 int local_rows = recvcount / padded_m;
150 38 std::vector<float> local_block;
151
1/2
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
38 local_block.resize(recvcount);
152
153
3/4
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 19 times.
✓ Branch 3 taken 38 times.
✗ Branch 4 not taken.
57 MPI_Scatterv(rank == 0 ? in.data() : nullptr, ScatterSendCounts_.data(), ScatterDispls_.data(), MPI_FLOAT,
154 local_block.data(), recvcount, MPI_FLOAT, 0, MPI_COMM_WORLD);
155
156
1/4
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
38 std::vector<float> local_output(static_cast<size_t>(local_rows - 2) * static_cast<size_t>(m));
157
158
2/2
✓ Branch 0 taken 364 times.
✓ Branch 1 taken 38 times.
402 for (int i = 1; i <= local_rows - 2; ++i) {
159
2/2
✓ Branch 0 taken 9084 times.
✓ Branch 1 taken 364 times.
9448 for (int j = 1; j <= m; ++j) {
160
1/2
✓ Branch 1 taken 9084 times.
✗ Branch 2 not taken.
9084 local_output[((i - 1) * m) + (j - 1)] = SobelAt(local_block, i, j, padded_m);
161 }
162 }
163
164
1/4
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
38 std::vector<int> recvcounts(size);
165
1/4
✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
38 std::vector<int> displs_out(size);
166 int offset_res = 0;
167
2/2
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 38 times.
114 for (int pp = 0; pp < size; ++pp) {
168
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 32 times.
76 int rows_p = base + (pp < rem ? 1 : 0);
169 76 recvcounts[pp] = rows_p * m;
170 76 displs_out[pp] = offset_res;
171 76 offset_res += recvcounts[pp];
172 }
173
174
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 19 times.
38 if (rank == 0) {
175
1/2
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
19 PostProcessGray_.resize(static_cast<size_t>(n) * static_cast<size_t>(m));
176 }
177
178
3/4
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 19 times.
✓ Branch 3 taken 38 times.
✗ Branch 4 not taken.
57 MPI_Gatherv(local_output.data(), (local_rows - 2) * m, MPI_FLOAT, rank == 0 ? PostProcessGray_.data() : nullptr,
179 recvcounts.data(), displs_out.data(), MPI_FLOAT, 0, MPI_COMM_WORLD);
180
181 38 return true;
182 }
183
184 38 bool ChaschinVSobelOperatorMPI::PostProcessingImpl() {
185 38 int rank = 0;
186 38 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
187
188 auto &out = GetOutput();
189 38 int n = std::get<0>(Size_);
190 38 int m = std::get<1>(Size_);
191
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 19 times.
38 if (rank != 0) {
192 19 PostProcessGray_.resize(static_cast<size_t>(n) * static_cast<size_t>(m));
193 }
194
195 38 MPI_Bcast(PostProcessGray_.data(), n * m, MPI_FLOAT, 0, MPI_COMM_WORLD);
196
197 38 out.resize(n);
198
199
2/2
✓ Branch 0 taken 728 times.
✓ Branch 1 taken 38 times.
766 for (int i = 0; i < n; ++i) {
200 728 out[i].resize(m);
201
2/2
✓ Branch 0 taken 18168 times.
✓ Branch 1 taken 728 times.
18896 for (int j = 0; j < m; ++j) {
202 18168 float v = PostProcessGray_[(i * m) + j];
203 18168 unsigned char c = static_cast<unsigned char>(std::clamp(v, 0.0F, 255.0F));
204 18168 out[i][j] = Pixel{.r = c, .g = c, .b = c};
205 }
206 }
207
208 38 return true;
209 }
210
211 } // namespace chaschin_v_sobel_operator
212