| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "sinev_a_quicksort_with_simple_merge/mpi/include/ops_mpi.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <cstddef> | ||
| 7 | #include <stack> | ||
| 8 | #include <utility> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "sinev_a_quicksort_with_simple_merge/common/include/common.hpp" | ||
| 12 | // #include "util/include/util.hpp" | ||
| 13 | |||
| 14 | namespace sinev_a_quicksort_with_simple_merge { | ||
| 15 | |||
| 16 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | SinevAQuicksortWithSimpleMergeMPI::SinevAQuicksortWithSimpleMergeMPI(const InType &in) { |
| 17 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 18 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | GetInput() = in; |
| 19 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | GetOutput().resize(in.size()); |
| 20 | 30 | } | |
| 21 | |||
| 22 | 30 | bool SinevAQuicksortWithSimpleMergeMPI::ValidationImpl() { | |
| 23 | 30 | int rank = 0; | |
| 24 | 30 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 25 | |||
| 26 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | if (rank == 0) { |
| 27 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (GetInput().empty()) { |
| 28 | ✗ | return false; | |
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | return true; | ||
| 33 | } | ||
| 34 | |||
| 35 | 30 | bool SinevAQuicksortWithSimpleMergeMPI::PreProcessingImpl() { | |
| 36 | 30 | int rank = 0; | |
| 37 | 30 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 38 | |||
| 39 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | if (rank == 0) { |
| 40 | 15 | GetOutput() = GetInput(); | |
| 41 | } | ||
| 42 | 30 | return true; | |
| 43 | } | ||
| 44 | |||
| 45 | 47 | int SinevAQuicksortWithSimpleMergeMPI::Partition(std::vector<int> &arr, int left, int right) { | |
| 46 | 47 | int pivot_index = left + ((right - left) / 2); | |
| 47 | 47 | int pivot_value = arr[pivot_index]; | |
| 48 | |||
| 49 | 47 | std::swap(arr[pivot_index], arr[left]); | |
| 50 | |||
| 51 | 47 | int i = left + 1; | |
| 52 | int j = right; | ||
| 53 | |||
| 54 |
2/2✓ Branch 0 taken 53 times.
✓ Branch 1 taken 4 times.
|
57 | while (i <= j) { |
| 55 |
4/4✓ Branch 0 taken 69 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 35 times.
|
88 | while (i <= j && arr[i] <= pivot_value) { |
| 56 | 35 | i++; | |
| 57 | } | ||
| 58 | |||
| 59 |
4/4✓ Branch 0 taken 43 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 33 times.
|
86 | while (i <= j && arr[j] > pivot_value) { |
| 60 | 33 | j--; | |
| 61 | } | ||
| 62 | |||
| 63 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 43 times.
|
53 | if (i < j) { |
| 64 | 10 | std::swap(arr[i], arr[j]); | |
| 65 | 10 | i++; | |
| 66 | 10 | j--; | |
| 67 | } else { | ||
| 68 | break; | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | 47 | std::swap(arr[left], arr[j]); | |
| 73 | 47 | return j; | |
| 74 | } | ||
| 75 | |||
| 76 | 61 | void SinevAQuicksortWithSimpleMergeMPI::SimpleMerge(std::vector<int> &arr, int left, int mid, int right) { | |
| 77 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
|
61 | if (left >= right) { |
| 78 | ✗ | return; | |
| 79 | } | ||
| 80 | |||
| 81 | 61 | std::vector<int> temp(right - left + 1); | |
| 82 | |||
| 83 | int i = left; | ||
| 84 | 61 | int j = mid + 1; | |
| 85 | int k = 0; | ||
| 86 | |||
| 87 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 61 times.
|
179 | while (i <= mid && j <= right) { |
| 88 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 28 times.
|
118 | if (arr[i] <= arr[j]) { |
| 89 | 90 | temp[k++] = arr[i++]; | |
| 90 | } else { | ||
| 91 | 28 | temp[k++] = arr[j++]; | |
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 61 times.
|
110 | while (i <= mid) { |
| 96 | 49 | temp[k++] = arr[i++]; | |
| 97 | } | ||
| 98 | |||
| 99 |
2/2✓ Branch 0 taken 57 times.
✓ Branch 1 taken 61 times.
|
118 | while (j <= right) { |
| 100 | 57 | temp[k++] = arr[j++]; | |
| 101 | } | ||
| 102 | |||
| 103 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 61 times.
|
285 | for (int idx = 0; idx < k; idx++) { |
| 104 | 224 | arr[left + idx] = temp[idx]; | |
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | 29 | void SinevAQuicksortWithSimpleMergeMPI::QuickSortWithSimpleMerge(std::vector<int> &arr, int left, int right) { | |
| 109 | struct Range { | ||
| 110 | int left; | ||
| 111 | int right; | ||
| 112 | }; | ||
| 113 | |||
| 114 | std::stack<Range> stack; | ||
| 115 |
1/2✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
|
29 | stack.push({left, right}); |
| 116 | |||
| 117 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 29 times.
|
81 | while (!stack.empty()) { |
| 118 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | Range current = stack.top(); |
| 119 | stack.pop(); | ||
| 120 | |||
| 121 | int l = current.left; | ||
| 122 | int r = current.right; | ||
| 123 | |||
| 124 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 47 times.
|
52 | if (l >= r) { |
| 125 | continue; | ||
| 126 | } | ||
| 127 | |||
| 128 | 47 | int pivot_index = Partition(arr, l, r); | |
| 129 | |||
| 130 | 47 | int left_size = pivot_index - l; | |
| 131 | 47 | int right_size = r - pivot_index; | |
| 132 | |||
| 133 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 43 times.
|
47 | if (left_size > 1 && right_size > 1) { |
| 134 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (left_size > right_size) { |
| 135 | ✗ | stack.push({pivot_index + 1, r}); | |
| 136 | ✗ | stack.push({l, pivot_index - 1}); | |
| 137 | } else { | ||
| 138 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | stack.push({l, pivot_index - 1}); |
| 139 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
8 | stack.push({pivot_index + 1, r}); |
| 140 | } | ||
| 141 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 37 times.
|
43 | } else if (left_size > 1) { |
| 142 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
12 | stack.push({l, pivot_index - 1}); |
| 143 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 28 times.
|
37 | } else if (right_size > 1) { |
| 144 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
18 | stack.push({pivot_index + 1, r}); |
| 145 | } | ||
| 146 | |||
| 147 |
1/2✓ Branch 1 taken 47 times.
✗ Branch 2 not taken.
|
47 | SimpleMerge(arr, l, pivot_index, r); |
| 148 | } | ||
| 149 | 29 | } | |
| 150 | |||
| 151 | 30 | SinevAQuicksortWithSimpleMergeMPI::DistributionInfo SinevAQuicksortWithSimpleMergeMPI::PrepareDistributionInfo( | |
| 152 | int total_size, int world_size, int world_rank) { | ||
| 153 | 30 | DistributionInfo info; | |
| 154 | |||
| 155 | 30 | int base_size = total_size / world_size; | |
| 156 | 30 | int remainder = total_size % world_size; | |
| 157 | |||
| 158 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
|
30 | info.local_size = base_size + (world_rank < remainder ? 1 : 0); |
| 159 | |||
| 160 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | info.send_counts.assign(world_size, 0); |
| 161 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | info.displacements.assign(world_size, 0); |
| 162 | |||
| 163 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | if (world_rank == 0) { |
| 164 | int displacement = 0; | ||
| 165 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 15 times.
|
45 | for (int i = 0; i < world_size; ++i) { |
| 166 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
|
54 | info.send_counts[i] = base_size + (i < remainder ? 1 : 0); |
| 167 | 30 | info.displacements[i] = displacement; | |
| 168 | 30 | displacement += info.send_counts[i]; | |
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | 30 | return info; | |
| 173 | ✗ | } | |
| 174 | |||
| 175 | 30 | std::vector<int> SinevAQuicksortWithSimpleMergeMPI::DistributeData(int world_size, int world_rank) { | |
| 176 | 30 | int total_size = 0; | |
| 177 | |||
| 178 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | if (world_rank == 0) { |
| 179 | 15 | total_size = static_cast<int>(GetOutput().size()); | |
| 180 | } | ||
| 181 | |||
| 182 | 30 | MPI_Bcast(&total_size, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 183 | |||
| 184 | 30 | DistributionInfo info = PrepareDistributionInfo(total_size, world_size, world_rank); | |
| 185 | |||
| 186 |
2/4✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
|
30 | std::vector<int> local_buffer(info.local_size); |
| 187 | |||
| 188 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | MPI_Scatterv(GetOutput().data(), info.send_counts.data(), info.displacements.data(), MPI_INT, local_buffer.data(), |
| 189 | info.local_size, MPI_INT, 0, MPI_COMM_WORLD); | ||
| 190 | |||
| 191 | 30 | return local_buffer; | |
| 192 | 30 | } | |
| 193 | |||
| 194 | 15 | void SinevAQuicksortWithSimpleMergeMPI::PerformMultiWayMerge(const std::vector<int> &all_sizes) { | |
| 195 | 15 | std::vector<std::pair<int, int>> segments; | |
| 196 | 15 | int offset = 0; | |
| 197 | |||
| 198 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 15 times.
|
45 | for (int all_size : all_sizes) { |
| 199 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 1 times.
|
30 | if (all_size > 0) { |
| 200 |
1/4✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
29 | segments.emplace_back(offset, offset + all_size - 1); |
| 201 | 29 | offset += all_size; | |
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 15 times.
|
29 | while (segments.size() > 1) { |
| 206 | 14 | std::vector<std::pair<int, int>> next_segments; | |
| 207 | |||
| 208 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
|
28 | for (std::size_t i = 0; i < segments.size(); i += 2) { |
| 209 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | if (i + 1 < segments.size()) { |
| 210 | 14 | int left = segments[i].first; | |
| 211 | 14 | int mid = segments[i].second; | |
| 212 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | int right = segments[i + 1].second; |
| 213 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | SimpleMerge(GetOutput(), left, mid, right); |
| 214 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | next_segments.emplace_back(left, right); |
| 215 | } else { | ||
| 216 | next_segments.push_back(segments[i]); | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | segments = std::move(next_segments); | ||
| 221 | } | ||
| 222 | 15 | } | |
| 223 | |||
| 224 | 30 | void SinevAQuicksortWithSimpleMergeMPI::BroadcastFinalResult() { | |
| 225 | 30 | int world_rank = 0; | |
| 226 | 30 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); | |
| 227 | |||
| 228 | 30 | int final_size = 0; | |
| 229 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | if (world_rank == 0) { |
| 230 | 15 | final_size = static_cast<int>(GetOutput().size()); | |
| 231 | } | ||
| 232 | |||
| 233 | 30 | MPI_Bcast(&final_size, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 234 | |||
| 235 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | if (world_rank != 0) { |
| 236 | 15 | GetOutput().resize(final_size); | |
| 237 | } | ||
| 238 | |||
| 239 | 30 | MPI_Bcast(GetOutput().data(), final_size, MPI_INT, 0, MPI_COMM_WORLD); | |
| 240 | 30 | } | |
| 241 | |||
| 242 | 30 | void SinevAQuicksortWithSimpleMergeMPI::ParallelQuickSort() { | |
| 243 | 30 | int world_size = 0; | |
| 244 | 30 | int world_rank = 0; | |
| 245 | 30 | MPI_Comm_size(MPI_COMM_WORLD, &world_size); | |
| 246 | 30 | MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); | |
| 247 | |||
| 248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (world_size == 1) { |
| 249 | ✗ | if (!GetOutput().empty()) { | |
| 250 | ✗ | QuickSortWithSimpleMerge(GetOutput(), 0, static_cast<int>(GetOutput().size()) - 1); | |
| 251 | } | ||
| 252 | ✗ | return; | |
| 253 | } | ||
| 254 | |||
| 255 | // 1. Распределение данных по процессам | ||
| 256 | 30 | std::vector<int> local_buffer = DistributeData(world_size, world_rank); | |
| 257 | |||
| 258 | // 2. Локальная сортировка на каждом процессе | ||
| 259 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 1 times.
|
30 | if (!local_buffer.empty()) { |
| 260 |
1/2✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
|
29 | QuickSortWithSimpleMerge(local_buffer, 0, static_cast<int>(local_buffer.size()) - 1); |
| 261 | } | ||
| 262 | |||
| 263 | // 3. Сбор размеров от всех процессов | ||
| 264 |
2/6✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
30 | std::vector<int> all_sizes(world_size); |
| 265 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | int local_size = static_cast<int>(local_buffer.size()); |
| 266 | |||
| 267 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | MPI_Gather(&local_size, 1, MPI_INT, all_sizes.data(), 1, MPI_INT, 0, MPI_COMM_WORLD); |
| 268 | |||
| 269 | // 4. Подготовка буфера на корневом процессе | ||
| 270 |
1/4✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
30 | std::vector<int> displacements(world_size, 0); |
| 271 | int total_size = 0; | ||
| 272 | |||
| 273 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | if (world_rank == 0) { |
| 274 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 15 times.
|
45 | for (int i = 0; i < world_size; ++i) { |
| 275 | 30 | displacements[i] = total_size; | |
| 276 | 30 | total_size += all_sizes[i]; | |
| 277 | } | ||
| 278 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | GetOutput().resize(total_size); |
| 279 | } | ||
| 280 | |||
| 281 | // 5. Сбор данных на корневом процессе | ||
| 282 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | int *recv_data = (world_rank == 0) ? GetOutput().data() : nullptr; |
| 283 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | int *recv_counts = (world_rank == 0) ? all_sizes.data() : nullptr; |
| 284 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
|
30 | int *recv_displs = (world_rank == 0) ? displacements.data() : nullptr; |
| 285 | |||
| 286 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | MPI_Gatherv(local_buffer.data(), local_size, MPI_INT, recv_data, recv_counts, recv_displs, MPI_INT, 0, |
| 287 | MPI_COMM_WORLD); | ||
| 288 | |||
| 289 | // 6. Многостороннее слияние отсортированных частей на процессе 0 | ||
| 290 |
3/4✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
30 | if (world_rank == 0 && !GetOutput().empty()) { |
| 291 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | PerformMultiWayMerge(all_sizes); |
| 292 | } | ||
| 293 | |||
| 294 | // 7. Рассылка результата (оставляем для корректной работы тестов) | ||
| 295 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | BroadcastFinalResult(); |
| 296 | } | ||
| 297 | |||
| 298 | 30 | bool SinevAQuicksortWithSimpleMergeMPI::RunImpl() { | |
| 299 | 30 | ParallelQuickSort(); | |
| 300 | 30 | return true; | |
| 301 | } | ||
| 302 | |||
| 303 | 30 | bool SinevAQuicksortWithSimpleMergeMPI::PostProcessingImpl() { | |
| 304 | 30 | return true; | |
| 305 | } | ||
| 306 | |||
| 307 | } // namespace sinev_a_quicksort_with_simple_merge | ||
| 308 |