| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "yakimov_i_max_values_in_matrix_rows/mpi/include/ops_mpi.hpp" | ||
| 2 | |||
| 3 | #include <mpi.h> | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <array> | ||
| 7 | #include <cstddef> | ||
| 8 | #include <filesystem> | ||
| 9 | #include <fstream> | ||
| 10 | #include <iostream> | ||
| 11 | #include <string> | ||
| 12 | #include <vector> | ||
| 13 | |||
| 14 | // #include "util/include/util.hpp" | ||
| 15 | #include "yakimov_i_max_values_in_matrix_rows/common/include/common.hpp" | ||
| 16 | |||
| 17 | namespace yakimov_i_max_values_in_matrix_rows { | ||
| 18 | |||
| 19 | namespace { | ||
| 20 | void CalculateLocalRows(int rank, int size, int total_rows, int &local_rows, int &start_row, int &end_row) { | ||
| 21 | ✗ | int rows_per_process = total_rows / size; | |
| 22 | ✗ | int remainder = total_rows % size; | |
| 23 | |||
| 24 | ✗ | start_row = (rank * rows_per_process) + std::min(rank, remainder); | |
| 25 | ✗ | end_row = start_row + rows_per_process + (rank < remainder ? 1 : 0); | |
| 26 | ✗ | local_rows = end_row - start_row; | |
| 27 | } | ||
| 28 | |||
| 29 | ✗ | void FindLocalMaxValues(int local_rows, int total_cols, const std::vector<InType> &local_data, | |
| 30 | std::vector<InType> &local_max_values) { | ||
| 31 | ✗ | for (int i = 0; i < local_rows; i++) { | |
| 32 | ✗ | InType row_max = local_data[static_cast<size_t>(i) * static_cast<size_t>(total_cols)]; | |
| 33 | ✗ | for (int j = 1; j < total_cols; j++) { | |
| 34 | ✗ | row_max = std::max(local_data[(i * total_cols) + j], row_max); | |
| 35 | } | ||
| 36 | ✗ | local_max_values[i] = row_max; | |
| 37 | } | ||
| 38 | ✗ | } | |
| 39 | } // namespace | ||
| 40 | |||
| 41 | ✗ | bool YakimovIMaxValuesInMatrixRowsMPI::ValidationImpl() { | |
| 42 | ✗ | int rank = 0; | |
| 43 | ✗ | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 44 | ✗ | if (rank == 0) { | |
| 45 | ✗ | return (GetInput() > 0); | |
| 46 | } | ||
| 47 | return true; | ||
| 48 | } | ||
| 49 | |||
| 50 | ✗ | void YakimovIMaxValuesInMatrixRowsMPI::SendDataToWorkers(int size, int total_rows, int total_cols) { | |
| 51 | ✗ | int rows_per_process = total_rows / size; | |
| 52 | ✗ | int remainder = total_rows % size; | |
| 53 | |||
| 54 | ✗ | for (int proc = 1; proc < size; proc++) { | |
| 55 | ✗ | int proc_start = (proc * rows_per_process) + std::min(proc, remainder); | |
| 56 | ✗ | int proc_rows = rows_per_process + (proc < remainder ? 1 : 0); | |
| 57 | |||
| 58 | ✗ | std::vector<InType> proc_data; | |
| 59 | ✗ | proc_data.reserve(static_cast<size_t>(proc_rows) * static_cast<size_t>(total_cols)); | |
| 60 | ✗ | for (int i = 0; i < proc_rows; i++) { | |
| 61 | ✗ | proc_data.insert(proc_data.end(), matrix_[proc_start + i].begin(), matrix_[proc_start + i].end()); | |
| 62 | } | ||
| 63 | |||
| 64 | ✗ | MPI_Send(proc_data.data(), proc_rows * total_cols, MPI_INT, proc, 0, MPI_COMM_WORLD); | |
| 65 | } | ||
| 66 | ✗ | } | |
| 67 | |||
| 68 | ✗ | void YakimovIMaxValuesInMatrixRowsMPI::ProcessLocalData(int rank, int local_rows, int total_cols, int start_row, | |
| 69 | std::vector<InType> &local_data) { | ||
| 70 | ✗ | if (rank == 0) { | |
| 71 | ✗ | local_data.reserve(static_cast<size_t>(local_rows) * static_cast<size_t>(total_cols)); | |
| 72 | ✗ | for (int i = 0; i < local_rows; i++) { | |
| 73 | ✗ | local_data.insert(local_data.end(), matrix_[start_row + i].begin(), matrix_[start_row + i].end()); | |
| 74 | } | ||
| 75 | } else { | ||
| 76 | ✗ | local_data.resize(static_cast<size_t>(local_rows) * static_cast<size_t>(total_cols)); | |
| 77 | ✗ | MPI_Recv(local_data.data(), local_rows * total_cols, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | |
| 78 | } | ||
| 79 | ✗ | } | |
| 80 | |||
| 81 | ✗ | void YakimovIMaxValuesInMatrixRowsMPI::GatherResults(int rank, int size, int total_rows, | |
| 82 | const std::vector<InType> &local_max_values, int start_row, | ||
| 83 | int local_rows) { | ||
| 84 | ✗ | int rows_per_process = total_rows / size; | |
| 85 | ✗ | int remainder = total_rows % size; | |
| 86 | |||
| 87 | ✗ | if (rank == 0) { | |
| 88 | ✗ | max_Values_.resize(total_rows); | |
| 89 | |||
| 90 | ✗ | for (int i = 0; i < local_rows; i++) { | |
| 91 | ✗ | max_Values_[start_row + i] = local_max_values[i]; | |
| 92 | } | ||
| 93 | |||
| 94 | ✗ | for (int proc = 1; proc < size; proc++) { | |
| 95 | ✗ | int proc_start = (proc * rows_per_process) + std::min(proc, remainder); | |
| 96 | ✗ | int proc_rows = rows_per_process + (proc < remainder ? 1 : 0); | |
| 97 | |||
| 98 | ✗ | std::vector<InType> proc_max_values(proc_rows); | |
| 99 | ✗ | MPI_Recv(proc_max_values.data(), proc_rows, MPI_INT, proc, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); | |
| 100 | |||
| 101 | ✗ | for (int i = 0; i < proc_rows; i++) { | |
| 102 | ✗ | max_Values_[proc_start + i] = proc_max_values[i]; | |
| 103 | } | ||
| 104 | } | ||
| 105 | } else { | ||
| 106 | ✗ | MPI_Send(local_max_values.data(), local_rows, MPI_INT, 0, 0, MPI_COMM_WORLD); | |
| 107 | } | ||
| 108 | ✗ | } | |
| 109 | |||
| 110 | ✗ | bool YakimovIMaxValuesInMatrixRowsMPI::PostProcessingImpl() { | |
| 111 | ✗ | int rank = 0; | |
| 112 | ✗ | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 113 | |||
| 114 | ✗ | if (rank == 0) { | |
| 115 | ✗ | if (!max_Values_.empty()) { | |
| 116 | OutType result = 0; | ||
| 117 | ✗ | for (const auto &max_val : max_Values_) { | |
| 118 | ✗ | result += max_val; | |
| 119 | } | ||
| 120 | ✗ | GetOutput() = result; | |
| 121 | } else { | ||
| 122 | return false; | ||
| 123 | } | ||
| 124 | } else { | ||
| 125 | ✗ | GetOutput() = 0; | |
| 126 | } | ||
| 127 | |||
| 128 | ✗ | OutType final_result = GetOutput(); | |
| 129 | ✗ | MPI_Bcast(&final_result, 1, MPI_INT, 0, MPI_COMM_WORLD); | |
| 130 | ✗ | GetOutput() = final_result; | |
| 131 | |||
| 132 | ✗ | return true; | |
| 133 | } | ||
| 134 | |||
| 135 | ✗ | YakimovIMaxValuesInMatrixRowsMPI::YakimovIMaxValuesInMatrixRowsMPI(const InType &in) { | |
| 136 | SetTypeOfTask(GetStaticTypeOfTask()); | ||
| 137 | ✗ | GetInput() = in; | |
| 138 | GetOutput() = 0; | ||
| 139 | ✗ | std::filesystem::path base_path = std::filesystem::current_path(); | |
| 140 | ✗ | while (base_path.filename() != "ppc-2025-processes-engineers") { | |
| 141 | ✗ | base_path = base_path.parent_path(); | |
| 142 | } | ||
| 143 | matrix_Filename_ = | ||
| 144 | ✗ | base_path.string() + "/tasks/yakimov_i_max_values_in_matrix_rows/data/" + std::to_string(GetInput()) + ".txt"; | |
| 145 | ✗ | } | |
| 146 | |||
| 147 | ✗ | bool YakimovIMaxValuesInMatrixRowsMPI::PreProcessingImpl() { | |
| 148 | ✗ | int rank = 0; | |
| 149 | ✗ | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 150 | |||
| 151 | ✗ | if (rank == 0) { | |
| 152 | ✗ | if (!ReadMatrixFromFile(matrix_Filename_)) { | |
| 153 | return false; | ||
| 154 | } | ||
| 155 | |||
| 156 | ✗ | max_Values_.resize(rows_, 0); | |
| 157 | } | ||
| 158 | |||
| 159 | ✗ | MPI_Barrier(MPI_COMM_WORLD); | |
| 160 | return true; | ||
| 161 | } | ||
| 162 | |||
| 163 | ✗ | bool YakimovIMaxValuesInMatrixRowsMPI::ReadMatrixFromFile(const std::string &filename) { | |
| 164 | ✗ | std::ifstream file(filename); | |
| 165 | ✗ | if (!file.is_open()) { | |
| 166 | return false; | ||
| 167 | } | ||
| 168 | |||
| 169 | ✗ | file >> rows_ >> cols_; | |
| 170 | |||
| 171 | ✗ | if (rows_ == 0 || cols_ == 0) { | |
| 172 | return false; | ||
| 173 | } | ||
| 174 | |||
| 175 | ✗ | matrix_.resize(rows_); | |
| 176 | ✗ | for (size_t i = 0; i < rows_; i++) { | |
| 177 | ✗ | matrix_[i].resize(cols_); | |
| 178 | } | ||
| 179 | |||
| 180 | ✗ | for (size_t i = 0; i < rows_; i++) { | |
| 181 | ✗ | for (size_t j = 0; j < cols_; j++) { | |
| 182 | ✗ | if (!(file >> matrix_[i][j])) { | |
| 183 | return false; | ||
| 184 | } | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | ✗ | file.close(); | |
| 189 | return true; | ||
| 190 | ✗ | } | |
| 191 | |||
| 192 | ✗ | void YakimovIMaxValuesInMatrixRowsMPI::BroadcastMatrixDimensions(int &total_rows, int &total_cols) const { | |
| 193 | ✗ | std::array<int, 2> matrix_dims = {0, 0}; | |
| 194 | ✗ | int rank = 0; | |
| 195 | ✗ | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 196 | |||
| 197 | ✗ | if (rank == 0) { | |
| 198 | ✗ | matrix_dims[0] = static_cast<int>(rows_); | |
| 199 | ✗ | matrix_dims[1] = static_cast<int>(cols_); | |
| 200 | } | ||
| 201 | |||
| 202 | ✗ | MPI_Bcast(matrix_dims.data(), 2, MPI_INT, 0, MPI_COMM_WORLD); | |
| 203 | ✗ | total_rows = matrix_dims[0]; | |
| 204 | ✗ | total_cols = matrix_dims[1]; | |
| 205 | ✗ | } | |
| 206 | |||
| 207 | ✗ | bool YakimovIMaxValuesInMatrixRowsMPI::RunImpl() { | |
| 208 | ✗ | int rank = 0; | |
| 209 | ✗ | int size = 0; | |
| 210 | ✗ | MPI_Comm_rank(MPI_COMM_WORLD, &rank); | |
| 211 | ✗ | MPI_Comm_size(MPI_COMM_WORLD, &size); | |
| 212 | |||
| 213 | ✗ | int total_rows = 0; | |
| 214 | ✗ | int total_cols = 0; | |
| 215 | ✗ | BroadcastMatrixDimensions(total_rows, total_cols); | |
| 216 | |||
| 217 | ✗ | if (total_rows == 0 || total_cols == 0) { | |
| 218 | return false; | ||
| 219 | } | ||
| 220 | |||
| 221 | int local_rows = 0; | ||
| 222 | int start_row = 0; | ||
| 223 | int end_row = 0; | ||
| 224 | ✗ | CalculateLocalRows(rank, size, total_rows, local_rows, start_row, end_row); | |
| 225 | |||
| 226 | ✗ | if (rank == 0) { | |
| 227 | ✗ | SendDataToWorkers(size, total_rows, total_cols); | |
| 228 | } | ||
| 229 | |||
| 230 | ✗ | std::vector<InType> local_data; | |
| 231 | ✗ | ProcessLocalData(rank, local_rows, total_cols, start_row, local_data); | |
| 232 | |||
| 233 | ✗ | std::vector<InType> local_max_values(local_rows); | |
| 234 | ✗ | FindLocalMaxValues(local_rows, total_cols, local_data, local_max_values); | |
| 235 | |||
| 236 | ✗ | GatherResults(rank, size, total_rows, local_max_values, start_row, local_rows); | |
| 237 | |||
| 238 | return true; | ||
| 239 | } | ||
| 240 | |||
| 241 | } // namespace yakimov_i_max_values_in_matrix_rows | ||
| 242 |