GCC Code Coverage Report


Directory: ./
File: tasks/pankov_matrix_vector/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 100 103 97.1%
Functions: 8 8 100.0%
Branches: 61 94 64.9%

Line Branch Exec Source
1 #include "pankov_matrix_vector/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <algorithm>
6 #include <cstddef>
7 #include <utility>
8 #include <vector>
9
10 #include "pankov_matrix_vector/common/include/common.hpp"
11
12 namespace pankov_matrix_vector {
13
14
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 PankovMatrixVectorMPI::PankovMatrixVectorMPI(const InType &in) {
15 SetTypeOfTask(GetStaticTypeOfTask());
16
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 InType temp(in);
17 12 std::swap(GetInput(), temp);
18 12 GetOutput() = std::vector<double>();
19 12 }
20
21 12 bool PankovMatrixVectorMPI::ValidationImpl() {
22 12 return GetOutput().empty();
23 }
24
25 12 bool PankovMatrixVectorMPI::PreProcessingImpl() {
26 const auto &input = GetInput();
27 const std::size_t rows = input.matrix.size();
28 12 GetOutput() = std::vector<double>(rows, 0.0);
29 12 return true;
30 }
31
32 6 void PankovMatrixVectorMPI::DistributeDataFromRank0(const std::vector<std::vector<double>> &matrix,
33 std::vector<std::vector<double>> *local_matrix_band,
34 std::vector<double> *local_result, std::size_t u_rows,
35 std::size_t u_cols, std::size_t u_size, int size,
36 const std::vector<double> &local_vector) {
37 6 std::size_t proc0_base_cols = u_cols / u_size;
38 6 std::size_t proc0_rem_cols = u_cols % u_size;
39 std::size_t proc0_start_col = 0;
40
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
8 std::size_t proc0_end_col = proc0_base_cols + (std::cmp_less(0, static_cast<int>(proc0_rem_cols)) ? 1 : 0);
41 6 proc0_end_col = std::min(proc0_end_col, u_cols);
42 std::size_t proc0_local_cols = proc0_end_col - proc0_start_col;
43
44
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
17 for (std::size_t i = 0; i < u_rows; ++i) {
45
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 11 times.
28 for (std::size_t j = 0; j < proc0_local_cols; ++j) {
46 17 (*local_matrix_band)[i][j] = matrix[i][proc0_start_col + j];
47 }
48 }
49
50 6 ComputePartialResults(*local_matrix_band, local_vector, local_result, u_rows, proc0_local_cols, proc0_start_col);
51
52 6 std::vector<MPI_Request> send_requests;
53 6 std::vector<std::vector<double>> send_buffers;
54
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 send_requests.reserve(size - 1);
55
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 send_buffers.reserve(size - 1);
56
57
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (int proc = 1; proc < size; ++proc) {
58 std::size_t proc_base_cols = u_cols / u_size;
59 std::size_t proc_rem_cols = u_cols % u_size;
60
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 std::size_t proc_start_col = (static_cast<std::size_t>(proc) * proc_base_cols) +
61 6 static_cast<std::size_t>(std::min(proc, static_cast<int>(proc_rem_cols)));
62 std::size_t proc_end_col =
63
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
12 proc_start_col + proc_base_cols + (std::cmp_less(proc, static_cast<int>(proc_rem_cols)) ? 1 : 0);
64 6 proc_end_col = std::min(proc_end_col, u_cols);
65 6 std::size_t proc_local_cols = proc_end_col - proc_start_col;
66
67
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 send_buffers.emplace_back(u_rows * proc_local_cols);
68 std::vector<double> &send_buffer = send_buffers.back();
69
70
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
17 for (std::size_t i = 0; i < u_rows; ++i) {
71
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 11 times.
21 for (std::size_t j = 0; j < proc_local_cols; ++j) {
72 10 send_buffer[(i * proc_local_cols) + j] = matrix[i][proc_start_col + j];
73 }
74 }
75
76 send_requests.emplace_back();
77
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Isend(send_buffer.data(), static_cast<int>(u_rows * proc_local_cols), MPI_DOUBLE, proc, 0, MPI_COMM_WORLD,
78 &send_requests.back());
79 }
80
81
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (!send_requests.empty()) {
82
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Waitall(static_cast<int>(send_requests.size()), send_requests.data(), MPI_STATUSES_IGNORE);
83 }
84 12 }
85
86 6 void PankovMatrixVectorMPI::ReceiveDataOnRankNonZero(std::vector<std::vector<double>> *local_matrix_band,
87 std::size_t u_rows, std::size_t local_cols) {
88 6 std::vector<double> recv_buffer(u_rows * local_cols);
89 6 MPI_Request recv_request = MPI_REQUEST_NULL;
90
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Irecv(recv_buffer.data(), static_cast<int>(u_rows * local_cols), MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &recv_request);
91
92
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 MPI_Wait(&recv_request, MPI_STATUS_IGNORE);
93
94
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 6 times.
17 for (std::size_t i = 0; i < u_rows; ++i) {
95
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 11 times.
21 for (std::size_t j = 0; j < local_cols; ++j) {
96 10 (*local_matrix_band)[i][j] = recv_buffer[(i * local_cols) + j];
97 }
98 }
99 6 }
100
101 12 void PankovMatrixVectorMPI::ComputePartialResults(const std::vector<std::vector<double>> &local_matrix_band,
102 const std::vector<double> &local_vector,
103 std::vector<double> *local_result, std::size_t u_rows,
104 std::size_t local_cols, std::size_t start_col) {
105
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 12 times.
34 for (std::size_t i = 0; i < u_rows; ++i) {
106
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 22 times.
49 for (std::size_t j = 0; j < local_cols; ++j) {
107 27 (*local_result)[i] += local_matrix_band[i][j] * local_vector[start_col + j];
108 }
109 }
110 12 }
111
112 12 bool PankovMatrixVectorMPI::RunImpl() {
113 12 int rank = 0;
114 12 int size = 1;
115 12 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
116 12 MPI_Comm_size(MPI_COMM_WORLD, &size);
117
118 const auto &input = GetInput();
119 12 const auto &matrix = input.matrix;
120 12 const auto &vector = input.vector;
121
122 12 int rows = 0;
123 12 int cols = 0;
124 12 int vector_size = 0;
125
126
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
127 6 rows = static_cast<int>(matrix.size());
128
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (rows > 0) {
129 6 cols = static_cast<int>(matrix[0].size());
130 }
131 6 vector_size = static_cast<int>(vector.size());
132 }
133
134 12 MPI_Bcast(&rows, 1, MPI_INT, 0, MPI_COMM_WORLD);
135 12 MPI_Bcast(&cols, 1, MPI_INT, 0, MPI_COMM_WORLD);
136 12 MPI_Bcast(&vector_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
137
138
3/6
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
12 if (rows == 0 || cols == 0 || cols != vector_size) {
139 GetOutput() = std::vector<double>(static_cast<std::size_t>(rows), 0.0);
140 MPI_Barrier(MPI_COMM_WORLD);
141 return cols == vector_size;
142 }
143
144 12 const auto u_cols = static_cast<std::size_t>(cols);
145 12 const auto u_rows = static_cast<std::size_t>(rows);
146 12 const auto u_size = static_cast<std::size_t>(size);
147
148 12 std::size_t base_cols = u_cols / u_size;
149 12 std::size_t rem_cols = u_cols % u_size;
150
151 12 std::size_t start_col = (static_cast<std::size_t>(rank) * base_cols) +
152
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 static_cast<std::size_t>(std::min(rank, static_cast<int>(rem_cols)));
153
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
20 std::size_t end_col = start_col + base_cols + (std::cmp_less(rank, static_cast<int>(rem_cols)) ? 1 : 0);
154 12 end_col = std::min(end_col, u_cols);
155 12 std::size_t local_cols = end_col - start_col;
156
157 12 std::vector<double> local_vector(static_cast<std::size_t>(vector_size));
158
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
159
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 local_vector = vector;
160 }
161
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Bcast(local_vector.data(), vector_size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
162
163
1/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 std::vector<std::vector<double>> local_matrix_band(u_rows);
164
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 12 times.
34 for (std::size_t i = 0; i < u_rows; ++i) {
165
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 local_matrix_band[i].resize(local_cols);
166 }
167
168
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 std::vector<double> local_result(u_rows, 0.0);
169
170
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (rank == 0) {
171
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 DistributeDataFromRank0(matrix, &local_matrix_band, &local_result, u_rows, u_cols, u_size, size, local_vector);
172 } else {
173
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 ReceiveDataOnRankNonZero(&local_matrix_band, u_rows, local_cols);
174 6 ComputePartialResults(local_matrix_band, local_vector, &local_result, u_rows, local_cols, start_col);
175 }
176
177
1/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 std::vector<double> global_result(u_rows, 0.0);
178
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Reduce(local_result.data(), global_result.data(), rows, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
179
180
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Bcast(global_result.data(), rows, MPI_DOUBLE, 0, MPI_COMM_WORLD);
181
182
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 GetOutput() = global_result;
183
184
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 MPI_Barrier(MPI_COMM_WORLD);
185 return true;
186 12 }
187
188 12 bool PankovMatrixVectorMPI::PostProcessingImpl() {
189 12 return !GetOutput().empty();
190 }
191
192 } // namespace pankov_matrix_vector
193