| 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 |