GCC Code Coverage Report


Directory: ./
File: tasks/otcheskov_s_contrast_lin_stretch/all/src/ops_all.cpp
Date: 2026-06-04 20:25:32
Exec Total Coverage
Lines: 99 100 99.0%
Functions: 10 10 100.0%
Branches: 73 106 68.9%

Line Branch Exec Source
1 #include "otcheskov_s_contrast_lin_stretch/all/include/ops_all.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cstddef>
7 #include <cstdint>
8 #include <thread>
9 #include <vector>
10
11 #include "otcheskov_s_contrast_lin_stretch/common/include/common.hpp"
12 #include "util/include/util.hpp"
13
14 namespace otcheskov_s_contrast_lin_stretch {
15
16
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 OtcheskovSContrastLinStretchALL::OtcheskovSContrastLinStretchALL(const InType &in) {
17
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Comm_rank(MPI_COMM_WORLD, &rank_);
18
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 MPI_Comm_size(MPI_COMM_WORLD, &size_);
19 SetTypeOfTask(GetStaticTypeOfTask());
20 GetOutput().clear();
21
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank_ == 0) {
22
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 GetInput() = in;
23
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 GetOutput().resize(GetInput().size());
24 } else {
25 GetInput().clear();
26 GetInput().shrink_to_fit();
27 }
28 18 }
29
30 18 bool OtcheskovSContrastLinStretchALL::ValidationImpl() {
31
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank_ == 0) {
32 9 is_valid_ = !GetInput().empty();
33 }
34 18 MPI_Bcast(&is_valid_, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD);
35 18 return is_valid_;
36 }
37
38 18 bool OtcheskovSContrastLinStretchALL::PreProcessingImpl() {
39 18 return true;
40 }
41
42 18 bool OtcheskovSContrastLinStretchALL::RunImpl() {
43
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2 times.
18 if (!is_valid_) {
44 return false;
45 }
46
47 const InType &input = GetInput();
48 OutType &output = GetOutput();
49 16 int global_size = 0;
50
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (rank_ == 0) {
51 8 global_size = static_cast<int>(input.size());
52 }
53 16 MPI_Bcast(&global_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
54
55 16 std::vector<int> counts(size_);
56
1/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
16 std::vector<int> displs(size_);
57 16 int base = global_size / size_;
58 16 int rem = global_size % size_;
59
60
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 16 times.
48 for (int i = 0; i < size_; ++i) {
61
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 6 times.
58 counts[i] = base + (i < rem ? 1 : 0);
62 32 displs[i] = (i * base) + std::min(i, rem);
63 }
64
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 auto local_size = static_cast<size_t>(counts[rank_]);
65
1/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
16 std::vector<uint8_t> local_input(local_size);
66
3/6
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
16 std::vector<uint8_t> local_output(local_size);
67
68
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
24 MPI_Scatterv(rank_ == 0 ? input.data() : nullptr, counts.data(), displs.data(), MPI_UINT8_T, local_input.data(),
69 static_cast<int>(local_size), MPI_UINT8_T, 0, MPI_COMM_WORLD);
70
71
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 MinMax local = ComputeMinMax(local_input);
72
73 16 uint8_t global_min{};
74 16 uint8_t global_max{};
75
76
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 MPI_Allreduce(&local.min, &global_min, 1, MPI_UINT8_T, MPI_MIN, MPI_COMM_WORLD);
77
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 MPI_Allreduce(&local.max, &global_max, 1, MPI_UINT8_T, MPI_MAX, MPI_COMM_WORLD);
78
79
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 if (global_min == global_max) {
80
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 CopyInput(local_input, local_output);
81 } else {
82 10 int min_i = static_cast<int>(global_min);
83 10 int range = static_cast<int>(global_max) - min_i;
84
85
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 LinearStretch(local_input, local_output, min_i, range);
86 }
87
88
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
24 MPI_Gatherv(local_output.data(), static_cast<int>(local_size), MPI_UINT8_T, rank_ == 0 ? output.data() : nullptr,
89 counts.data(), displs.data(), MPI_UINT8_T, 0, MPI_COMM_WORLD);
90 return true;
91 }
92
93 18 bool OtcheskovSContrastLinStretchALL::PostProcessingImpl() {
94 18 return true;
95 }
96
97
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
16 OtcheskovSContrastLinStretchALL::MinMax OtcheskovSContrastLinStretchALL::ComputeMinMax(const InType &input) {
98
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 15 times.
16 if (input.empty()) {
99 1 return MinMax{};
100 }
101 15 const size_t size = input.size();
102 15 const size_t num_threads = std::min<size_t>(static_cast<size_t>(ppc::util::GetNumThreads()), size);
103
104 15 const size_t block = size / num_threads;
105 15 std::vector<MinMax> local(num_threads, {255, 0});
106
107 {
108 15 std::vector<std::jthread> threads;
109
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 threads.reserve(num_threads);
110
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 15 times.
44 for (size_t tid = 0; tid < num_threads; ++tid) {
111 29 size_t begin = tid * block;
112
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 15 times.
29 size_t end = (tid == num_threads - 1) ? size : begin + block;
113
114
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 threads.emplace_back([&, tid, begin, end]() {
115 29 auto [min, max] = std::ranges::minmax_element(input.begin() + static_cast<std::ptrdiff_t>(begin),
116 29 input.begin() + static_cast<std::ptrdiff_t>(end));
117 29 local[tid] = {.min = *min, .max = *max};
118 29 });
119 }
120 15 }
121
122 15 MinMax result{.min = 255, .max = 0};
123
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 15 times.
44 for (size_t tid = 0; tid < num_threads; ++tid) {
124 29 result.min = std::min(result.min, local[tid].min);
125 29 result.max = std::max(result.max, local[tid].max);
126 }
127
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 return result;
128 }
129
130
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 void OtcheskovSContrastLinStretchALL::CopyInput(const InType &input, OutType &output) {
131
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
6 if (input.empty()) {
132 1 return;
133 }
134 5 const size_t size = input.size();
135
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 const size_t num_threads = std::min<size_t>(static_cast<size_t>(ppc::util::GetNumThreads()), size);
136 5 const size_t block = size / num_threads;
137
138 5 std::vector<std::jthread> threads;
139
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 threads.reserve(num_threads);
140
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 5 times.
14 for (size_t tid = 0; tid < num_threads; ++tid) {
141 9 size_t begin = tid * block;
142
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 size_t end = (tid == num_threads - 1) ? size : begin + block;
143
144
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 threads.emplace_back([&, begin, end]() {
145
2/2
✓ Branch 0 taken 251102 times.
✓ Branch 1 taken 9 times.
251111 for (size_t i = begin; i < end; ++i) {
146 251102 output[i] = input[i];
147 }
148 });
149 }
150 5 }
151
152
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 void OtcheskovSContrastLinStretchALL::LinearStretch(const InType &input, OutType &output, int min_i, int range) {
153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (input.empty()) {
154 return;
155 }
156 10 const size_t size = input.size();
157
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 const size_t num_threads = std::min<size_t>(static_cast<size_t>(ppc::util::GetNumThreads()), size);
158 10 const size_t block = size / num_threads;
159
160 10 std::vector<std::jthread> threads;
161
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 threads.reserve(num_threads);
162
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10 times.
30 for (size_t tid = 0; tid < num_threads; ++tid) {
163 20 size_t begin = tid * block;
164
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 size_t end = (tid == num_threads - 1) ? size : begin + block;
165
166
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 threads.emplace_back([&, begin, end, min_i, range]() {
167
2/2
✓ Branch 0 taken 410013 times.
✓ Branch 1 taken 20 times.
410033 for (size_t i = begin; i < end; ++i) {
168 410013 int pixel = static_cast<int>(input[i]);
169 410013 int value = (pixel - min_i) * 255 / (range);
170 value = std::clamp(value, 0, 255);
171 410013 output[i] = static_cast<uint8_t>(value);
172 }
173 20 });
174 }
175 10 }
176
177 } // namespace otcheskov_s_contrast_lin_stretch
178