GCC Code Coverage Report


Directory: ./
File: tasks/frolova_s_radix_sort_double/omp/src/ops_omp.cpp
Date: 2026-04-02 17:12:27
Exec Total Coverage
Lines: 51 57 89.5%
Functions: 7 7 100.0%
Branches: 35 62 56.5%

Line Branch Exec Source
1 #include "frolova_s_radix_sort_double/omp/include/ops_omp.hpp"
2
3 #include <omp.h>
4
5 #include <algorithm>
6 #include <bit>
7 #include <cstddef>
8 #include <cstdint>
9 #include <utility>
10 #include <vector>
11
12 #include "frolova_s_radix_sort_double/common/include/common.hpp"
13
14 namespace frolova_s_radix_sort_double {
15
16 namespace {
17
18 40 void RadixSortChunk(std::vector<double> &chunk) {
19 const int radix = 256;
20 const int num_bits = 8;
21 const int num_passes = sizeof(uint64_t);
22
23 40 std::vector<double> temp(chunk.size());
24
25
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 40 times.
360 for (int pass = 0; pass < num_passes; pass++) {
26
1/4
✓ Branch 1 taken 320 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
320 std::vector<int> count(radix, 0);
27
2/2
✓ Branch 0 taken 133120 times.
✓ Branch 1 taken 320 times.
133440 for (double value : chunk) {
28 auto bits = std::bit_cast<uint64_t>(value);
29 133120 int byte = static_cast<int>((bits >> (pass * num_bits)) & 0xFF);
30 133120 count[byte]++;
31 }
32 int total = 0;
33
2/2
✓ Branch 0 taken 81920 times.
✓ Branch 1 taken 320 times.
82240 for (int i = 0; i < radix; i++) {
34 81920 int old = count[i];
35 81920 count[i] = total;
36 81920 total += old;
37 }
38
2/2
✓ Branch 0 taken 133120 times.
✓ Branch 1 taken 320 times.
133440 for (double value : chunk) {
39 auto bits = std::bit_cast<uint64_t>(value);
40 133120 int byte = static_cast<int>((bits >> (pass * num_bits)) & 0xFF);
41 133120 temp[count[byte]++] = value;
42 }
43 chunk.swap(temp);
44 }
45 40 }
46
47 40 void ProcessChunk(std::vector<double> &chunk) {
48 40 RadixSortChunk(chunk);
49
50 40 std::vector<double> negative;
51
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 std::vector<double> positive;
52
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 negative.reserve(chunk.size());
53
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 positive.reserve(chunk.size());
54
55
4/4
✓ Branch 0 taken 3964 times.
✓ Branch 1 taken 12676 times.
✓ Branch 2 taken 16640 times.
✓ Branch 3 taken 40 times.
16680 for (double val : chunk) {
56
2/2
✓ Branch 0 taken 3964 times.
✓ Branch 1 taken 12676 times.
16640 if ((std::bit_cast<uint64_t>(val) >> 63) != 0U) {
57 negative.push_back(val);
58 } else {
59 positive.push_back(val);
60 }
61 }
62
63 std::ranges::reverse(negative);
64
65 size_t pos = 0;
66
2/2
✓ Branch 0 taken 3964 times.
✓ Branch 1 taken 40 times.
4004 for (double val : negative) {
67 3964 chunk[pos++] = val;
68 }
69
2/2
✓ Branch 0 taken 12676 times.
✓ Branch 1 taken 40 times.
12716 for (double val : positive) {
70 12676 chunk[pos++] = val;
71 }
72 40 }
73
74 } // namespace
75
76
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 FrolovaSRadixSortDoubleOMP::FrolovaSRadixSortDoubleOMP(const InType &in) {
77 SetTypeOfTask(GetStaticTypeOfTask());
78
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 GetInput() = in;
79 40 }
80
81 40 bool FrolovaSRadixSortDoubleOMP::ValidationImpl() {
82 40 return !GetInput().empty();
83 }
84
85 40 bool FrolovaSRadixSortDoubleOMP::PreProcessingImpl() {
86 40 return true;
87 }
88
89
1/2
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
40 bool FrolovaSRadixSortDoubleOMP::RunImpl() {
90 const std::vector<double> &input = GetInput();
91
1/2
✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
40 if (input.empty()) {
92 return false;
93 }
94
95 size_t n = input.size();
96 40 std::vector<double> working = input;
97
98 40 int max_threads = omp_get_max_threads();
99
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 int num_threads_to_use = std::min(max_threads, std::max(1, static_cast<int>(n / 10000)));
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (num_threads_to_use == 0) {
101 num_threads_to_use = 1;
102 }
103
104
1/4
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
40 std::vector<size_t> chunk_sizes(num_threads_to_use, n / num_threads_to_use);
105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 for (size_t i = 0; i < n % static_cast<size_t>(num_threads_to_use); i++) {
106 chunk_sizes[i]++;
107 }
108
109
1/4
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
40 std::vector<size_t> chunk_offsets(num_threads_to_use, 0);
110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 for (int i = 1; i < num_threads_to_use; i++) {
111 chunk_offsets[i] = chunk_offsets[i - 1] + chunk_sizes[i - 1];
112 }
113
114 40 #pragma omp parallel num_threads(num_threads_to_use) default(none) \
115 shared(working, chunk_sizes, chunk_offsets, num_threads_to_use)
116 {
117 int tid = omp_get_thread_num();
118 if (tid < num_threads_to_use) {
119 size_t offset = chunk_offsets[tid];
120 size_t size = chunk_sizes[tid];
121
122 std::vector<double> chunk(working.begin() + static_cast<ptrdiff_t>(offset),
123 working.begin() + static_cast<ptrdiff_t>(offset + size));
124
125 ProcessChunk(chunk);
126
127 for (size_t i = 0; i < size; ++i) {
128 working[offset + i] = chunk[i];
129 }
130 }
131 }
132
133
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 std::vector<double> merged_result;
134
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 merged_result.assign(working.begin(), working.begin() + static_cast<ptrdiff_t>(chunk_sizes[0]));
135
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 for (int i = 1; i < num_threads_to_use; i++) {
137 std::vector<double> merged(merged_result.size() + chunk_sizes[i]);
138 auto next_chunk_begin = working.begin() + static_cast<ptrdiff_t>(chunk_offsets[i]);
139 auto next_chunk_end = next_chunk_begin + static_cast<ptrdiff_t>(chunk_sizes[i]);
140 std::merge(merged_result.begin(), merged_result.end(), next_chunk_begin, next_chunk_end, merged.begin());
141
142 merged_result = std::move(merged);
143 }
144
145 GetOutput() = std::move(merged_result);
146 return true;
147 }
148
149 40 bool FrolovaSRadixSortDoubleOMP::PostProcessingImpl() {
150 40 return true;
151 }
152
153 } // namespace frolova_s_radix_sort_double
154