GCC Code Coverage Report


Directory: ./
File: tasks/shkenev_i_matvect_using_vertical_ribbon/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 99 100 99.0%
Functions: 11 11 100.0%
Branches: 71 106 67.0%

Line Branch Exec Source
1 #include "shkenev_i_matvect_using_vertical_ribbon/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cstddef>
6 #include <vector>
7
8 #include "shkenev_i_matvect_using_vertical_ribbon/common/include/common.hpp"
9
10 namespace shkenev_i_matvect_using_vertical_ribbon {
11
12
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 ShkenevImatvectUsingVerticalRibbonMPI::ShkenevImatvectUsingVerticalRibbonMPI(const InType &in) {
13 SetTypeOfTask(GetStaticTypeOfTask());
14
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 InType temp = in;
15 GetInput().swap(temp);
16 16 GetOutput() = OutType{};
17 16 }
18
19 16 bool ShkenevImatvectUsingVerticalRibbonMPI::ValidationImpl() {
20 16 int rank = 0;
21 16 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
22
23
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (rank != 0) {
24 return true;
25 }
26
27 const auto &input = GetInput();
28 const auto &matrix = input.first;
29 const auto &vector = input.second;
30
31
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 if (matrix.empty() || vector.empty()) {
32 return false;
33 }
34
35 std::size_t cols = matrix[0].size();
36
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 8 times.
26 for (const auto &row : matrix) {
37
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (row.size() != cols) {
38 return false;
39 }
40 }
41
42 8 return vector.size() == cols;
43 }
44
45 16 bool ShkenevImatvectUsingVerticalRibbonMPI::PreProcessingImpl() {
46 16 return true;
47 }
48
49 namespace {
50
51 16 void BroadcastMatrixSize(int &rows, int &cols) {
52 16 MPI_Bcast(&rows, 1, MPI_INT, 0, MPI_COMM_WORLD);
53 16 MPI_Bcast(&cols, 1, MPI_INT, 0, MPI_COMM_WORLD);
54 16 }
55
56 void ComputeColumnDistribution(int rank, int world_size, int total_cols, int &local_cols, int &col_offset) {
57 21 int base = total_cols / world_size;
58 21 int remainder = total_cols % world_size;
59
60 local_cols = base;
61
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (rank < remainder) {
62 6 local_cols += 1;
63 }
64
65 col_offset = 0;
66
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 7 times.
35 for (int i = 0; i < rank; ++i) {
67 int cols_for_proc = base;
68
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1 times.
14 if (i < remainder) {
69 12 cols_for_proc += 1;
70 }
71 14 col_offset += cols_for_proc;
72 }
73 }
74
75 void ScatterMatrixColumns(const std::vector<std::vector<double>> &matrix, std::vector<double> &local_matrix, int rows,
76 int local_cols, int col_offset) {
77
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 7 times.
48 for (int row = 0; row < rows; ++row) {
78
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 17 times.
85 for (int col = 0; col < local_cols; ++col) {
79 51 int global_col = col_offset + col;
80 51 std::size_t index =
81 51 (static_cast<std::size_t>(row) * static_cast<std::size_t>(local_cols)) + static_cast<std::size_t>(col);
82 51 local_matrix[index] = matrix[static_cast<std::size_t>(row)][static_cast<std::size_t>(global_col)];
83 }
84 }
85 }
86
87 void ScatterVectorPart(const std::vector<double> &vector, std::vector<double> &local_vector, int local_cols,
88 int col_offset) {
89
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 7 times.
36 for (int i = 0; i < local_cols; ++i) {
90 22 local_vector[static_cast<std::size_t>(i)] = vector[col_offset + i];
91 }
92 }
93
94 14 void ComputeLocalProduct(const std::vector<double> &local_matrix, const std::vector<double> &local_vector,
95 std::vector<double> &local_result, int rows, int local_cols) {
96
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 14 times.
48 for (int row = 0; row < rows; ++row) {
97 double sum = 0.0;
98
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 34 times.
85 for (int col = 0; col < local_cols; ++col) {
99 51 std::size_t index =
100 51 (static_cast<std::size_t>(row) * static_cast<std::size_t>(local_cols)) + static_cast<std::size_t>(col);
101 51 sum += local_matrix[index] * local_vector[static_cast<std::size_t>(col)];
102 }
103 34 local_result[static_cast<std::size_t>(row)] = sum;
104 }
105 14 }
106
107 7 void ReceiveDataFromProcess0(int rows, int local_cols, std::vector<double> &local_matrix,
108 std::vector<double> &local_vector) {
109
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (local_cols > 0) {
110 MPI_Status status;
111 7 MPI_Recv(local_matrix.data(), rows * local_cols, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, &status);
112 7 MPI_Recv(local_vector.data(), local_cols, MPI_DOUBLE, 0, 1, MPI_COMM_WORLD, &status);
113 }
114 7 }
115
116 14 void GatherAndBroadcastResults(int rank, int rows, const std::vector<double> &local_result,
117 std::vector<double> &result) {
118
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (rows > 0) {
119 double *result_ptr = result.data();
120
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
21 MPI_Reduce(local_result.data(), (rank == 0) ? result_ptr : nullptr, rows, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
121 14 MPI_Bcast(result_ptr, rows, MPI_DOUBLE, 0, MPI_COMM_WORLD);
122 }
123 14 }
124
125 } // namespace
126
127 2 bool ShkenevImatvectUsingVerticalRibbonMPI::HandleSmallMatrixCase(int rank, int rows, int cols) {
128 2 std::vector<double> result(static_cast<std::size_t>(rows), 0.0);
129
130
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (rank == 0) {
131 const auto &matrix = GetInput().first;
132 const auto &vector = GetInput().second;
133
134
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (int i = 0; i < rows; ++i) {
135
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (int j = 0; j < cols; ++j) {
136 1 result[static_cast<std::size_t>(i)] += matrix[i][j] * vector[j];
137 }
138 }
139
140
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 GetOutput() = result;
141 } else {
142
1/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 GetOutput().resize(static_cast<std::size_t>(rows), 0.0);
143 }
144
145
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (rows > 0) {
146
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 MPI_Bcast(GetOutput().data(), rows, MPI_DOUBLE, 0, MPI_COMM_WORLD);
147 }
148 2 return true;
149 }
150
151 7 void ShkenevImatvectUsingVerticalRibbonMPI::SendDataToProcesses(int world_size, int rows, int cols) {
152
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 for (int proc = 1; proc < world_size; ++proc) {
153 int proc_cols = 0;
154 int proc_offset = 0;
155 ComputeColumnDistribution(proc, world_size, cols, proc_cols, proc_offset);
156
157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (proc_cols == 0) {
158 continue;
159 }
160
161 7 std::vector<double> temp_matrix(static_cast<std::size_t>(rows) * static_cast<std::size_t>(proc_cols), 0.0);
162
1/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
7 std::vector<double> temp_vector(static_cast<std::size_t>(proc_cols), 0.0);
163
164 ScatterMatrixColumns(GetInput().first, temp_matrix, rows, proc_cols, proc_offset);
165 ScatterVectorPart(GetInput().second, temp_vector, proc_cols, proc_offset);
166
167
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 MPI_Send(temp_matrix.data(), rows * proc_cols, MPI_DOUBLE, proc, 0, MPI_COMM_WORLD);
168
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 MPI_Send(temp_vector.data(), proc_cols, MPI_DOUBLE, proc, 1, MPI_COMM_WORLD);
169 }
170 7 }
171
172 16 bool ShkenevImatvectUsingVerticalRibbonMPI::RunImpl() {
173 16 int world_size = 0;
174 16 int rank = 0;
175 16 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
176 16 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
177
178 16 int rows = 0;
179 16 int cols = 0;
180
181
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (rank == 0) {
182 8 rows = static_cast<int>(GetInput().first.size());
183 8 cols = static_cast<int>(GetInput().first[0].size());
184 }
185
186 16 BroadcastMatrixSize(rows, cols);
187
188
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 if ((rows == 0) || (cols == 0)) {
189 return false;
190 }
191
192
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 if (cols < world_size) {
193 2 return HandleSmallMatrixCase(rank, rows, cols);
194 }
195
196 int local_cols = 0;
197 int col_offset = 0;
198
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8 times.
14 ComputeColumnDistribution(rank, world_size, cols, local_cols, col_offset);
199
200 14 std::vector<double> local_matrix(static_cast<std::size_t>(rows) * static_cast<std::size_t>(local_cols), 0.0);
201
1/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
14 std::vector<double> local_vector(static_cast<std::size_t>(local_cols), 0.0);
202
1/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
14 std::vector<double> local_result(static_cast<std::size_t>(rows), 0.0);
203
204
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (rank == 0) {
205 7 ScatterMatrixColumns(GetInput().first, local_matrix, rows, local_cols, col_offset);
206 ScatterVectorPart(GetInput().second, local_vector, local_cols, col_offset);
207
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 SendDataToProcesses(world_size, rows, cols);
208 } else {
209
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 ReceiveDataFromProcess0(rows, local_cols, local_matrix, local_vector);
210 }
211
212 14 ComputeLocalProduct(local_matrix, local_vector, local_result, rows, local_cols);
213
214
1/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
14 std::vector<double> result(static_cast<std::size_t>(rows), 0.0);
215
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 GatherAndBroadcastResults(rank, rows, local_result, result);
216
217
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 GetOutput() = result;
218 return true;
219 }
220
221 16 bool ShkenevImatvectUsingVerticalRibbonMPI::PostProcessingImpl() {
222 16 return true;
223 }
224
225 } // namespace shkenev_i_matvect_using_vertical_ribbon
226