| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "../include/reduce_mpi.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | |||
| 5 | #include <cstdint> | ||
| 6 | #include <cstring> | ||
| 7 | #include <numeric> | ||
| 8 | |||
| 9 | #include "../../common/include/common.hpp" | ||
| 10 | |||
| 11 | namespace kutergin_v_reduce { | ||
| 12 | |||
| 13 | namespace { | ||
| 14 | |||
| 15 | // вспомогательная функция для применения операции op к двум буферам a и b | ||
| 16 | void ApplyOp(void *a, const void *b, int count, MPI_Datatype datatype, MPI_Op op) { | ||
| 17 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if (op == MPI_SUM && datatype == MPI_INT) { |
| 18 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | for (int i = 0; i < count; ++i) { |
| 19 | 2 | reinterpret_cast<int *>(a)[i] += reinterpret_cast<const int *>(b)[i]; | |
| 20 | } | ||
| 21 | } | ||
| 22 | } | ||
| 23 | |||
| 24 | } // namespace | ||
| 25 | |||
| 26 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | ReduceMPI::ReduceMPI(const InType &in) { |
| 27 | SetTypeOfTask(GetStaticTypeOfTask()); // установка типа задачи | ||
| 28 | GetInput() = in; // сохранение входных данных | ||
| 29 | 8 | GetOutput() = 0; // инициализация выходных данных | |
| 30 | 8 | } | |
| 31 | |||
| 32 | 8 | int Reduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm) { | |
| 33 | 8 | int process_rank = 0; | |
| 34 | 8 | int process_count = 0; | |
| 35 | 8 | MPI_Comm_rank(comm, &process_rank); | |
| 36 | 8 | MPI_Comm_size(comm, &process_count); | |
| 37 | |||
| 38 |
3/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
|
8 | if (root < 0 || root >= process_count) // root-процесс не существует |
| 39 | { | ||
| 40 | return MPI_ERR_ROOT; // возвращение стандартного кода ошибки MPI | ||
| 41 | } | ||
| 42 | |||
| 43 | 4 | int type_size = 0; | |
| 44 | 4 | MPI_Type_size(datatype, &type_size); | |
| 45 | |||
| 46 | // Древовидный сбор | ||
| 47 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for (int mask = 1; mask < process_count; |
| 48 | 2 | mask <<= 1) // удвоение битовой маски на каждой итерации посредством битового сдвига | |
| 49 | { | ||
| 50 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if ((process_rank & mask) != 0) // процессы-отправители |
| 51 | { | ||
| 52 | 2 | MPI_Send(sendbuf, count, datatype, process_rank - mask, 0, comm); | |
| 53 | break; | ||
| 54 | } | ||
| 55 | |||
| 56 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (process_rank + mask < process_count) // процессы-получатели |
| 57 | { | ||
| 58 | 2 | auto *recv_temp = new uint8_t[static_cast<size_t>(count) * type_size]; | |
| 59 | 2 | MPI_Recv(recv_temp, count, datatype, process_rank + mask, 0, comm, MPI_STATUS_IGNORE); | |
| 60 | |||
| 61 | ApplyOp(sendbuf, recv_temp, count, datatype, op); // выполнение op (MPI_SUM) для datatype (MPI_INT) | ||
| 62 | |||
| 63 | 2 | delete[] recv_temp; | |
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | // Результат с процесса 0 отправляется на процесс 'root' | ||
| 68 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
|
4 | if (process_rank == 0 && root != 0) { |
| 69 | 1 | MPI_Send(sendbuf, count, datatype, root, 0, comm); | |
| 70 | } | ||
| 71 | |||
| 72 | // Корневой процесс 'root' получает финальный результат | ||
| 73 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (process_rank == root) { |
| 74 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (root == 0) { |
| 75 | 1 | std::memcpy(recvbuf, sendbuf, static_cast<size_t>(count) * type_size); | |
| 76 | } else { | ||
| 77 | 1 | MPI_Recv(recvbuf, count, datatype, 0, 0, comm, MPI_STATUS_IGNORE); | |
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | return MPI_SUCCESS; | ||
| 82 | } | ||
| 83 | |||
| 84 | 8 | bool ReduceMPI::ValidationImpl() { | |
| 85 | 8 | return true; | |
| 86 | } | ||
| 87 | |||
| 88 | 8 | bool ReduceMPI::PreProcessingImpl() { | |
| 89 | 8 | return true; | |
| 90 | } | ||
| 91 | |||
| 92 | 8 | bool ReduceMPI::RunImpl() { | |
| 93 | 8 | int rank = 0; | |
| 94 | 8 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 95 | |||
| 96 | const auto &input = GetInput(); | ||
| 97 | 8 | int root_process = input.root; | |
| 98 | const auto &input_vec = input.data; | ||
| 99 | |||
| 100 | /* | ||
| 101 | int send_data = input_vec.empty() ? 0 : input_vec[0]; // у каждого процесса - свое число | ||
| 102 | int recv_data = 0; // буфер для результат | ||
| 103 | */ | ||
| 104 | |||
| 105 | int local_sum = | ||
| 106 | 8 | std::accumulate(input_vec.begin(), input_vec.end(), 0); // вычисление локальной суммы всего входного вектора | |
| 107 | 8 | int global_sum = 0; | |
| 108 | |||
| 109 | // Вызов своей реализации Reduce() | ||
| 110 | 8 | Reduce(&local_sum, &global_sum, 1, MPI_INT, MPI_SUM, root_process, MPI_COMM_WORLD); | |
| 111 | |||
| 112 | // Только корневой процесс записывает результат в Output | ||
| 113 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if (rank == root_process) { |
| 114 | 2 | GetOutput() = global_sum; | |
| 115 | } | ||
| 116 | |||
| 117 | 8 | return true; | |
| 118 | } | ||
| 119 | |||
| 120 | 8 | bool ReduceMPI::PostProcessingImpl() { | |
| 121 | 8 | return true; | |
| 122 | } | ||
| 123 | |||
| 124 | } // namespace kutergin_v_reduce | ||
| 125 |