GCC Code Coverage Report


Directory: ./
File: tasks/tabalaev_a_cannon_mat_mul/mpi/src/ops_mpi.cpp
Date: 2026-01-27 01:59:34
Exec Total Coverage
Lines: 40 92 43.5%
Functions: 6 6 100.0%
Branches: 20 94 21.3%

Line Branch Exec Source
1 #include "tabalaev_a_cannon_mat_mul/mpi/include/ops_mpi.hpp"
2
3 #include <mpi.h>
4
5 #include <array>
6 #include <climits>
7 #include <cmath>
8 #include <cstddef>
9 #include <vector>
10
11 #include "tabalaev_a_cannon_mat_mul/common/include/common.hpp"
12
13 namespace tabalaev_a_cannon_mat_mul {
14
15
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 TabalaevACannonMatMulMPI::TabalaevACannonMatMulMPI(const InType &in) {
16 SetTypeOfTask(GetStaticTypeOfTask());
17 GetInput() = in;
18 GetOutput() = {};
19 14 }
20
21 14 bool TabalaevACannonMatMulMPI::ValidationImpl() {
22 14 int world_rank = 0;
23 14 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
24
25 14 int validation = 0;
26
27
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (world_rank == 0) {
28 7 const size_t n = std::get<0>(GetInput());
29 const auto &a = std::get<1>(GetInput());
30 const auto &b = std::get<2>(GetInput());
31
3/6
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 if (n > 0 && a.size() == n * n && b.size() == n * n) {
32 7 validation = 1;
33 }
34 }
35
36 14 MPI_Bcast(&validation, 1, MPI_INT, 0, MPI_COMM_WORLD);
37
38 14 return validation != 0;
39 }
40
41 14 bool TabalaevACannonMatMulMPI::PreProcessingImpl() {
42 14 return true;
43 }
44
45 14 bool TabalaevACannonMatMulMPI::RunImpl() {
46 14 int world_size = 0;
47 14 MPI_Comm_size(MPI_COMM_WORLD, &world_size);
48 14 int world_rank = 0;
49 14 MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
50
51 14 int n = 0;
52
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (world_rank == 0) {
53 7 n = static_cast<int>(std::get<0>(GetInput()));
54 }
55 14 MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
56
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 int q = static_cast<int>(std::sqrt(world_size));
58
59
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
14 if (q * q != world_size || n % q != 0) {
60 14 const size_t result_size = static_cast<size_t>(n) * static_cast<size_t>(n);
61 14 std::vector<double> result(result_size, 0.0);
62
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
14 if (world_rank == 0) {
63 auto &a = std::get<1>(GetInput());
64 auto &b = std::get<2>(GetInput());
65 7 LocalMatrixMultiply(a, b, result, n);
66 }
67
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 MPI_Bcast(result.data(), static_cast<int>(result_size), MPI_DOUBLE, 0, MPI_COMM_WORLD);
68
69
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 GetOutput() = result;
70
71 return true;
72 }
73
74 int block_size = n / q;
75 int block_elems = block_size * block_size;
76
77 std::array<int, 2> dims = {q, q};
78 std::array<int, 2> periods = {1, 1};
79 MPI_Comm grid_comm = MPI_COMM_NULL;
80 MPI_Cart_create(MPI_COMM_WORLD, 2, dims.data(), periods.data(), 1, &grid_comm);
81
82 int grid_rank = 0;
83 MPI_Comm_rank(grid_comm, &grid_rank);
84
85 std::array<int, 2> coords = {0, 0};
86 MPI_Cart_coords(grid_comm, grid_rank, 2, coords.data());
87
88 int row = coords[0];
89 int col = coords[1];
90
91 MPI_Datatype block_type = MPI_DATATYPE_NULL;
92 MPI_Type_vector(block_size, block_size, n, MPI_DOUBLE, &block_type);
93 MPI_Type_commit(&block_type);
94 MPI_Datatype resized_block = MPI_DATATYPE_NULL;
95 MPI_Type_create_resized(block_type, 0, sizeof(double), &resized_block);
96 MPI_Type_commit(&resized_block);
97
98 std::vector<double> local_a(block_elems);
99 std::vector<double> local_b(block_elems);
100 std::vector<double> local_c(block_elems, 0.0);
101
102 std::vector<int> counts(world_size, 1);
103 std::vector<int> displs(world_size);
104
105 if (grid_rank == 0) {
106 for (int i = 0; i < q; ++i) {
107 for (int j = 0; j < q; ++j) {
108 displs[(i * q) + j] = (i * n * block_size) + (j * block_size);
109 }
110 }
111 auto &a = std::get<1>(GetInput());
112 auto &b = std::get<2>(GetInput());
113 MPI_Scatterv(a.data(), counts.data(), displs.data(), resized_block, local_a.data(), block_elems, MPI_DOUBLE, 0,
114 grid_comm);
115 MPI_Scatterv(b.data(), counts.data(), displs.data(), resized_block, local_b.data(), block_elems, MPI_DOUBLE, 0,
116 grid_comm);
117 } else {
118 MPI_Scatterv(nullptr, nullptr, nullptr, resized_block, local_a.data(), block_elems, MPI_DOUBLE, 0, grid_comm);
119 MPI_Scatterv(nullptr, nullptr, nullptr, resized_block, local_b.data(), block_elems, MPI_DOUBLE, 0, grid_comm);
120 }
121
122 int left = 0;
123 int right = 0;
124 int up = 0;
125 int down = 0;
126
127 MPI_Cart_shift(grid_comm, 1, 1, &left, &right);
128 MPI_Cart_shift(grid_comm, 0, 1, &up, &down);
129
130 for (int i = 0; i < row; ++i) {
131 MPI_Sendrecv_replace(local_a.data(), block_elems, MPI_DOUBLE, left, 0, right, 0, grid_comm, MPI_STATUS_IGNORE);
132 }
133 for (int i = 0; i < col; ++i) {
134 MPI_Sendrecv_replace(local_b.data(), block_elems, MPI_DOUBLE, up, 1, down, 1, grid_comm, MPI_STATUS_IGNORE);
135 }
136
137 for (int k = 0; k < q; ++k) {
138 LocalMatrixMultiply(local_a, local_b, local_c, block_size);
139 MPI_Sendrecv_replace(local_a.data(), block_elems, MPI_DOUBLE, left, 0, right, 0, grid_comm, MPI_STATUS_IGNORE);
140 MPI_Sendrecv_replace(local_b.data(), block_elems, MPI_DOUBLE, up, 1, down, 1, grid_comm, MPI_STATUS_IGNORE);
141 }
142
143 std::vector<double> global_result(static_cast<size_t>(n) * static_cast<size_t>(n));
144 MPI_Gatherv(local_c.data(), block_elems, MPI_DOUBLE, global_result.data(), counts.data(), displs.data(),
145 resized_block, 0, grid_comm);
146
147 MPI_Bcast(global_result.data(), n * n, MPI_DOUBLE, 0, grid_comm);
148 GetOutput() = global_result;
149
150 MPI_Type_free(&resized_block);
151 MPI_Type_free(&block_type);
152 MPI_Comm_free(&grid_comm);
153 return true;
154 }
155
156 14 bool TabalaevACannonMatMulMPI::PostProcessingImpl() {
157 14 return true;
158 }
159
160 7 void TabalaevACannonMatMulMPI::LocalMatrixMultiply(const std::vector<double> &a, const std::vector<double> &b,
161 std::vector<double> &c, int n) {
162
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 7 times.
43 for (int i = 0; i < n; ++i) {
163
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 36 times.
310 for (int k = 0; k < n; ++k) {
164 274 double temp = a[(i * n) + k];
165
2/2
✓ Branch 0 taken 2556 times.
✓ Branch 1 taken 274 times.
2830 for (int j = 0; j < n; ++j) {
166 2556 c[(i * n) + j] += temp * b[(k * n) + j];
167 }
168 }
169 }
170 7 }
171
172 } // namespace tabalaev_a_cannon_mat_mul
173