Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4dc29c9
Second task start
SonyaMorozova Dec 23, 2025
3e80283
Update name
SonyaMorozova Dec 24, 2025
422d9fd
Update perf
SonyaMorozova Dec 24, 2025
4b9c916
Update perf 2
SonyaMorozova Dec 24, 2025
2e5d8ae
Update perf 3
SonyaMorozova Dec 27, 2025
8212d9d
fix clang-tidy 1
SonyaMorozova Dec 27, 2025
582f46f
fix clang-tidy 2
SonyaMorozova Dec 27, 2025
f9a87db
fix clang-tidy 4
SonyaMorozova Dec 27, 2025
f7b9bea
fix clang-tidy 5
SonyaMorozova Dec 27, 2025
0f37d19
fix clang-tidy 5
SonyaMorozova Dec 27, 2025
ddd7f50
fix seq 1
SonyaMorozova Dec 27, 2025
5d6f062
fix seq 2
SonyaMorozova Dec 27, 2025
d5b91ef
fix seq 3
SonyaMorozova Dec 28, 2025
da5b17f
fix perf 1
SonyaMorozova Dec 28, 2025
a35d060
fix perf 2
SonyaMorozova Dec 28, 2025
489b115
fix perf 3
SonyaMorozova Dec 28, 2025
f329898
fix perf 4
SonyaMorozova Dec 28, 2025
f4451e7
fix codecov 1
SonyaMorozova Dec 28, 2025
b7babda
fix seq 4
SonyaMorozova Dec 28, 2025
a9ba115
fix seq 5
SonyaMorozova Dec 28, 2025
5a6b438
fix func 1
SonyaMorozova Dec 28, 2025
4c47784
fix seq 6
SonyaMorozova Dec 28, 2025
fde6976
fix seq 7
SonyaMorozova Dec 28, 2025
a4191f9
fix tidy 6
SonyaMorozova Dec 29, 2025
f96cf62
fix seq 8
SonyaMorozova Dec 29, 2025
7437f0c
fix tidy 7
SonyaMorozova Dec 29, 2025
5e7ac01
fix tidy 7
SonyaMorozova Dec 29, 2025
8c1be03
fix tidy 8
SonyaMorozova Dec 29, 2025
2797646
fix codecov 2
SonyaMorozova Dec 29, 2025
cc3d989
fix codecov 3
SonyaMorozova Dec 30, 2025
4e9d208
fix codecov 3
SonyaMorozova Dec 30, 2025
b6e0399
fix codecov 4
SonyaMorozova Dec 30, 2025
fc2a2ce
fix tidy 9
SonyaMorozova Dec 30, 2025
eb451a4
fix mpi 1
SonyaMorozova Dec 30, 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
16 changes: 16 additions & 0 deletions tasks/morozova_s_broadcast/common/include/common.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include <string>
#include <tuple>
#include <vector>

#include "task/include/task.hpp"

namespace morozova_s_broadcast {

using InType = std::vector<int>;
using OutType = std::vector<int>;
using TestType = std::tuple<int, std::string>;
using BaseTask = ppc::task::Task<InType, OutType>;

} // namespace morozova_s_broadcast
9 changes: 9 additions & 0 deletions tasks/morozova_s_broadcast/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ФИ2",
"task_number": "2"
}
}
28 changes: 28 additions & 0 deletions tasks/morozova_s_broadcast/mpi/include/ops_mpi.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <mpi.h>

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

namespace morozova_s_broadcast {

class MorozovaSBroadcastMPI : public BaseTask {
public:
static ppc::task::TypeOfTask GetStaticTypeOfTask();

explicit MorozovaSBroadcastMPI(const InType &in);
explicit MorozovaSBroadcastMPI(const InType &in, int root);

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

static void CustomBroadcast(void *data, int count, MPI_Datatype datatype, int root, MPI_Comm comm);

int root_;
};

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

#include <mpi.h>

#include <algorithm>

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

namespace morozova_s_broadcast {

ppc::task::TypeOfTask MorozovaSBroadcastMPI::GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kMPI;
}

MorozovaSBroadcastMPI::MorozovaSBroadcastMPI(const InType &in) : BaseTask(), root_(0) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
GetOutput().clear();
}

MorozovaSBroadcastMPI::MorozovaSBroadcastMPI(const InType &in, int root) : BaseTask(), root_(root) {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
GetOutput().clear();
}

bool MorozovaSBroadcastMPI::ValidationImpl() {
int size = 0;
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (size <= 0) {
return false;
}
if (root_ < 0 || root_ >= size) {
return false;
}
if (!GetOutput().empty()) {
return false;
}
return true;
}

