GCC Code Coverage Report


Directory: ./
File: tasks/perepelkin_i_matrix_mult_horizontal_strip_only_a/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 93 94 98.9%
Functions: 10 11 90.9%
Branches: 59 92 64.1%

Line Branch Exec Source
1 #include "perepelkin_i_matrix_mult_horizontal_strip_only_a/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <cstddef>
6 #include <functional>
7 #include <numeric>
8 #include <vector>
9
10 #include "perepelkin_i_matrix_mult_horizontal_strip_only_a/common/include/common.hpp"
11
12 namespace perepelkin_i_matrix_mult_horizontal_strip_only_a {
13
14
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 PerepelkinIMatrixMultHorizontalStripOnlyAMPI::PerepelkinIMatrixMultHorizontalStripOnlyAMPI(const InType &in) {
15
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank_);
16
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 MPI_Comm_size(MPI_COMM_WORLD, &proc_num_);
17
18 SetTypeOfTask(GetStaticTypeOfTask());
19
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (proc_rank_ == 0) {
20 GetInput() = in;
21 }
22 32 GetOutput() = std::vector<std::vector<double>>();
23 32 }
24
25 32 bool PerepelkinIMatrixMultHorizontalStripOnlyAMPI::ValidationImpl() {
26 32 bool is_valid = true;
27
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (proc_rank_ == 0) {
28 16 is_valid = RootValidationImpl();
29 }
30
31 32 MPI_Bcast(&is_valid, 1, MPI_C_BOOL, 0, MPI_COMM_WORLD);
32
2/4
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 32 times.
32 return (is_valid && GetOutput().empty());
33 }
34
35
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 bool PerepelkinIMatrixMultHorizontalStripOnlyAMPI::RootValidationImpl() {
36 const auto &[matrix_a, matrix_b] = GetInput();
37
38
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 if (matrix_a.empty() || matrix_b.empty()) {
39 return false;
40 }
41
42 const size_t width_a = matrix_a[0].size();
43 const size_t width_b = matrix_b[0].size();
44 const size_t height_b = matrix_b.size();
45
46
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (width_a != height_b) {
47 return false;
48 }
49
50
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if (!CheckConsistentRowWidths(matrix_a, width_a)) {
51 return false;
52 }
53
54 if (!CheckConsistentRowWidths(matrix_b, width_b)) {
55 return false;
56 }
57
58 return true;
59 }
60
61 bool PerepelkinIMatrixMultHorizontalStripOnlyAMPI::CheckConsistentRowWidths(
62 const std::vector<std::vector<double>> &matrix, size_t expected_width) {
63
4/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 16 times.
82 for (size_t i = 1; i < matrix.size(); ++i) {
64
2/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
50 if (matrix[i].size() != expected_width) {
65 return false;
66 }
67 }
68 return true;
69 }
70
71 32 bool PerepelkinIMatrixMultHorizontalStripOnlyAMPI::PreProcessingImpl() {
72
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (proc_rank_ == 0) {
73 const auto &[matrix_a, matrix_b] = GetInput();
74
75 // Store original sizes on root
76 16 height_a_ = matrix_a.size();
77 16 height_b_ = matrix_b.size();
78 16 width_a_ = matrix_a[0].size();
79 16 width_b_ = matrix_b[0].size();
80
81 // Flatten matrix A
82 16 flat_a_.reserve(width_a_ * height_a_);
83
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 16 times.
57 for (const auto &row : matrix_a) {
84 41 flat_a_.insert(flat_a_.end(), row.begin(), row.end());
85 }
86
87 // Create transposed-and-flattened matrix B
88 16 flat_b_t_.resize(width_b_ * width_a_);
89
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 16 times.
57 for (size_t row = 0; row < width_a_; row++) {
90
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 41 times.
140 for (size_t col = 0; col < width_b_; col++) {
91 99 flat_b_t_[(col * width_a_) + row] = matrix_b[row][col];
92 }
93 }
94 }
95
96 32 return true;
97 }
98
99 32 bool PerepelkinIMatrixMultHorizontalStripOnlyAMPI::RunImpl() {
100 // [1] Broadcast matrix sizes and matrix B
101 32 BcastMatrixSizes();
102 32 BcastMatrixB();
103
104 // [2] Distribute matrix A
105 32 std::vector<double> local_a;
106 32 std::vector<int> rows_per_rank;
107
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 const size_t local_rows = DistributeMatrixA(local_a, rows_per_rank);
108
109 // [3] Local computation of matrix C
110
1/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32 std::vector<double> local_c(local_rows * width_b_);
111
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 32 times.
73 for (size_t row_a = 0; row_a < local_rows; row_a++) {
112 41 const auto a_it = local_a.begin() + static_cast<DiffT>(row_a * width_a_);
113 const auto a_end = a_it + static_cast<DiffT>(width_a_);
114
115
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 41 times.
143 for (size_t col_b = 0; col_b < width_b_; col_b++) {
116 102 const auto b_it = flat_b_t_.begin() + static_cast<DiffT>(col_b * width_a_);
117 102 local_c[(row_a * width_b_) + col_b] =
118 102 std::transform_reduce(a_it, a_end, b_it, 0.0, std::plus<>(), std::multiplies<>());
119 }
120 }
121
122 // [4] Gather local results
123
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 GatherAndBcastResult(rows_per_rank, local_c);
124 32 return true;
125 }
126
127 32 void PerepelkinIMatrixMultHorizontalStripOnlyAMPI::BcastMatrixSizes() {
128 32 MPI_Bcast(&height_a_, 1, MPI_INT, 0, MPI_COMM_WORLD);
129 32 MPI_Bcast(&height_b_, 1, MPI_INT, 0, MPI_COMM_WORLD);
130 32 MPI_Bcast(&width_a_, 1, MPI_INT, 0, MPI_COMM_WORLD);
131 32 MPI_Bcast(&width_b_, 1, MPI_INT, 0, MPI_COMM_WORLD);
132 32 }
133
134 32 void PerepelkinIMatrixMultHorizontalStripOnlyAMPI::BcastMatrixB() {
135 32 const size_t total_t = width_b_ * height_b_;
136
137
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 if (proc_rank_ != 0) {
138 16 flat_b_t_.resize(total_t);
139 }
140
141 32 MPI_Bcast(flat_b_t_.data(), static_cast<int>(total_t), MPI_DOUBLE, 0, MPI_COMM_WORLD);
142 32 }
143
144 32 int PerepelkinIMatrixMultHorizontalStripOnlyAMPI::DistributeMatrixA(std::vector<double> &local_a,
145 std::vector<int> &rows_per_rank) {
146 // Determine rows per rank
147 32 rows_per_rank.resize(proc_num_);
148 32 const int base_rows = static_cast<int>(height_a_ / proc_num_);
149 32 const int remainder_rows = static_cast<int>(height_a_ % proc_num_);
150
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 32 times.
96 for (int i = 0; i < proc_num_; i++) {
151
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 18 times.
110 rows_per_rank[i] = base_rows + (i < remainder_rows ? 1 : 0);
152 }
153
154 // Prepare counts and displacements
155 32 std::vector<int> counts(proc_num_);
156
1/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32 std::vector<int> displacements(proc_num_);
157
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 32 times.
96 for (int i = 0, offset = 0; i < proc_num_; i++) {
158 64 counts[i] = rows_per_rank[i] * static_cast<int>(width_a_);
159 64 displacements[i] = offset;
160 64 offset += counts[i];
161 }
162
163
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 const int local_a_size = rows_per_rank[proc_rank_] * static_cast<int>(width_a_);
164
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 local_a.resize(local_a_size);
165
166
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 MPI_Scatterv(flat_a_.data(), counts.data(), displacements.data(), MPI_DOUBLE, local_a.data(), local_a_size,
167 MPI_DOUBLE, 0, MPI_COMM_WORLD);
168
169
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
64 return rows_per_rank[proc_rank_];
170 }
171
172 32 void PerepelkinIMatrixMultHorizontalStripOnlyAMPI::GatherAndBcastResult(const std::vector<int> &rows_per_rank,
173 const std::vector<double> &local_c) {
174 32 std::vector<int> counts(proc_num_);
175
1/4
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32 std::vector<int> displacements(proc_num_);
176
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 32 times.
96 for (int i = 0, offset = 0; i < proc_num_; i++) {
177 64 counts[i] = rows_per_rank[i] * static_cast<int>(width_b_);
178 64 displacements[i] = offset;
179 64 offset += counts[i];
180 }
181
182
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 flat_c_.resize(height_a_ * width_b_);
183
184
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 MPI_Allgatherv(local_c.data(), counts[proc_rank_], MPI_DOUBLE, flat_c_.data(), counts.data(), displacements.data(),
185 MPI_DOUBLE, MPI_COMM_WORLD);
186 32 }
187
188 32 bool PerepelkinIMatrixMultHorizontalStripOnlyAMPI::PostProcessingImpl() {
189 auto &output = GetOutput();
190 32 output.resize(height_a_);
191
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 32 times.
114 for (auto &row : output) {
192 82 row.resize(width_b_);
193 }
194
195
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 32 times.
114 for (size_t i = 0; i < height_a_; i++) {
196
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 82 times.
286 for (size_t j = 0; j < width_b_; j++) {
197 204 output[i][j] = flat_c_[(i * width_b_) + j];
198 }
199 }
200
201 32 return true;
202 }
203
204 } // namespace perepelkin_i_matrix_mult_horizontal_strip_only_a
205