GCC Code Coverage Report


Directory: ./
File: tasks/dorogin_v_bitwise_simple_merge/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 98 100 98.0%
Functions: 9 9 100.0%
Branches: 71 102 69.6%

Line Branch Exec Source
1 #include "dorogin_v_bitwise_simple_merge/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cstdint>
7 #include <cstring>
8 #include <vector>
9
10 #include "dorogin_v_bitwise_simple_merge/common/include/common.hpp"
11
12 namespace dorogin_v_bitwise_simple_merge {
13
14 namespace {
15
16 uint64_t DoubleToSortableKey(double value) {
17 uint64_t bits = 0;
18 std::memcpy(&bits, &value, sizeof(double));
19
2/2
✓ Branch 0 taken 821 times.
✓ Branch 1 taken 779 times.
1600 if ((bits >> 63) != 0) {
20 821 bits = ~bits;
21 } else {
22 779 bits ^= (static_cast<uint64_t>(1) << 63);
23 }
24 return bits;
25 }
26
27 double SortableKeyToDouble(uint64_t bits) {
28 1600 if ((bits >> 63) != 0) {
29 779 bits ^= (static_cast<uint64_t>(1) << 63);
30 } else {
31 821 bits = ~bits;
32 }
33 double value = 0;
34 std::memcpy(&value, &bits, sizeof(double));
35 return value;
36 }
37
38
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 void RadixSort(std::vector<double> &data) {
39
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (data.size() <= 1) {
40 return;
41 }
42
43 6 std::vector<uint64_t> keys(data.size());
44
2/2
✓ Branch 0 taken 1600 times.
✓ Branch 1 taken 6 times.
1606 for (size_t i = 0; i < data.size(); i++) {
45
2/2
✓ Branch 0 taken 821 times.
✓ Branch 1 taken 779 times.
3200 keys[i] = DoubleToSortableKey(data[i]);
46 }
47
48
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<uint64_t> temp(data.size());
49
50
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 6 times.
54 for (int shift = 0; shift < 64; shift += 8) {
51
1/4
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
48 std::vector<size_t> count(257, 0);
52
53
2/2
✓ Branch 0 taken 12800 times.
✓ Branch 1 taken 48 times.
12848 for (const auto &key : keys) {
54 12800 size_t bucket = (key >> shift) & 0xFF;
55 12800 count[bucket + 1]++;
56 }
57
58
2/2
✓ Branch 0 taken 12288 times.
✓ Branch 1 taken 48 times.
12336 for (int i = 1; i <= 256; i++) {
59 12288 count[i] += count[i - 1];
60 }
61
62
2/2
✓ Branch 0 taken 12800 times.
✓ Branch 1 taken 48 times.
12848 for (const auto &key : keys) {
63 12800 size_t bucket = (key >> shift) & 0xFF;
64 12800 temp[count[bucket]++] = key;
65 }
66
67 std::swap(keys, temp);
68 }
69
70
2/2
✓ Branch 0 taken 1600 times.
✓ Branch 1 taken 6 times.
1606 for (size_t i = 0; i < data.size(); i++) {
71
2/2
✓ Branch 0 taken 779 times.
✓ Branch 1 taken 821 times.
3200 data[i] = SortableKeyToDouble(keys[i]);
72 }
73 }
74
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 void SimpleMerge(const std::vector<double> &left, const std::vector<double> &right, std::vector<double> &result) {
76 result.clear();
77 3 result.reserve(left.size() + right.size());
78 size_t i = 0;
79 size_t j = 0;
80
4/4
✓ Branch 0 taken 1597 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1595 times.
1598 while (i < left.size() && j < right.size()) {
81
2/2
✓ Branch 0 taken 796 times.
✓ Branch 1 taken 799 times.
1595 if (left[i] <= right[j]) {
82 result.push_back(left[i]);
83 796 i++;
84 } else {
85 result.push_back(right[j]);
86 799 j++;
87 }
88 }
89
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
7 while (i < left.size()) {
90 result.push_back(left[i]);
91 4 i++;
92 }
93
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 while (j < right.size()) {
94 result.push_back(right[j]);
95 1 j++;
96 }
97 3 }
98
99 6 void DistributeData(const std::vector<double> &input_data, std::vector<double> &local_data,
100 const std::vector<int> &send_counts, const std::vector<int> &displs, int rank, int size) {
101 6 int local_size = send_counts[rank];
102 6 local_data.resize(local_size);
103
104
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank == 0) {
105
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (int proc = 1; proc < size; proc++) {
106
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (send_counts[proc] > 0) {
107 3 MPI_Send(&input_data[displs[proc]], send_counts[proc], MPI_DOUBLE, proc, 0, MPI_COMM_WORLD);
108 }
109 }
110
2/2
✓ Branch 0 taken 800 times.
✓ Branch 1 taken 3 times.
803 for (int i = 0; i < local_size; i++) {
111 800 local_data[i] = input_data[i];
112 }
113 } else {
114
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (local_size > 0) {
115 3 MPI_Recv(local_data.data(), local_size, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
116 }
117 }
118 6 }
119
120 6 void GatherAndMerge(std::vector<double> &output_data, std::vector<double> &local_data,
121 const std::vector<int> &send_counts, int rank, int size) {
122
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank == 0) {
123 3 output_data = local_data;
124 3 std::vector<double> temp_result;
125
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (int proc = 1; proc < size; proc++) {
126
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (send_counts[proc] > 0) {
127
2/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 std::vector<double> recv_data(send_counts[proc]);
128
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 MPI_Recv(recv_data.data(), send_counts[proc], MPI_DOUBLE, proc, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
129
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 SimpleMerge(output_data, recv_data, temp_result);
130 output_data.swap(temp_result);
131 }
132 }
133 } else {
134 3 int local_size = static_cast<int>(local_data.size());
135
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (local_size > 0) {
136 3 MPI_Send(local_data.data(), local_size, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD);
137 }
138 }
139 6 }
140
141 } // namespace
142
143
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 DoroginVBitwiseSimpleMergeMPI::DoroginVBitwiseSimpleMergeMPI(const InType &in) {
144 SetTypeOfTask(GetStaticTypeOfTask());
145
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GetInput() = in;
146 GetOutput() = {};
147 6 }
148
149 6 bool DoroginVBitwiseSimpleMergeMPI::ValidationImpl() {
150 6 return true;
151 }
152
153 6 bool DoroginVBitwiseSimpleMergeMPI::PreProcessingImpl() {
154 6 int rank = 0;
155 6 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
156
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank == 0) {
157 3 input_data_ = GetInput();
158 }
159 output_data_.clear();
160 6 return true;
161 }
162
163 6 bool DoroginVBitwiseSimpleMergeMPI::RunImpl() {
164 6 int rank = 0;
165 6 int size = 0;
166 6 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
167 6 MPI_Comm_size(MPI_COMM_WORLD, &size);
168
169 6 int total_size = 0;
170
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (rank == 0) {
171 3 total_size = static_cast<int>(input_data_.size());
172 }
173 6 MPI_Bcast(&total_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
174
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (total_size == 0) {
176 output_data_.clear();
177 return true;
178 }
179
180 6 int base_chunk = total_size / size;
181 6 int remainder = total_size % size;
182
183 6 std::vector<int> send_counts(size);
184
1/4
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 std::vector<int> displs(size);
185
186
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int i = 0; i < size; i++) {
187
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 send_counts[i] = base_chunk + static_cast<int>(i < remainder);
188
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 displs[i] = (i == 0) ? 0 : (displs[i - 1] + send_counts[i - 1]);
189 }
190
191 6 std::vector<double> local_data;
192
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 DistributeData(input_data_, local_data, send_counts, displs, rank, size);
193
194
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 RadixSort(local_data);
195
196
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GatherAndMerge(output_data_, local_data, send_counts, rank, size);
197
198
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 output_data_.resize(static_cast<size_t>(total_size));
199
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (total_size > 0) {
200
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Bcast(output_data_.data(), total_size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
201 }
202
203 return true;
204 }
205
206 6 bool DoroginVBitwiseSimpleMergeMPI::PostProcessingImpl() {
207 6 GetOutput() = output_data_;
208 6 return true;
209 }
210
211 } // namespace dorogin_v_bitwise_simple_merge
212