Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
e07b139
add student folder
smallAbyss Nov 16, 2025
a3bbc5a
base task solution
smallAbyss Nov 17, 2025
7d9173e
clang-format fix
smallAbyss Nov 18, 2025
1751f66
pre-commit fix
smallAbyss Nov 18, 2025
a5371bb
yaml fix
smallAbyss Nov 18, 2025
24be004
increase matrix sizes
smallAbyss Nov 18, 2025
ce8d488
change int to size_t for matrix sizes
smallAbyss Nov 18, 2025
b51ae83
change matrix sizes
smallAbyss Nov 18, 2025
c292d20
clang format fix
smallAbyss Nov 18, 2025
df0cfa2
reduce matrix sizes
smallAbyss Nov 19, 2025
35c1fe3
clang-tidy fix
smallAbyss Nov 19, 2025
1e48841
add func tests
smallAbyss Nov 19, 2025
93bae7f
clang-format fix
smallAbyss Nov 19, 2025
a08851a
another clang-tidy fix
smallAbyss Nov 19, 2025
6f4e8e1
another clang-format fix
smallAbyss Nov 19, 2025
36a93a2
change perf tests data
smallAbyss Nov 19, 2025
afc425c
add report.md
smallAbyss Nov 19, 2025
2932a7e
add func tests
smallAbyss Nov 20, 2025
349ccb8
mpi fix
smallAbyss Nov 22, 2025
87a1ba2
load h and w only for root & sizet fix
smallAbyss Nov 22, 2025
48d5185
change report
smallAbyss Nov 22, 2025
f8c6979
fix grammatical mistakes
smallAbyss Nov 22, 2025
ac58228
clang-format fix
smallAbyss Nov 22, 2025
6a3322a
clang-tidy fix
smallAbyss Nov 22, 2025
c54828c
add cstddef for sizet
smallAbyss Nov 22, 2025
394fd88
clang-format fix
smallAbyss Nov 22, 2025
5fed4ab
fix include
smallAbyss Nov 22, 2025
8898854
codecov fix
smallAbyss Nov 23, 2025
79b30b4
points
smallAbyss Nov 23, 2025
55a1ab4
remove unused picture
smallAbyss Nov 23, 2025
7f85672
fix checks
smallAbyss Nov 24, 2025
a0d559a
change mpi_reduce to mpi_gatherv
smallAbyss Nov 25, 2025
708650c
change matrix sizes sharing
smallAbyss Nov 25, 2025
187c7ac
some changes
smallAbyss Nov 25, 2025
16dced1
clang-format fix
smallAbyss Nov 25, 2025
56be159
report update
smallAbyss Nov 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions tasks/luzan_e_matrix_rows_sum/common/include/common.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include <tuple>
Comment thread
allnes marked this conversation as resolved.
#include <vector>

#include "task/include/task.hpp"

namespace luzan_e_matrix_rows_sum {

using InType = std::tuple<std::vector<int>, int, int>; // matrix, height, width
using OutType = std::vector<int>; // vec of sums, size = height
using TestType = std::tuple<int, int>; // height & width
using BaseTask = ppc::task::Task<InType, OutType>;

} // namespace luzan_e_matrix_rows_sum
9 changes: 9 additions & 0 deletions tasks/luzan_e_matrix_rows_sum/info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"student": {
"first_name": "Егор",
"last_name": "Лузан",
"middle_name": "Андреевич",
"group_number": "3823Б1ФИ3",
"task_number": "1"
}
}
22 changes: 22 additions & 0 deletions tasks/luzan_e_matrix_rows_sum/mpi/include/ops_mpi.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "luzan_e_matrix_rows_sum/common/include/common.hpp"
#include "task/include/task.hpp"

namespace luzan_e_matrix_rows_sum {

class LuzanEMatrixRowsSumMPI : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kMPI;
}
explicit LuzanEMatrixRowsSumMPI(const InType &in);

private:
bool ValidationImpl() override;
bool PreProcessingImpl() override;
bool RunImpl() override;
bool PostProcessingImpl() override;
};

} // namespace luzan_e_matrix_rows_sum
130 changes: 130 additions & 0 deletions tasks/luzan_e_matrix_rows_sum/mpi/src/ops_mpi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#include "luzan_e_matrix_rows_sum/mpi/include/ops_mpi.hpp"

#include <mpi.h>

#include <cstddef>
#include <tuple>
#include <vector>

#include "luzan_e_matrix_rows_sum/common/include/common.hpp"

namespace luzan_e_matrix_rows_sum {

LuzanEMatrixRowsSumMPI::LuzanEMatrixRowsSumMPI(const InType &in) {
SetTypeOfTask(GetStaticTypeOfTask());
GetOutput() = {};

// saving matrix only if it's rank=0
int rank = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);

if (rank == 0) {
GetInput() = in;
} else {
GetInput() = {};
}
}

bool LuzanEMatrixRowsSumMPI::ValidationImpl() {
int rank = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank != 0) {
return true;
}

int height = std::get<1>(GetInput());
int width = std::get<2>(GetInput());
return std::get<0>(GetInput()).size() == static_cast<size_t>(height) * static_cast<size_t>(width) && height > 0 &&
width > 0;
}