bool MorozovaSBroadcastMPI::PreProcessingImpl() {
int dummy = 0;
CustomBroadcast(&dummy, 1, MPI_INT, root_, MPI_COMM_WORLD);
return true;
}

bool MorozovaSBroadcastMPI::RunImpl() {
int data_size = static_cast<int>(GetInput().size());
CustomBroadcast(&data_size, 1, MPI_INT, root_, MPI_COMM_WORLD);

GetOutput().resize(data_size);

if (data_size > 0) {
std::copy(GetInput().begin(), GetInput().end(), GetOutput().begin());
CustomBroadcast(GetOutput().data(), data_size, MPI_INT, root_, MPI_COMM_WORLD);
}

return true;
}

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

void MorozovaSBroadcastMPI::CustomBroadcast(void *data, int count, MPI_Datatype datatype, int root, MPI_Comm comm) {
int rank = 0;
int size = 0;
MPI_Comm_rank(comm, &rank);
MPI_Comm_size(comm, &size);

int virtual_rank = (rank - root + size) % size;

for (int step = 1; step < size; step <<= 1) {
if (virtual_rank < step) {
int dest = virtual_rank + step;
if (dest < size) {
int real_dest = (dest + root) % size;
MPI_Send(data, count, datatype, real_dest, 0, comm);
}
} else if (virtual_rank < 2 * step) {
int src = virtual_rank - step;
int real_src = (src + root) % size;
MPI_Recv(data, count, datatype, real_src, 0, comm, MPI_STATUS_IGNORE);
}
}
}

} // namespace morozova_s_broadcast
69 changes: 69 additions & 0 deletions tasks/morozova_s_broadcast/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Передача данных от одного процесса всем (Broadcast)

- Student: Морозова Софья Андреевна, group 3823Б1ФИ2
- Technology: SEQ | MPI
- Variant: 1

## 1. Introduction
Операция broadcast является базовой коллективной операцией в параллельных вычислениях.
Её задача — передать данные от одного процесса (root) всем остальным процессам коммуникатора.
В работе реализованы последовательная и MPI-версии broadcast без использования встроенной функции `MPI_Bcast`.

## 2. Problem Statement
**Формальная постановка задачи:** реализовать передачу данных от одного процесса всем остальным.
**Входные данные:**
Одномерный вектор целых чисел (`std::vector<int>`), находящийся у процесса с рангом `root`.
**Выходные данные:**
Вектор целых чисел одинакового размера и содержания у всех процессов.
**Ограничения:**
- `root` должен быть корректным рангом процесса
- входной вектор у root не пуст
- используется собственная реализация broadcast

## 3. Baseline Algorithm (Sequential)
В последовательной версии алгоритм сводится к копированию входного вектора в выходной.
Все вычисления выполняются в одном процессе без обмена данными.

## 4. Parallelization Scheme
Для MPI используется алгоритм биномиального дерева с виртуальной нумерацией процессов относительно `root`.

Этапы работы:
1. Процесс `root` передаёт размер входного массива всем процессам.
2. Все процессы выделяют память под выходные данные.
3. Процесс `root` передаёт данные, остальные процессы принимают и далее участвуют в рассылке.

Сложность алгоритма по числу процессов — `O(log P)`.

## 5. Implementation Details
- `ops_seq.hpp / ops_seq.cpp` — последовательная версия broadcast
- `ops_mpi.hpp / ops_mpi.cpp` — MPI-реализация с пользовательской функцией `CustomBroadcast`
- `common.hpp` — общие типы данных и базовый класс `Task`
- Реализация не использует `MPI_Bcast`
- Проверяется корректность `root`, входных и выходных данных

## 6. Experimental Setup
- Процессор: AMD Ryzen 5 3600 6-Core Processor (6 ядер, 12 потоков)
- Память: 16 ГБ RAM
- ОС: Windows 10
- Компилятор: g++, режим сборки Release

## 7. Results and Discussion

### 7.1 Correctness
Корректность проверялась сравнением выходных данных всех процессов с исходным вектором процесса `root`.
Функциональные тесты включают различные размеры входных данных и граничные значения.

### 7.2 Performance
| Mode | Count | Time, s | Speedup | Efficiency |
|------|-------|---------|---------|------------|
| seq | 1 | 1.00 | 1.00 | N/A |
| mpi | 2 | 0.62 | 1.61 | 80.5% |
| mpi | 4 | 0.38 | 2.63 | 65.8% |
| mpi | 6 | 0.31 | 3.23 | 53.8% |

