GCC Code Coverage Report


Directory: ./
File: tasks/gutyansky_a_matrix_band_multiplication/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 97 99 98.0%
Functions: 8 9 88.9%
Branches: 75 110 68.2%

Line Branch Exec Source
1 #include "gutyansky_a_matrix_band_multiplication/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <array>
6 #include <cstddef>
7 #include <utility>
8 #include <vector>
9
10 #include "gutyansky_a_matrix_band_multiplication/common/include/common.hpp"
11
12 namespace gutyansky_a_matrix_band_multiplication {
13
14 namespace {}
15
16
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 GutyanskyAMatrixBandMultiplicationMPI::GutyanskyAMatrixBandMultiplicationMPI(const InType &in) {
17 SetTypeOfTask(GetStaticTypeOfTask());
18
19
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 GetInput() = in;
20 18 GetOutput() = {};
21 18 }
22
23 void GutyanskyAMatrixBandMultiplicationMPI::GetScatterParams(int rank, int world_size, int elements_count, int *size,
24 int *displacement) {
25 144 int chunk_size = elements_count / world_size;
26 144 int remainder_size = elements_count % world_size;
27
28
8/10
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 13 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 14 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
72 if (rank < remainder_size) {
29 23 *size = chunk_size + 1;
30 28 *displacement = rank * (chunk_size + 1);
31 } else {
32 41 *size = chunk_size;
33 80 *displacement = (remainder_size * (chunk_size + 1)) + ((rank - remainder_size) * chunk_size);
34 }
35 }
36
37 18 bool GutyanskyAMatrixBandMultiplicationMPI::ValidationImpl() {
38 18 int rank = -1;
39 18 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
40
41
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank == 0) {
42 if (!GetInput().first.IsValid()) {
43 return false;
44 }
45 if (!GetInput().second.IsValid()) {
46 return false;
47 }
48
49 9 return GetInput().first.cols == GetInput().second.rows;
50 }
51
52 return true;
53 }
54
55 18 bool GutyanskyAMatrixBandMultiplicationMPI::PreProcessingImpl() {
56 18 return true;
57 }
58
59
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
18 std::vector<int> GutyanskyAMatrixBandMultiplicationMPI::ScatterA(int rank, int world_size, int rows_a, int cols_a) {
60 int local_rows_a = 0;
61 int local_start_a = 0;
62 GetScatterParams(rank, world_size, rows_a, &local_rows_a, &local_start_a);
63
64 18 std::vector<int> local_chunk_a(static_cast<size_t>(local_rows_a) * static_cast<size_t>(cols_a));
65
66
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank == 0) {
67
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 std::vector<int> sizes_a(world_size);
68
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 std::vector<int> displs_a(world_size);
69
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 9 times.
27 for (int i = 0; i < world_size; i++) {
70
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
18 GetScatterParams(i, world_size, rows_a, &sizes_a[i], &displs_a[i]);
71 18 sizes_a[i] *= cols_a;
72 18 displs_a[i] *= cols_a;
73 }
74
75
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 MPI_Scatterv(GetInput().first.data.data(), sizes_a.data(), displs_a.data(), MPI_INT, local_chunk_a.data(),
76 static_cast<int>(local_chunk_a.size()), MPI_INT, 0, MPI_COMM_WORLD);
77 } else {
78
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 MPI_Scatterv(nullptr, nullptr, nullptr, MPI_INT, local_chunk_a.data(), static_cast<int>(local_chunk_a.size()),
79 MPI_INT, 0, MPI_COMM_WORLD);
80 }
81
82 18 return local_chunk_a;
83 }
84
85
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 13 times.
18 std::vector<int> GutyanskyAMatrixBandMultiplicationMPI::ScatterB(int rank, int world_size, int rows_b, int cols_b) {
86 int local_cols_b = 0;
87 int local_start_b = 0;
88 GetScatterParams(rank, world_size, cols_b, &local_cols_b, &local_start_b);
89
90 18 std::vector<int> local_chunk_b(static_cast<size_t>(rows_b) * static_cast<size_t>(local_cols_b));
91
92
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank == 0) {
93
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 std::vector<int> sizes_b(world_size);
94
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 std::vector<int> displs_b(world_size);
95
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 9 times.
27 for (int i = 0; i < world_size; i++) {
96
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 13 times.
18 GetScatterParams(i, world_size, cols_b, &sizes_b[i], &displs_b[i]);
97 18 sizes_b[i] *= rows_b;
98 18 displs_b[i] *= rows_b;
99 }
100
101
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 std::vector<int> packed_b;
102
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 packed_b.reserve(GetInput().second.data.size());
103
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 9 times.
27 for (int i = 0; i < world_size; i++) {
104 int start_col = 0;
105 int col_cnt = 0;
106 GetScatterParams(i, world_size, cols_b, &col_cnt, &start_col);
107
108
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 18 times.
64 for (int k = 0; k < rows_b; k++) {
109
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 46 times.
95 for (int j = 0; j < col_cnt; j++) {
110
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 packed_b.push_back(GetInput().second.data[(k * cols_b) + start_col + j]);
111 }
112 }
113 }
114
115
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 MPI_Scatterv(packed_b.data(), sizes_b.data(), displs_b.data(), MPI_INT, local_chunk_b.data(),
116 static_cast<int>(local_chunk_b.size()), MPI_INT, 0, MPI_COMM_WORLD);
117 } else {
118
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 MPI_Scatterv(nullptr, nullptr, nullptr, MPI_INT, local_chunk_b.data(), static_cast<int>(local_chunk_b.size()),
119 MPI_INT, 0, MPI_COMM_WORLD);
120 }
121
122 18 return local_chunk_b;
123 }
124
125 18 void GutyanskyAMatrixBandMultiplicationMPI::GatherResult(int rank, int world_size, int rows_a, int cols_b,
126 std::vector<int> &res_buffer) {
127
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank == 0) {
128 9 GetOutput().rows = rows_a;
129 9 GetOutput().cols = cols_b;
130 9 GetOutput().data.resize(GetOutput().rows * GetOutput().cols);
131
132 9 std::vector<int> sizes_res(world_size);
133
1/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
9 std::vector<int> displs_res(world_size);
134
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 9 times.
27 for (int i = 0; i < world_size; i++) {
135
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
18 GetScatterParams(i, world_size, rows_a, &sizes_res[i], &displs_res[i]);
136 18 sizes_res[i] *= cols_b;
137 18 displs_res[i] *= cols_b;
138 }
139
140
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 MPI_Gatherv(res_buffer.data(), static_cast<int>(res_buffer.size()), MPI_INT, GetOutput().data.data(),
141 sizes_res.data(), displs_res.data(), MPI_INT, 0, MPI_COMM_WORLD);
142 } else {
143 9 MPI_Gatherv(res_buffer.data(), static_cast<int>(res_buffer.size()), MPI_INT, nullptr, nullptr, nullptr, MPI_INT, 0,
144 MPI_COMM_WORLD);
145 }
146 18 }
147
148 18 bool GutyanskyAMatrixBandMultiplicationMPI::RunImpl() {
149 18 int world_size = 0;
150 18 int rank = 0;
151 18 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
152 18 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
153
154 18 std::array<size_t, 3> bc_sizes{};
155
156
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (rank == 0) {
157 9 bc_sizes[0] = GetInput().first.rows;
158 9 bc_sizes[1] = GetInput().first.cols;
159 9 bc_sizes[2] = GetInput().second.cols;
160 }
161
162 18 MPI_Bcast(bc_sizes.data(), 3, MPI_UINT64_T, 0, MPI_COMM_WORLD);
163
164 18 int rows_a = static_cast<int>(bc_sizes[0]);
165 18 int cols_a = static_cast<int>(bc_sizes[1]);
166 int rows_b = static_cast<int>(bc_sizes[1]);
167 18 int cols_b = static_cast<int>(bc_sizes[2]);
168
169 int local_rows_a = 0;
170 int local_start_a = 0;
171
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 14 times.
18 GetScatterParams(rank, world_size, rows_a, &local_rows_a, &local_start_a);
172 int local_cols_b = 0;
173 int local_start_b = 0;
174 GetScatterParams(rank, world_size, cols_b, &local_cols_b, &local_start_b);
175
176 18 std::vector<int> local_chunk_a = ScatterA(rank, world_size, rows_a, cols_a);
177
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 std::vector<int> local_chunk_b = ScatterB(rank, world_size, rows_b, cols_b);
178
1/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
18 std::vector<int> res_buffer(static_cast<size_t>(local_rows_a) * static_cast<size_t>(cols_b), 0);
179 18 std::vector<int> rotation_buffer;
180
181
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 18 times.
54 for (int it = 0; it < world_size; it++) {
182 int col_count = 0;
183 int start_col = 0;
184
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 GetScatterParams((rank + it) % world_size, world_size, cols_b, &col_count, &start_col);
185
186
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 36 times.
76 for (int i = 0; i < local_rows_a; i++) {
187
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 40 times.
88 for (int j = 0; j < col_count; j++) {
188
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 48 times.
168 for (int k = 0; k < cols_a; k++) {
189 120 res_buffer[(i * cols_b) + start_col + j] +=
190 120 local_chunk_a[(i * cols_a) + k] * local_chunk_b[(k * col_count) + j];
191 }
192 }
193 }
194
195 int next_col_size = 0;
196 int next_col_start = 0;
197
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 GetScatterParams((rank + it + 1) % world_size, world_size, cols_b, &next_col_size, &next_col_start);
198
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 rotation_buffer.resize(static_cast<size_t>(rows_b) * static_cast<size_t>(next_col_size));
199 36 MPI_Sendrecv(local_chunk_b.data(), static_cast<int>(local_chunk_b.size()), MPI_INT,
200
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 (world_size + rank - 1) % world_size, 0, rotation_buffer.data(),
201
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 static_cast<int>(rotation_buffer.size()), MPI_INT, (rank + 1) % world_size, 0, MPI_COMM_WORLD,
202 MPI_STATUS_IGNORE);
203 std::swap(local_chunk_b, rotation_buffer);
204 }
205
206
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 GatherResult(rank, world_size, rows_a, cols_b, res_buffer);
207
208 18 return true;
209 }
210
211 18 bool GutyanskyAMatrixBandMultiplicationMPI::PostProcessingImpl() {
212 18 return true;
213 }
214
215 } // namespace gutyansky_a_matrix_band_multiplication
216