Skip to content

Commit 2ada1d7

Browse files
authored
Зенин Антон. Технология SEQ-MPI. Сумма значений по столбцам матрицы. Вариант 12. (#60)
<!-- Требования к названию pull request: "<Фамилия> <Имя>. Технология <TECHNOLOGY_NAME:SEQ|OMP|TBB|STL|MPI>. <Полное название задачи>. Вариант <Номер>" --> ## Описание <!-- Пожалуйста, предоставьте подробное описание вашей реализации, включая: - основные детали решения (описание выбранного алгоритма) - применение технологии параллелизма (если применимо) --> - **Задача**: Сумма значений по столбцам матрицы - **Вариант**: 12 - **Технология**: SEQ,, MPI - **Описание** вашей реализации и отчёта. Реализованы последовательная (SEQ) и параллельная (MPI) версии алгоритма вычисления суммы значений матрицы по столбцам. В последовтельной версии выполняется полный проход по матрице в формате row-major, и каждый элемент добавляется к соответствующей сумме столбца. В параллельной MPI-версии матрица распределяется по столбцам между процессами. Главный процесс формирует буфер с данными столбцов, перераспределённых по адресатам, и рассылает их с помощью MPI_Scatterv. Каждый процесс локально суммирует значения своих столбцов. Затем локальные результаты собираются на процессе 0 через MPI_Gatherv, после чего итоговый вектор сумм рассылается всем процессам при помощи MPI_Bcast для корректной валидации. --- ## Чек-лист <!-- Пожалуйста, убедитесь, что следующие пункты выполнены **до** отправки pull request'а и запроса его ревью: --> - [x] **Статус CI**: Все CI-задачи (сборка, тесты, генерация отчёта) успешно проходят на моей ветке в моем форке - [x] **Директория и именование задачи**: Я создал директорию с именем `<фамилия>_<первая_буква_имени>_<короткое_название_задачи>` - [x] **Полное описание задачи**: Я предоставил полное описание задачи в теле pull request - [x] **clang-format**: Мои изменения успешно проходят `clang-format` локально в моем форке (нет ошибок форматирования) - [x] **clang-tidy**: Мои изменения успешно проходят `clang-tidy` локально в моем форке (нет предупреждений/ошибок) - [x] **Функциональные тесты**: Все функциональные тесты успешно проходят локально на моей машине - [x] **Тесты производительности**: Все тесты производительности успешно проходят локально на моей машине - [x] **Ветка**: Я работаю в ветке, названной точно так же, как директория моей задачи (например, `nesterov_a_vector_sum`), а не в `master` - [x] **Правдивое содержание**: Я подтверждаю, что все сведения, указанные в этом pull request, являются точными и достоверными <!-- ПРИМЕЧАНИЕ: Ложные сведения в этом чек-листе могут привести к отклонению PR и получению нулевого балла за соответствующую задачу. -->
1 parent 36265d0 commit 2ada1d7

11 files changed

Lines changed: 714 additions & 0 deletions

File tree

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#pragma once
2+
3+
#include <cstddef>
4+
#include <tuple>
5+
#include <vector>
6+
7+
#include "task/include/task.hpp"
8+
9+
namespace zenin_a_sum_values_by_columns_matrix {
10+
11+
using InType = std::tuple<size_t, size_t, std::vector<double>>; // rows -> columns -> matrix
12+
using OutType = std::vector<double>;
13+
using TestType = std::tuple<size_t, size_t>;
14+
using BaseTask = ppc::task::Task<InType, OutType>;
15+
16+
} // namespace zenin_a_sum_values_by_columns_matrix
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"student": {
3+
"first_name": "Антон",
4+
"last_name": "Зенин",
5+
"middle_name": "Алексеевич",
6+
"group_number": "3823Б1ФИ1",
7+
"task_number": "1"
8+
}
9+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
#include <cstddef>
3+
#include <vector>
4+
5+
#include "task/include/task.hpp"
6+
#include "zenin_a_sum_values_by_columns_matrix/common/include/common.hpp"
7+
8+
namespace zenin_a_sum_values_by_columns_matrix {
9+
10+
class ZeninASumValuesByColumnsMatrixMPI : public BaseTask {
11+
public:
12+
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
13+
return ppc::task::TypeOfTask::kMPI;
14+
}
15+
explicit ZeninASumValuesByColumnsMatrixMPI(const InType &in);
16+
17+
private:
18+
bool ValidationImpl() override;
19+
bool PreProcessingImpl() override;
20+
bool RunImpl() override;
21+
bool PostProcessingImpl() override;
22+
23+
static void FillSendBuffer(const std::vector<double> &mat, std::vector<double> &sendbuf, size_t rows, size_t cols,
24+
size_t base, size_t rest, int world_size);
25+
};
26+
27+
} // namespace zenin_a_sum_values_by_columns_matrix
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#include "zenin_a_sum_values_by_columns_matrix/mpi/include/ops_mpi.hpp"
2+
3+
#include <mpi.h>
4+
5+
#include <cmath>
6+
#include <cstddef>
7+
#include <stdexcept>
8+
#include <tuple>
9+
#include <utility>
10+
#include <vector>
11+
12+
#include "zenin_a_sum_values_by_columns_matrix/common/include/common.hpp"
13+
14+
namespace zenin_a_sum_values_by_columns_matrix {
15+
16+
ZeninASumValuesByColumnsMatrixMPI::ZeninASumValuesByColumnsMatrixMPI(const InType &in) {
17+
SetTypeOfTask(GetStaticTypeOfTask());
18+
GetInput() = in;
19+
GetOutput() = OutType{};
20+
}
21+
22+
bool ZeninASumValuesByColumnsMatrixMPI::ValidationImpl() {
23+
auto &input = GetInput();
24+
return ((std::get<0>(input)) * std::get<1>(input) == std::get<2>(input).size() && (GetOutput().empty()));
25+
}
26+
27+
bool ZeninASumValuesByColumnsMatrixMPI::PreProcessingImpl() {
28+
int rank = 0;
29+
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
30+
if (rank != 0) {
31+
return true;
32+
}
33+
GetOutput().clear();
34+
return true;
35+
}
36+
37+
void ZeninASumValuesByColumnsMatrixMPI::FillSendBuffer(const std::vector<double> &mat, std::vector<double> &sendbuf,
38+
size_t rows, size_t cols, size_t base, size_t rest,
39+
int world_size) {
40+
size_t pos = 0;
41+
for (int proc = 0; proc < world_size; proc++) {
42+
auto proc_size = static_cast<size_t>(proc);
43+
size_t pc_begin = (proc_size * base) + (std::cmp_less(proc_size, rest) ? proc_size : rest);
44+
size_t pc_end = pc_begin + (base + (std::cmp_less(proc_size, rest) ? 1 : 0));
45+
for (size_t col = pc_begin; col < pc_end; col++) {
46+
for (size_t row = 0; row < rows; row++) {
47+
sendbuf[pos++] = mat[(row * cols) + col];
48+
}
49+
}
50+
}
51+
}
52+
53+
bool ZeninASumValuesByColumnsMatrixMPI::RunImpl() {
54+
auto rows = static_cast<size_t>(std::get<0>(GetInput()));
55+
auto cols = static_cast<size_t>(std::get<1>(GetInput()));
56+
const std::vector<double> &mat = std::get<2>(GetInput());
57+
58+
std::vector<double> &global_sum = GetOutput();
59+
60+
int rank = 0;
61+
int world_size = 0;
62+
63+
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
64+
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
65+
66+
const size_t base = cols / static_cast<size_t>(world_size);
67+
const size_t rest = cols % static_cast<size_t>(world_size);
68+
69+
const size_t my_cols = base + (std::cmp_less(static_cast<size_t>(rank), rest) ? 1 : 0);
70+
71+
std::vector<int> sendcounts(static_cast<size_t>(world_size));
72+
std::vector<int> displs(static_cast<size_t>(world_size));
73+
if (rank == 0) {
74+
int offset = 0;
75+
for (int proc = 0; proc < world_size; proc++) {
76+
size_t pc = base + (std::cmp_less(static_cast<size_t>(proc), rest) ? 1 : 0);
77+
sendcounts[proc] = static_cast<int>(pc * rows);
78+
displs[proc] = offset;
79+
offset += sendcounts[proc];
80+
}
81+
}
82+
83+
std::vector<double> sendbuf;
84+
if (rank == 0) {
85+
sendbuf.resize(rows * cols);
86+
FillSendBuffer(mat, sendbuf, rows, cols, base, rest, world_size);
87+
}
88+
std::vector<double> local_block(rows * my_cols);
89+
MPI_Scatterv(sendbuf.data(), sendcounts.data(), displs.data(), MPI_DOUBLE, local_block.data(),
90+
static_cast<int>(local_block.size()), MPI_DOUBLE, 0, MPI_COMM_WORLD);
91+
92+
std::vector<double> local_sum(my_cols, 0.0);
93+
for (size_t col_id = 0; col_id < my_cols; col_id++) {
94+
for (size_t row_id = 0; row_id < rows; row_id++) {
95+
local_sum[col_id] += local_block[(col_id * rows) + row_id];
96+
}
97+
}
98+
std::vector<int> recvcounts(static_cast<size_t>(world_size));
99+
std::vector<int> recvdispls(static_cast<size_t>(world_size));
100+
101+
if (rows == 0) {
102+
throw std::runtime_error("Matrix has zero rows");
103+
}
104+
105+
if (rank == 0) {
106+
size_t offset = 0;
107+
for (int proc = 0; proc < world_size; proc++) {
108+
recvcounts[proc] = sendcounts[proc] / static_cast<int>(rows);
109+
recvdispls[proc] = static_cast<int>(offset);
110+
offset += static_cast<size_t>(recvcounts[proc]);
111+
}
112+
global_sum.assign(cols, 0.0);
113+
}
114+
115+
MPI_Gatherv(local_sum.data(), static_cast<int>(my_cols), MPI_DOUBLE, global_sum.data(), recvcounts.data(),
116+
recvdispls.data(), MPI_DOUBLE, 0, MPI_COMM_WORLD);
117+
global_sum.resize(cols);
118+
MPI_Bcast(global_sum.data(), static_cast<int>(cols), MPI_DOUBLE, 0, MPI_COMM_WORLD);
119+
return true;
120+
}
121+
122+
bool ZeninASumValuesByColumnsMatrixMPI::PostProcessingImpl() {
123+
return true;
124+
}
125+
126+
} // namespace zenin_a_sum_values_by_columns_matrix

0 commit comments

Comments
 (0)