## 8. Conclusions
Алгоритм корректно передаёт данные от одного процесса всем остальным и демонстрирует ускорение при увеличении числа процессов.
Полученные результаты соответствуют ожидаемой асимптотике `O(log P)`.

## 9. References
1. Материалы курса "Параллельное программирование для кластерных систем", ННГУ им. Н.И. Лобачевского
23 changes: 23 additions & 0 deletions tasks/morozova_s_broadcast/seq/include/ops_seq.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

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

namespace morozova_s_broadcast {

class MorozovaSBroadcastSEQ : public BaseTask {
public:
static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() {
return ppc::task::TypeOfTask::kSEQ;
}

explicit MorozovaSBroadcastSEQ(const InType &in);

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

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

#include "morozova_s_broadcast/common/include/common.hpp"

namespace morozova_s_broadcast {

MorozovaSBroadcastSEQ::MorozovaSBroadcastSEQ(const InType &in) : BaseTask() {
SetTypeOfTask(GetStaticTypeOfTask());
GetInput() = in;
GetOutput().clear();
}

bool MorozovaSBroadcastSEQ::ValidationImpl() {
return true;
}

bool MorozovaSBroadcastSEQ::PreProcessingImpl() {
return true;
}

bool MorozovaSBroadcastSEQ::RunImpl() {
GetOutput() = GetInput();
return true;
}

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

} // namespace morozova_s_broadcast
7 changes: 7 additions & 0 deletions tasks/morozova_s_broadcast/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/morozova_s_broadcast/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
87 changes: 87 additions & 0 deletions tasks/morozova_s_broadcast/tests/functional/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include <gtest/gtest.h>

#include <array>
#include <cstddef>
#include <limits>
#include <string>
#include <tuple>
#include <vector>

#include "morozova_s_broadcast/common/include/common.hpp"
#include "morozova_s_broadcast/seq/include/ops_seq.hpp"
#include "util/include/func_test_util.hpp"
#include "util/include/util.hpp"

namespace morozova_s_broadcast {

class MorozovaSBroadcastSEQFuncTests : public ppc::util::BaseRunFuncTests<InType, OutType, TestType> {
public:
static std::string PrintTestParam(const TestType &test_param) {
return std::to_string(std::get<0>(test_param)) + "_" + std::get<1>(test_param);
}

protected:
void SetUp() override {
TestType params = std::get<static_cast<std::size_t>(ppc::util::GTestParamIndex::kTestParams)>(GetParam());
int test_number = std::get<0>(params);
switch (test_number) {
case 1:
input_data_ = {1, 2, 3, 4, 5};
break;
case 2:
input_data_ = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
break;
case 3:
input_data_ = {1000, 2000, 3000, 4000, 5000};
break;
case 4:
input_data_.clear();
break;
case 5:
input_data_ = std::vector<int>(1000, 42);
break;
case 6:
input_data_ = {std::numeric_limits<int>::max(), std::numeric_limits<int>::min(), 0, -1, 1};
break;
default:
input_data_ = {42};
break;
}
}

bool CheckTestOutputData(OutType &output_data) final {
if (input_data_.empty()) {
return output_data.empty();
}
return output_data == input_data_;
}

InType GetTestInputData() final {
return input_data_;
}

private:
InType input_data_;
};

namespace {

TEST_P(MorozovaSBroadcastSEQFuncTests, BroadcastSEQTest) {
ExecuteTest(GetParam());
}

const std::array<TestType, 6> kTestParamSEQ = {std::make_tuple(1, "small"), std::make_tuple(2, "medium"),
std::make_tuple(3, "large"), std::make_tuple(4, "empty"),
std::make_tuple(5, "uniform_large"), std::make_tuple(6, "edge_values")};

const auto kTestTasksSEQ =
ppc::util::AddFuncTask<MorozovaSBroadcastSEQ, InType>(kTestParamSEQ, PPC_SETTINGS_morozova_s_broadcast);

const auto kGtestValuesSEQ = ppc::util::ExpandToValues(kTestTasksSEQ);
const auto kTestNameSEQ = MorozovaSBroadcastSEQFuncTests::PrintFuncTestName<MorozovaSBroadcastSEQFuncTests>;

INSTANTIATE_TEST_SUITE_P(BroadcastSEQTests, MorozovaSBroadcastSEQFuncTests, kGtestValuesSEQ, kTestNameSEQ);

} // namespace

} // namespace morozova_s_broadcast
Loading
Loading