GCC Code Coverage Report


Directory: ./
File: tasks/balchunayte_z_sobel/all/src/ops_all.cpp
Date: 2026-06-04 20:25:32
Exec Total Coverage
Lines: 72 75 96.0%
Functions: 7 7 100.0%
Branches: 20 32 62.5%

Line Branch Exec Source
1 #include "balchunayte_z_sobel/all/include/ops_all.hpp"
2
3 #include <mpi.h>
4 #include <omp.h>
5
6 #include <algorithm>
7 #include <cstddef>
8 #include <cstdlib>
9 #include <functional>
10 #include <thread>
11 #include <vector>
12
13 #include "balchunayte_z_sobel/common/include/common.hpp"
14 #include "oneapi/tbb/parallel_for.h"
15 #include "util/include/util.hpp"
16
17 namespace balchunayte_z_sobel {
18
19 namespace {
20
21 int ConvertPixelToGray(const Pixel &pixel_value) {
22 24 return (77 * static_cast<int>(pixel_value.r) + 150 * static_cast<int>(pixel_value.g) +
23 24 29 * static_cast<int>(pixel_value.b)) >>
24 24 8;
25 }
26
27 12 void ProcessRows(const Image &input_image, std::vector<int> &output_data, int row_begin, int row_end) {
28 12 const int image_width = input_image.width;
29 12 const auto image_width_size = static_cast<size_t>(image_width);
30
31
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (int row_index = row_begin; row_index < row_end; ++row_index) {
32
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 for (int col_index = 1; col_index < image_width - 1; ++col_index) {
33 24 const size_t index_top_left =
34 24 (static_cast<size_t>(row_index - 1) * image_width_size) + static_cast<size_t>(col_index - 1);
35 24 const size_t index_top_middle =
36 24 (static_cast<size_t>(row_index - 1) * image_width_size) + static_cast<size_t>(col_index);
37 24 const size_t index_top_right =
38 24 (static_cast<size_t>(row_index - 1) * image_width_size) + static_cast<size_t>(col_index + 1);
39
40 24 const size_t index_middle_left =
41 24 (static_cast<size_t>(row_index) * image_width_size) + static_cast<size_t>(col_index - 1);
42 24 const size_t index_middle_right =
43 (static_cast<size_t>(row_index) * image_width_size) + static_cast<size_t>(col_index + 1);
44
45 24 const size_t index_bottom_left =
46 24 (static_cast<size_t>(row_index + 1) * image_width_size) + static_cast<size_t>(col_index - 1);
47 24 const size_t index_bottom_middle =
48 (static_cast<size_t>(row_index + 1) * image_width_size) + static_cast<size_t>(col_index);
49 24 const size_t index_bottom_right =
50 (static_cast<size_t>(row_index + 1) * image_width_size) + static_cast<size_t>(col_index + 1);
51
52 const int gray_top_left = ConvertPixelToGray(input_image.data[index_top_left]);
53 const int gray_top_middle = ConvertPixelToGray(input_image.data[index_top_middle]);
54 const int gray_top_right = ConvertPixelToGray(input_image.data[index_top_right]);
55
56 const int gray_middle_left = ConvertPixelToGray(input_image.data[index_middle_left]);
57 const int gray_middle_right = ConvertPixelToGray(input_image.data[index_middle_right]);
58
59 const int gray_bottom_left = ConvertPixelToGray(input_image.data[index_bottom_left]);
60 const int gray_bottom_middle = ConvertPixelToGray(input_image.data[index_bottom_middle]);
61 const int gray_bottom_right = ConvertPixelToGray(input_image.data[index_bottom_right]);
62
63 24 const int gradient_x = (-gray_top_left + gray_top_right) + (-2 * gray_middle_left + (2 * gray_middle_right)) +
64 24 (-gray_bottom_left + gray_bottom_right);
65
66 24 const int gradient_y = (gray_top_left + (2 * gray_top_middle) + gray_top_right) +
67 24 (-gray_bottom_left - (2 * gray_bottom_middle) - gray_bottom_right);
68
69 24 const int magnitude = std::abs(gradient_x) + std::abs(gradient_y);
70
71 24 const size_t output_index = (static_cast<size_t>(row_index) * image_width_size) + static_cast<size_t>(col_index);
72 24 output_data[output_index] = magnitude;
73 }
74 }
75 12 }
76
77 void ProcessRowsOMP(const Image &input_image, std::vector<int> &output_data, int row_begin, int row_end) {
78 6 #pragma omp parallel for default(none) shared(input_image, output_data, row_begin, row_end) schedule(static)
79 for (int row_index = row_begin; row_index < row_end; ++row_index) {
80 ProcessRows(input_image, output_data, row_index, row_index + 1);
81 }
82 }
83
84 void ProcessRowsTBB(const Image &input_image, std::vector<int> &output_data, int row_begin, int row_end) {
85 6 oneapi::tbb::parallel_for(row_begin, row_end, [&input_image, &output_data](int row_index) {
86 6 ProcessRows(input_image, output_data, row_index, row_index + 1);
87 });
88 }
89
90 6 void ProcessRowsSTL(const Image &input_image, std::vector<int> &output_data, int row_begin, int row_end) {
91 6 const int local_row_count = row_end - row_begin;
92
93
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (local_row_count <= 0) {
94 return;
95 }
96
97
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 const int requested_thread_count = std::max(1, ppc::util::GetNumThreads());
98 const int actual_thread_count = std::min(requested_thread_count, local_row_count);
99
100 6 std::vector<std::thread> worker_threads;
101
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 worker_threads.reserve(static_cast<size_t>(actual_thread_count));
102
103 6 const int rows_per_thread = local_row_count / actual_thread_count;
104 6 const int remaining_rows = local_row_count % actual_thread_count;
105
106 6 int start_row_index = row_begin;
107
108
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (int thread_index = 0; thread_index < actual_thread_count; ++thread_index) {
109 6 const int extra_row_count = static_cast<int>(thread_index < remaining_rows);
110 6 const int end_row_index = start_row_index + rows_per_thread + extra_row_count;
111
112
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 worker_threads.emplace_back(ProcessRows, std::cref(input_image), std::ref(output_data), start_row_index,
113 end_row_index);
114
115 6 start_row_index = end_row_index;
116 }
117
118
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (auto &worker_thread : worker_threads) {
119
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 worker_thread.join();
120 }
121 6 }
122
123 } // namespace
124
125
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 BalchunayteZSobelOpALL::BalchunayteZSobelOpALL(const InType &input_image) {
126 SetTypeOfTask(GetStaticTypeOfTask());
127 GetInput() = input_image;
128 GetOutput().clear();
129 6 }
130
131 6 bool BalchunayteZSobelOpALL::ValidationImpl() {
132 const auto &input_image = GetInput();
133
134
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 if (input_image.width <= 0 || input_image.height <= 0) {
135 return false;
136 }
137
138
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 const auto expected_size = static_cast<size_t>(input_image.width) * static_cast<size_t>(input_image.height);
139
140
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (input_image.data.size() != expected_size) {
141 return false;
142 }
143
144 6 return GetOutput().empty();
145 }
146
147 6 bool BalchunayteZSobelOpALL::PreProcessingImpl() {
148 const auto &input_image = GetInput();
149 6 GetOutput().assign(static_cast<size_t>(input_image.width) * static_cast<size_t>(input_image.height), 0);
150 6 return true;
151 }
152
153 6 bool BalchunayteZSobelOpALL::RunImpl() {
154 6 int rank = -1;
155 6 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
156
157 const auto &input_image = GetInput();
158 auto &output_data = GetOutput();
159
160
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (input_image.width < 3 || input_image.height < 3) {
161 MPI_Barrier(MPI_COMM_WORLD);
162 return rank >= 0;
163 }
164
165 const int first_inner_row = 1;
166 6 const int last_inner_row = input_image.height - 1;
167 6 const int inner_row_count = last_inner_row - first_inner_row;
168
169 6 const int first_border = first_inner_row + (inner_row_count / 3);
170 6 const int second_border = first_inner_row + ((2 * inner_row_count) / 3);
171
172 ProcessRowsOMP(input_image, output_data, first_inner_row, first_border);
173 6 ProcessRowsSTL(input_image, output_data, first_border, second_border);
174 ProcessRowsTBB(input_image, output_data, second_border, last_inner_row);
175
176 6 MPI_Barrier(MPI_COMM_WORLD);
177
178 6 return rank >= 0;
179 }
180
181 6 bool BalchunayteZSobelOpALL::PostProcessingImpl() {
182 6 return true;
183 }
184
185 } // namespace balchunayte_z_sobel
186