GCC Code Coverage Report


Directory: ./
File: tasks/ovchinnikov_m_bubble_sort/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 87 87 100.0%
Functions: 9 9 100.0%
Branches: 72 98 73.5%

Line Branch Exec Source
1 #include "ovchinnikov_m_bubble_sort/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cstddef>
7 #include <vector>
8
9 #include "ovchinnikov_m_bubble_sort/common/include/common.hpp"
10
11 namespace ovchinnikov_m_bubble_sort {
12
13 namespace {
14
15
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
12 void SortOddEven(std::vector<int> &array) {
16
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
12 if (array.empty()) {
17 return;
18 }
19 bool sorted = false;
20
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 11 times.
28 while (!sorted) {
21 sorted = true;
22
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 17 times.
40 for (size_t i = 0; i + 1 < array.size(); i += 2) {
23
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18 times.
23 if (array[i] > array[i + 1]) {
24 std::swap(array[i], array[i + 1]);
25 sorted = false;
26 }
27 }
28
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 17 times.
35 for (size_t i = 1; i + 1 < array.size(); i += 2) {
29
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 11 times.
18 if (array[i] > array[i + 1]) {
30 std::swap(array[i], array[i + 1]);
31 sorted = false;
32 }
33 }
34 }
35 }
36
37 int FindPartner(int rank, int phase) {
38 int partner = 0;
39
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 if (phase % 2 == 0) {
40
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank % 2 == 0) {
41 12 partner = rank + 1;
42 } else {
43 12 partner = rank - 1;
44 }
45 } else {
46
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank % 2 == 0) {
47 6 partner = rank - 1;
48 } else {
49 6 partner = rank + 1;
50 }
51 }
52 return partner;
53 }
54
55 24 std::vector<int> SwapDataWithPartner(int partner, const std::vector<int> &local_data) {
56 // Exchange sizes first
57 24 int my_size = static_cast<int>(local_data.size());
58 24 int partner_size = 0;
59
60 24 MPI_Sendrecv(&my_size, 1, MPI_INT, partner, 0, &partner_size, 1, MPI_INT, partner, 0, MPI_COMM_WORLD,
61 MPI_STATUS_IGNORE);
62
63 // Exchange data
64 24 std::vector<int> partner_data(partner_size);
65
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 MPI_Sendrecv(local_data.data(), my_size, MPI_INT, partner, 1, partner_data.data(), partner_size, MPI_INT, partner, 1,
66 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
67
68 24 return partner_data;
69 }
70
71 24 std::vector<int> MergeAndSplit(int rank, int partner, const std::vector<int> &local_data,
72 const std::vector<int> &partner_data) {
73
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 std::vector<int> merged;
74
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 merged.reserve(local_data.size() + partner_data.size());
75 size_t i = 0;
76 size_t j = 0;
77
4/4
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 70 times.
94 while (i < local_data.size() && j < partner_data.size()) {
78
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 31 times.
70 if (local_data[i] <= partner_data[j]) {
79 merged.push_back(local_data[i]);
80 39 i++;
81 } else {
82 merged.push_back(partner_data[j]);
83 31 j++;
84 }
85 }
86
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 24 times.
45 while (i < local_data.size()) {
87 merged.push_back(local_data[i]);
88 21 i++;
89 }
90
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 24 times.
53 while (j < partner_data.size()) {
91 merged.push_back(partner_data[j]);
92 29 j++;
93 }
94 // std::ranges::merge(local_data.begin(), local_data.end(), partner_data.begin(), partner_data.end(), merged.begin());
95
96
1/4
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
24 std::vector<int> result(local_data.size());
97
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (rank < partner) {
98 // Keep smaller half
99 12 std::copy(merged.begin(), merged.begin() + static_cast<int>(local_data.size()), result.begin());
100 } else {
101 // Keep larger half
102 12 std::copy(merged.end() - static_cast<int>(local_data.size()), merged.end(), result.begin());
103 }
104
105 24 return result;
106 }
107
108 12 void ManageOddEven(int rank, int proc_count, std::vector<int> &local_data) {
109
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 12 times.
48 for (int phase = 0; phase < (proc_count + 1); phase++) {
110 int partner = FindPartner(rank, phase);
111
112
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 12 times.
36 if (partner >= 0 && partner < proc_count) { // partner validation
113 24 std::vector<int> partner_data = SwapDataWithPartner(partner, local_data);
114
3/6
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
48 local_data = MergeAndSplit(rank, partner, local_data, partner_data);
115 }
116 }
117 12 MPI_Barrier(MPI_COMM_WORLD);
118 12 }
119
120 } // namespace
121
122
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 OvchinnikovMBubbleSortMPI::OvchinnikovMBubbleSortMPI(const InType &in) {
123 SetTypeOfTask(GetStaticTypeOfTask());
124
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 GetInput() = in;
125 static_cast<void>(GetOutput());
126 14 }
127
128 14 bool OvchinnikovMBubbleSortMPI::ValidationImpl() {
129 14 return true;
130 }
131
132 14 bool OvchinnikovMBubbleSortMPI::PreProcessingImpl() {
133 14 return true;
134 }
135
136 14 bool OvchinnikovMBubbleSortMPI::RunImpl() {
137 14 int rank = 0;
138 14 int proc_count = 0;
139 14 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
140 14 MPI_Comm_size(MPI_COMM_WORLD, &proc_count);
141
142 const auto &input_vector = GetInput();
143 14 int vec_size = static_cast<int>(input_vector.size());
144
145
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 12 times.
14 if (vec_size == 0) {
146 2 GetOutput() = std::vector<int>();
147 2 return true;
148 }
149
150 12 std::vector<int> elem_count(proc_count);
151
1/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 std::vector<int> elem_offset(proc_count);
152
153
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
154 6 int chunk_base = vec_size / proc_count;
155 6 int chunk_extra = vec_size % proc_count;
156 int offset = 0;
157
158
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 for (int i = 0; i < proc_count; i++) {
159 12 int chunk_end_bit = static_cast<int>(i < chunk_extra);
160 12 elem_count[i] = chunk_base + chunk_end_bit;
161 12 elem_offset[i] = offset;
162 12 offset += elem_count[i];
163 }
164 //
165 }
166
167
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Bcast(elem_count.data(), proc_count, MPI_INT, 0, MPI_COMM_WORLD);
168
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Bcast(elem_offset.data(), proc_count, MPI_INT, 0, MPI_COMM_WORLD);
169
170
1/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 std::vector<int> local_data(elem_count[rank]);
171
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
18 MPI_Scatterv(rank == 0 ? input_vector.data() : nullptr, elem_count.data(), elem_offset.data(), MPI_INT,
172
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 local_data.data(), elem_count[rank], MPI_INT, 0, MPI_COMM_WORLD);
173
174 12 SortOddEven(local_data);
175
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 ManageOddEven(rank, proc_count, local_data);
176 12 std::vector<int> result;
177
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
178
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 result.resize(vec_size);
179 }
180
181
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
18 MPI_Gatherv(local_data.data(), static_cast<int>(local_data.size()), MPI_INT, rank == 0 ? result.data() : nullptr,
182 elem_count.data(), elem_offset.data(), MPI_INT, 0, MPI_COMM_WORLD);
183
184
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
185
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GetOutput() = result;
186 } else {
187
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 GetOutput().resize(vec_size);
188 }
189
190
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Bcast(GetOutput().data(), vec_size, MPI_INT, 0, MPI_COMM_WORLD);
191 return true;
192 }
193
194 14 bool OvchinnikovMBubbleSortMPI::PostProcessingImpl() {
195 14 return true;
196 }
197
198 } // namespace ovchinnikov_m_bubble_sort
199