bool LuzanEMatrixRowsSumMPI::PreProcessingImpl() {
int rank = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank != 0) {
return true;
}
Comment thread
allnes marked this conversation as resolved.

int height = std::get<1>(GetInput());
GetOutput().resize(height);
for (int row = 0; row < height; row++) {
GetOutput()[row] = 0;
}
return true;
}

bool LuzanEMatrixRowsSumMPI::RunImpl() {
// mpi things
int height = 0;
int width = 0;
std::tuple_element_t<0, InType> mat;

int rank = 0;
int size = 0;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);

// getting input matrix on rank=0
// getting & sharing matrix sizes
std::vector<int> dim(2, 0);
if (rank == 0) {
mat = std::get<0>(GetInput());
height = std::get<1>(GetInput());
width = std::get<2>(GetInput());
}
MPI_Bcast(&height, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Bcast(&width, 1, MPI_INT, 0, MPI_COMM_WORLD);

// calcilating shifts & rows_per_proc (only about rows rigth now)
int rest = height % size;
std::vector<int> shift(size, 0);
std::vector<int> per_proc(size, height / size); // rows per proc

int accumulator = 0;
for (int i = 0; i < size; i++) {
if (rest > 0) {
per_proc[i]++;
rest--;
}
shift[i] = accumulator;
accumulator = per_proc[i] + shift[i];
}

// preparing to recieve data
std::vector<int> recv(static_cast<size_t>(per_proc[rank] * width));

for (int i = 0; i < size; i++) {
per_proc[i] *= width; // now it's about elements
shift[i] *= width;
}
MPI_Scatterv(mat.data(), per_proc.data(), shift.data(), MPI_INT, recv.data(), per_proc[rank], MPI_INT, 0,
MPI_COMM_WORLD);
mat.clear(); // no need anymore

// calculating
std::vector<int> rows_sum(static_cast<size_t>(per_proc[rank] / width)); // sums
int rows_to_calc = static_cast<int>(per_proc[rank] / width);
for (int row = 0; row < rows_to_calc; row++) {
for (int col = 0; col < width; col++) {
rows_sum[row] += recv[(row * width) + col];
}
}

for (int i = 0; i < size; i++) {
per_proc[i] /= width; // back to rows
shift[i] /= width;
}

std::vector<int> fin_sum(height);
MPI_Gatherv(rows_sum.data(), rows_to_calc, MPI_INT, fin_sum.data(), per_proc.data(), shift.data(), MPI_INT, 0,
MPI_COMM_WORLD);
MPI_Bcast(fin_sum.data(), height, MPI_INT, 0, MPI_COMM_WORLD);
GetOutput() = fin_sum;
return true;
}

bool LuzanEMatrixRowsSumMPI::PostProcessingImpl() {
return true;
}

} // namespace luzan_e_matrix_rows_sum
87 changes: 87 additions & 0 deletions tasks/luzan_e_matrix_rows_sum/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# <Сумма значений по строкам матрицы>

- Student: Лузан Егор Андреевич, group 3823Б1ФИ3
- Technology: SEQ | MPI
- Variant: 11

## 1. Introduction
Цель работы — реализовать и сравнить две версии программы, вычисляющей сумму элементов в каждой строке матрицы:
1. последовательную,
2. параллельную, использующую библиотеку **MPI**.

Подобная задача встречается при обработке больших таблиц данных, изображений, численных расчётах.

Ожидается ускорение mpi версии относительно последовательной версии.

## 2. Problem Statement
Дана матрица A размера `height × width`.
Требуется вычислить вектор $sum$ размера `width`, где:
$$sum[i] = \sum_{j=0}^{width-1} A_{i\_j}$$

**Входные данные:**
- Матрица в форме вектора `(std::vector)` размера `height × width` состоящая из целых чисел.

**Выходные данные**:
- Вектор `(std::vector)` размера `height` состоящий из целых чисел, каждое из которых является суммой строки матрицы.

**Ограничения:**
- элементы матрицы — целые числа.
- элементы матрицы лежат в диапазоне -`[0; 42000]`.

## 3. Baseline Algorithm (Sequential)
- Инициализация всех элементов выходного вектора нулями.
- Последовательный обход всех строк исходной матрицы, производя суммирование элементов в них и записывая результат в соответствующий элемент выходного вектора.

## 4. Parallelization Scheme
**Распределение данных:**
- Для каждого процесса:
1. Делим высоту матрицы нацело на количество процессов, получая `rows_per_proc` - минимальное количество строк для обработки каждый процессом.
2. Получаем остаток `rest` от предыдущего деления.
3. Раскладываем оставшиеся `rest` строк по процессам по одной, начиная с `rank=0`. Также вычисляем `shift` - массив смещений, который будет использован при рассылке данных с корневого процесса.
4. Таким образом первые `rest` процессов обработают `rows_per_proc` + 1 строку, остальные `rows_per_proc`.

