GCC Code Coverage Report


Directory: ./
File: tasks/votincev_d_matrix_mult/mpi/src/ops_mpi.cpp
Date: 2026-01-10 02:40:41
Exec Total Coverage
Lines: 106 106 100.0%
Functions: 8 8 100.0%
Branches: 59 90 65.6%

Line Branch Exec Source
1 #include "votincev_d_matrix_mult/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cstddef>
7 #include <tuple>
8 #include <vector>
9
10 #include "votincev_d_matrix_mult/common/include/common.hpp"
11
12 namespace votincev_d_matrix_mult {
13
14
1/2
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
20 VotincevDMatrixMultMPI::VotincevDMatrixMultMPI(const InType &in) {
15 SetTypeOfTask(GetStaticTypeOfTask());
16 GetInput() = in;
17 20 }
18
19 // проверка входных данных
20 20 bool VotincevDMatrixMultMPI::ValidationImpl() {
21 const auto &in = GetInput();
22 20 int param_m = std::get<0>(in);
23 20 int param_n = std::get<1>(in);
24 20 int param_k = std::get<2>(in);
25 const auto &matrix_a = std::get<3>(in);
26 const auto &matrix_b = std::get<4>(in);
27
28
3/6
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20 times.
20 return (param_m > 0 && param_n > 0 && param_k > 0 && static_cast<int>(matrix_a.size()) == (param_m * param_k) &&
29
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 static_cast<int>(matrix_b.size()) == (param_k * param_n));
30 }
31
32 // препроцессинг
33 20 bool VotincevDMatrixMultMPI::PreProcessingImpl() {
34 20 return true;
35 }
36
37 // главный метод MPI
38 20 bool VotincevDMatrixMultMPI::RunImpl() {
39 // получаю кол-во процессов
40 20 int process_n = 0;
41 20 MPI_Comm_size(MPI_COMM_WORLD, &process_n);
42
43 // получаю ранг текущего
44 20 int proc_rank = 0;
45 20 MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank);
46
47 // размерности матриц получают все процессы
48 int m = 0;
49 int n = 0;
50 int k = 0;
51 const auto &in = GetInput();
52 20 m = std::get<0>(in);
53 20 n = std::get<1>(in);
54
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 k = std::get<2>(in);
55
56 // если процессов больше чем строк в матрице A -
57 // то активных процессов будет меньше (m)
58 // (потому что разедление по строкам)
59 20 process_n = std::min(process_n, m);
60
61 // "лишние" процессы не работают
62
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 if (proc_rank >= process_n) {
63 return true;
64 }
65
66 18 std::vector<double> matrix_a;
67
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 std::vector<double> matrix_b;
68
69 // матрицу B получают все процессы
70
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 matrix_b = std::get<4>(in);
71
72 // матрицу А получит полностью только 0й процесс
73
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 8 times.
18 if (proc_rank == 0) {
74
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 matrix_a = std::get<3>(in);
75 }
76
77 // если всего 1 процесс - последовательное умножение
78
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (process_n == 1) {
79
1/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 GetOutput() = SeqMatrixMult(m, n, k, matrix_a, matrix_b);
80 2 return true;
81 }
82
83 // какие строки каждый процесс будет перемножать
84 // [start0, end0, start1, end1, ...]
85 16 std::vector<int> ranges;
86
87
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (proc_rank == 0) {
88 8 auto proc_n_sizet = static_cast<size_t>(process_n);
89
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 ranges.resize(proc_n_sizet * 2);
90
91 // минимум на обработку
92 8 int base = m / process_n;
93 // остаток распределим
94 8 int remain = m % process_n;
95
96 int start = 0;
97
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
24 for (size_t i = 0; i < proc_n_sizet; i++) {
98 int part = base;
99
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 10 times.
16 if (remain > 0) {
100 6 part++;
101 6 remain--;
102 }
103
104 // i+i ~~ size_t+size_t .... i*2 ~~ size_t*int (clang-tidy: size_t*int - is bad)
105 16 ranges[i + i] = start;
106 16 ranges[i + i + 1] = start + part; // end (не включительно)
107
108 start += part;
109 }
110 }
111
112 // my_range получит [start, end]
113
1/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
16 std::vector<int> my_range = {0, 0};
114
115 // local_matrix — локальный блок матрицы A данного процесса
116 16 std::vector<double> local_matrix;
117
118 // отправляю всем часть матрицы A в local_matrix
119
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 SendData(k, proc_rank, process_n, my_range, ranges, local_matrix, matrix_a);
120
121 // теперь каждый владеет своим куском (local_matrix)
122 // вызываем обычное перемножение, результат умножение кладется в local_matrix
123
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 MatrixPartMult(k, n, local_matrix, matrix_b);
124
125 // сбор результатов назад к 0му
126
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (proc_rank == 0) {
127
2/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
8 std::vector<double> final_result(static_cast<size_t>(m * n));
128
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 int my_rows = ranges[1] - ranges[0]; // сколько строк
129 // копирую откуда до куда куда
130 std::ranges::copy(local_matrix.begin(), local_matrix.end(), final_result.begin());
131
132 // смещение; изначально равно количеству уже записанных значений
133 8 int offset = my_rows * n;
134 8 auto proc_n_sizet = static_cast<size_t>(process_n);
135
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 for (size_t i = 1; i < proc_n_sizet; ++i) {
136 8 int start_i = ranges[i + i];
137 8 int end_i = ranges[i + i + 1];
138 8 int rows = end_i - start_i;
139
140 // сколько в данной пачке элементов
141 8 int count = rows * n;
142
143
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Recv(final_result.data() + static_cast<size_t>(offset), count, MPI_DOUBLE, static_cast<int>(i), 0,
144 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
145
146 8 offset += count;
147 }
148 // 0й процесс собрал всё от других процессов
149
150
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 GetOutput() = final_result;
151
152 } else {
153 // другие процессы посылают свои результаты основному 0му процессу
154 8 int rows = my_range[1] - my_range[0];
155
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 MPI_Send(local_matrix.data(), rows * n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
156 }
157
158 return true;
159 }
160
161 // ===============================
162 // ==== дополнительные функции ===
163 // ===============================
164
165 16 void VotincevDMatrixMultMPI::SendData(int k, int proc_rank, int process_n, std::vector<int> &my_range,
166 std::vector<int> &ranges, std::vector<double> &local_matrix,
167 std::vector<double> &matrix_a) {
168
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (proc_rank == 0) {
169 // заполняю данные для себя — свои строки матрицы А
170 8 int my_start = ranges[0];
171 8 int my_end = ranges[1];
172 8 int my_rows = my_end - my_start;
173
174 8 auto local_matrix_size = static_cast<size_t>(my_rows) * static_cast<size_t>(k);
175 8 local_matrix.resize(local_matrix_size);
176
2/2
✓ Branch 0 taken 218 times.
✓ Branch 1 taken 8 times.
226 for (size_t i = 0; i < local_matrix_size; i++) {
177 218 local_matrix[i] = matrix_a[i];
178 }
179
180 // рассылаю остальным
181
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 for (int i = 1; i < process_n; i++) {
182 8 int start_i = ranges[i + i];
183 8 int end_i = ranges[i + i + 1];
184
185 8 MPI_Send(&start_i, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
186 8 MPI_Send(&end_i, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
187
188 8 int elem_count = (end_i - start_i) * k;
189
190 8 auto offset = static_cast<size_t>(start_i) * static_cast<size_t>(k);
191 8 MPI_Send(matrix_a.data() + offset, elem_count, MPI_DOUBLE, i, 0, MPI_COMM_WORLD);
192 }
193
194 } else {
195 // получаю диапазон
196 8 MPI_Recv(my_range.data(), 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
197 8 MPI_Recv(&my_range[1], 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
198
199 8 int start_i = my_range[0];
200 8 int end_i = my_range[1];
201 8 int elem_count = (end_i - start_i) * k;
202
203 8 local_matrix.resize(elem_count);
204
205 // получаю матрицу (часть)
206 8 MPI_Recv(local_matrix.data(), elem_count, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
207 }
208 16 }
209
210 // простое последовательное умножение (если кол-во_процессов == 1)
211 2 std::vector<double> VotincevDMatrixMultMPI::SeqMatrixMult(int param_m, int param_n, int param_k,
212 std::vector<double> &matrix_a,
213 std::vector<double> &matrix_b) {
214 2 std::vector<double> matrix_res;
215
1/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 matrix_res.assign(static_cast<size_t>(param_m) * static_cast<size_t>(param_n), 0.0);
216
217
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (int i = 0; i < param_m; ++i) {
218
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
12 for (int j = 0; j < param_n; ++j) {
219 double sum = 0.0;
220
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 10 times.
92 for (int k = 0; k < param_k; ++k) {
221 82 sum += matrix_a[(i * param_k) + k] * matrix_b[(k * param_n) + j];
222 }
223 10 matrix_res[(i * param_n) + j] = sum;
224 }
225 }
226 2 return matrix_res;
227 }
228
229 // умножение части матрицы A на всю матрицу B
230
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 void VotincevDMatrixMultMPI::MatrixPartMult(int param_k, int param_n, std::vector<double> &local_matrix,
231 const std::vector<double> &matrix_b) {
232 16 size_t str_count = local_matrix.size() / param_k;
233
234 16 std::vector<double> result;
235
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 result.resize(str_count * param_n);
236
237
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 16 times.
70 for (size_t i = 0; i < str_count; i++) {
238
2/2
✓ Branch 0 taken 390 times.
✓ Branch 1 taken 54 times.
444 for (int j = 0; j < param_n; j++) {
239 double sum = 0.0;
240
2/2
✓ Branch 0 taken 3323 times.
✓ Branch 1 taken 390 times.
3713 for (int k = 0; k < param_k; k++) {
241 3323 sum += local_matrix[(i * param_k) + k] * matrix_b[(k * param_n) + j];
242 }
243 390 result[(i * param_n) + j] = sum;
244 }
245 }
246
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 local_matrix = result;
247 16 }
248
249 20 bool VotincevDMatrixMultMPI::PostProcessingImpl() {
250 20 return true;
251 }
252
253 } // namespace votincev_d_matrix_mult
254