GCC Code Coverage Report


Directory: ./
File: tasks/tsyplakov_k_from_all_to_one/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 0 64 0.0%
Functions: 0 20 0.0%
Branches: 0 34 0.0%

Line Branch Exec Source
1 #include "tsyplakov_k_from_all_to_one/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cstddef>
6 #include <cstdlib>
7 #include <cstring>
8 #include <vector>
9
10 namespace tsyplakov_k_from_all_to_one {
11
12 template <typename T>
13 TsyplakovKFromAllToOneMPI<T>::TsyplakovKFromAllToOneMPI(const InTypeT<T> &in) {
14 this->SetTypeOfTask(GetStaticTypeOfTask());
15 this->GetInput() = in;
16 }
17
18 template <typename T>
19 bool TsyplakovKFromAllToOneMPI<T>::ValidationImpl() {
20 const auto &[data, root] = this->GetInput();
21 return !data.empty() && root >= 0;
22 }
23
24 template <typename T>
25 bool TsyplakovKFromAllToOneMPI<T>::PreProcessingImpl() {
26 gathered_.clear();
27 return true;
28 }
29
30 template <typename T>
31 bool TsyplakovKFromAllToOneMPI<T>::RunImpl() {
32 #ifdef USE_MPI
33 int rank = 0;
34 int size = 1;
35 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
36 MPI_Comm_size(MPI_COMM_WORLD, &size);
37
38 const auto &[local_vec, root] = this->GetInput();
39 const int sendcount = static_cast<int>(local_vec.size());
40
41 MPI_Datatype mpi_type{};
42 if constexpr (std::is_same_v<T, int>) {
43 mpi_type = MPI_INT;
44 } else if constexpr (std::is_same_v<T, float>) {
45 mpi_type = MPI_FLOAT;
46 } else if constexpr (std::is_same_v<T, double>) {
47 mpi_type = MPI_DOUBLE;
48 } else {
49 static_assert(!sizeof(T *), "Unsupported MPI type");
50 }
51
52 std::vector<T> recvbuf;
53 if (rank == root) {
54 recvbuf.resize(static_cast<std::size_t>(sendcount * size));
55 }
56
57 MyMpiGather(local_vec.data(), sendcount, mpi_type, rank == root ? recvbuf.data() : nullptr, sendcount, mpi_type, root,
58 MPI_COMM_WORLD);
59
60 if (rank == root) {
61 gathered_ = std::move(recvbuf);
62 this->GetOutput() = gathered_;
63 }
64 #else
65 this->GetOutput() = std::get<0>(this->GetInput());
66 #endif
67 return true;
68 }
69
70 template <typename T>
71 bool TsyplakovKFromAllToOneMPI<T>::PostProcessingImpl() {
72 return true;
73 }
74
75 namespace {
76
77 std::ptrdiff_t Offset(int index, int block_bytes) {
78 return static_cast<std::ptrdiff_t>(index) * static_cast<std::ptrdiff_t>(block_bytes);
79 }
80
81 int CheckArgs(int sendcount, int recvcount, MPI_Datatype sendtype, MPI_Datatype recvtype) {
82 if (sendcount != recvcount) {
83 return MPI_ERR_COUNT;
84 }
85 if (sendtype != recvtype) {
86 return MPI_ERR_TYPE;
87 }
88 return MPI_SUCCESS;
89 }
90
91 void ReceiveBlocks(int real_src, int block_bytes, MPI_Comm comm, std::vector<int> &ranks,
92 std::vector<std::byte> &data) {
93 int recv_blocks = 0;
94 MPI_Recv(&recv_blocks, 1, MPI_INT, real_src, 0, comm, MPI_STATUS_IGNORE);
95
96 const std::size_t old_blocks = ranks.size();
97 const std::size_t new_blocks = old_blocks + static_cast<std::size_t>(recv_blocks);
98
99 ranks.resize(new_blocks);
100 data.resize(new_blocks * static_cast<std::size_t>(block_bytes));
101
102 for (int i = 0; i < recv_blocks; ++i) {
103 const std::size_t idx = old_blocks + static_cast<std::size_t>(i);
104
105 MPI_Recv(&ranks[idx], 1, MPI_INT, real_src, 0, comm, MPI_STATUS_IGNORE);
106
107 MPI_Recv(data.data() + Offset(static_cast<int>(idx), block_bytes), block_bytes, MPI_BYTE, real_src, 0, comm,
108 MPI_STATUS_IGNORE);
109 }
110 }
111
112 void SendBlocks(int real_dest, int block_bytes, MPI_Comm comm, const std::vector<int> &ranks,
113 const std::vector<std::byte> &data) {
114 const int blocks = static_cast<int>(ranks.size());
115
116 MPI_Send(&blocks, 1, MPI_INT, real_dest, 0, comm);
117
118 for (int i = 0; i < blocks; ++i) {
119 MPI_Send(&ranks[static_cast<std::size_t>(i)], 1, MPI_INT, real_dest, 0, comm);
120
121 MPI_Send(data.data() + Offset(i, block_bytes), block_bytes, MPI_BYTE, real_dest, 0, comm);
122 }
123 }
124
125 void GatherStep(int step, int size, int rel_rank, int root, int block_bytes, MPI_Comm comm, std::vector<int> &ranks,
126 std::vector<std::byte> &data) {
127 if (rel_rank % (2 * step) == 0) {
128 const int src = rel_rank + step;
129 if (src < size) {
130 const int real_src = (src + root) % size;
131 ReceiveBlocks(real_src, block_bytes, comm, ranks, data);
132 }
133 } else {
134 const int dest = rel_rank - step;
135 const int real_dest = (dest + root) % size;
136 SendBlocks(real_dest, block_bytes, comm, ranks, data);
137 }
138 }
139
140 void AssembleRoot(int block_bytes, void *recvbuf, const std::vector<int> &ranks, const std::vector<std::byte> &data) {
141 const int blocks = static_cast<int>(ranks.size());
142
143 for (int i = 0; i < blocks; ++i) {
144 std::memcpy(static_cast<std::byte *>(recvbuf) + Offset(ranks[static_cast<std::size_t>(i)], block_bytes),
145 data.data() + Offset(i, block_bytes), static_cast<std::size_t>(block_bytes));
146 }
147 }
148
149 } // namespace
150
151 int MyMpiGather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount,
152 MPI_Datatype recvtype, int root, MPI_Comm comm) {
153 const int check = CheckArgs(sendcount, recvcount, sendtype, recvtype);
154 if (check != MPI_SUCCESS) {
155 return check;
156 }
157
158 int rank = 0;
159 int size = 1;
160 MPI_Comm_rank(comm, &rank);
161 MPI_Comm_size(comm, &size);
162
163 int type_size = 0;
164 MPI_Type_size(sendtype, &type_size);
165
166 const int block_bytes = sendcount * type_size;
167
168 std::vector<int> ranks(1, rank);
169 std::vector<std::byte> data(static_cast<std::size_t>(block_bytes));
170
171 std::memcpy(data.data(), sendbuf, static_cast<std::size_t>(block_bytes));
172
173 const int rel_rank = (rank - root + size) % size;
174
175 for (int step = 1; step < size; step <<= 1) {
176 GatherStep(step, size, rel_rank, root, block_bytes, comm, ranks, data);
177 }
178
179 if (rank == root) {
180 AssembleRoot(block_bytes, recvbuf, ranks, data);
181 }
182
183 return MPI_SUCCESS;
184 }
185
186 template class TsyplakovKFromAllToOneMPI<int>;
187 template class TsyplakovKFromAllToOneMPI<float>;
188 template class TsyplakovKFromAllToOneMPI<double>;
189
190 } // namespace tsyplakov_k_from_all_to_one
191