**Роли рангов:**
- Root-процесс получает матрицу и её размеры.
- Root-процесс рассылает остальным процессам части матрицы для вычислений.
- Во время вычисления сумм процессы всех рангов имеют одинаковые задачи.
- После вычисления итоговый результат будет записан в процессе `rank = 0` с помощью `MPI_Reduce()`.

## 5. Implementation Details
- Для тестов производительности матрица генерируется внутри программы. Результат заранее предсказуем.
- Загрузка матрицы производиться только на root-процесс для экономии памяти.
- Работа программы проверена на матрицах на матрицах состоящих только из одного столбца/строки, на матрицы из одного элемента.

## 6. Experimental Setup
- Hardware/OS:
- CPU: Intel Core i7-13620H; P-cores-6, E-cores-4.
- RAM: 16 GB RAM.
- OS: Windows 11, x64.
- Toolchain:
- Cmake 3.28.3.
- Компилятор: gcc (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0.
- Использовался Docker-контейнер с Ubuntu 24.04.2 LTS.
- Режим сборки: Release.

- Data: Для замера производительности использовалась матрица размером 14 000 × 14 000, элементы которой представляют собой целые последовательные числа от 0 до 42 000.

## 7. Results and Discussion

### 7.1 Correctness
Корректность работы проверена с помощью GoogleTest на матрицах размерностями 3×3, 2×5, 10×70, 2000×5, 5×2000, 1×1.

### 7.2 Performance

| Mode | Count | Time, s | Speedup | Efficiency |
| ---- | ----- | ------------------ | ------- | ---------- |
| seq | 1 | 0,06262 | 1.00 | N/A |
| mpi | 2 | 0,71973 | 0.08 | 4% |
| mpi | 4 | 0,60037 | 0.10 | 2% |

## 8. Conclusions

Разработана программа, выполняющая поиск сумм строк матрицы. Также разработана её параллельная версия с использованием MPI.
Эффективность параллельного очень низкая из-за высоких затрат на пересылку данных и создание процессов.

## 9. References
1. Курс лекций ННГУ "Параллельное программирование для кластерных систем".
2. Стандарт MPI.
22 changes: 22 additions & 0 deletions tasks/luzan_e_matrix_rows_sum/seq/include/ops_seq.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include "luzan_e_matrix_rows_sum/common/include/common.hpp"
#include "task/include/task.hpp"

namespace luzan_e_matrix_rows_sum {

class LuzanEMatrixRowsSumSEQ : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kSEQ;
}
explicit LuzanEMatrixRowsSumSEQ(const InType &in);

private:
bool ValidationImpl() override; //= input data check
bool PreProcessingImpl() override; //= pre proc
bool RunImpl() override; //= PARALLEL
bool PostProcessingImpl() override; //= back to reality
};

} // namespace luzan_e_matrix_rows_sum
51 changes: 51 additions & 0 deletions tasks/luzan_e_matrix_rows_sum/seq/src/ops_seq.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "luzan_e_matrix_rows_sum/seq/include/ops_seq.hpp"

#include <cstddef>
#include <tuple>
#include <vector>

#include "luzan_e_matrix_rows_sum/common/include/common.hpp"

namespace luzan_e_matrix_rows_sum {

LuzanEMatrixRowsSumSEQ::LuzanEMatrixRowsSumSEQ(const InType &in) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
GetOutput() = {};
}

Comment thread
allnes marked this conversation as resolved.
bool LuzanEMatrixRowsSumSEQ::ValidationImpl() {
Comment thread
allnes marked this conversation as resolved.
int height = std::get<1>(GetInput());
int width = std::get<2>(GetInput());

return std::get<0>(GetInput()).size() == static_cast<size_t>(height) * static_cast<size_t>(width) && height > 0 &&
width > 0;
}

bool LuzanEMatrixRowsSumSEQ::PreProcessingImpl() {
int height = std::get<1>(GetInput());
GetOutput().resize(height);
for (int row = 0; row < height; row++) {
GetOutput()[row] = 0;
}
return true;
}

bool LuzanEMatrixRowsSumSEQ::RunImpl() {
int height = std::get<1>(GetInput());
int width = std::get<2>(GetInput());
const std::tuple_element_t<0, InType> &mat = std::get<0>(GetInput());

for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
GetOutput()[row] += mat[(width * row) + col];
}
}
return true;
}

bool LuzanEMatrixRowsSumSEQ::PostProcessingImpl() {
return true;
}

} // namespace luzan_e_matrix_rows_sum
7 changes: 7 additions & 0 deletions tasks/luzan_e_matrix_rows_sum/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"tasks_type": "processes",
"tasks": {
"mpi": "enabled",
"seq": "enabled"
}
}
13 changes: 13 additions & 0 deletions tasks/luzan_e_matrix_rows_sum/tests/.clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
InheritParentConfig: true

Checks: >
-modernize-loop-convert,
-cppcoreguidelines-avoid-goto,
-cppcoreguidelines-avoid-non-const-global-variables,
-misc-use-anonymous-namespace,
-modernize-use-std-print,
-modernize-type-traits
CheckOptions:
- key: readability-function-cognitive-complexity.Threshold
value: 50 # Relaxed for tests
Loading
Loading