From 05cd4f04ea839ea6b3c760d164daa5d7e1a724c9 Mon Sep 17 00:00:00 2001 From: Projectius_student Date: Fri, 2 Jan 2026 20:00:08 +0300 Subject: [PATCH 01/10] initial renaming --- .../common/include/common.hpp | 18 +++ tasks/konstantinov_s_broadcast/data/pic.jpg | Bin 0 -> 23 bytes tasks/konstantinov_s_broadcast/info.json | 9 ++ .../mpi/include/ops_mpi.hpp | 23 +++ .../mpi/src/ops_mpi.cpp | 145 ++++++++++++++++++ tasks/konstantinov_s_broadcast/report.md | 55 +++++++ .../seq/include/ops_seq.hpp | 22 +++ .../seq/src/ops_seq.cpp | 44 ++++++ tasks/konstantinov_s_broadcast/settings.json | 7 + .../tests/.clang-tidy | 13 ++ .../tests/functional/main.cpp | 82 ++++++++++ .../tests/performance/main.cpp | 52 +++++++ .../konstantinov_s_broadcast/tests/testgen.h | 66 ++++++++ 13 files changed, 536 insertions(+) create mode 100644 tasks/konstantinov_s_broadcast/common/include/common.hpp create mode 100644 tasks/konstantinov_s_broadcast/data/pic.jpg create mode 100644 tasks/konstantinov_s_broadcast/info.json create mode 100644 tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp create mode 100644 tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp create mode 100644 tasks/konstantinov_s_broadcast/report.md create mode 100644 tasks/konstantinov_s_broadcast/seq/include/ops_seq.hpp create mode 100644 tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp create mode 100644 tasks/konstantinov_s_broadcast/settings.json create mode 100644 tasks/konstantinov_s_broadcast/tests/.clang-tidy create mode 100644 tasks/konstantinov_s_broadcast/tests/functional/main.cpp create mode 100644 tasks/konstantinov_s_broadcast/tests/performance/main.cpp create mode 100644 tasks/konstantinov_s_broadcast/tests/testgen.h diff --git a/tasks/konstantinov_s_broadcast/common/include/common.hpp b/tasks/konstantinov_s_broadcast/common/include/common.hpp new file mode 100644 index 0000000000..163b0f5a38 --- /dev/null +++ b/tasks/konstantinov_s_broadcast/common/include/common.hpp @@ -0,0 +1,18 @@ +#pragma once + +// #include +// #include +// #include +#include + +#include "task/include/task.hpp" + +namespace konstantinov_s_broadcast { + +using EType = double; +using InType = std::vector; +using OutType = int; +using TestType = int; // std::tuple, int>, std::string>; +using BaseTask = ppc::task::Task; + +} // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/data/pic.jpg b/tasks/konstantinov_s_broadcast/data/pic.jpg new file mode 100644 index 0000000000000000000000000000000000000000..637624238c89d914613ed301968bffbf462bc110 GIT binary patch literal 23 bcmWGA<1$h(;xaNd<@(RSzyQYo|NjR7KDY +// #include +#include +#include +// #include + +#include "konstantinov_s_broadcast/common/include/common.hpp" +// #include "util/include/util.hpp" + +namespace konstantinov_s_broadcast { + +KonstantinovSBroadcastMPI::KonstantinovSBroadcastMPI(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; +} + +bool KonstantinovSBroadcastMPI::ValidationImpl() { + // std::cout << "\t\tValidation mpi\n"; + return !GetInput().empty(); +} + +bool KonstantinovSBroadcastMPI::PreProcessingImpl() { + return true; +} + +void KonstantinovSBroadcastMPI::CountSignChange(int &res, const EType *data, int start, int iterations) { + for (int i = start; i < iterations; i++) { + res += static_cast((data[i] > 0) != (data[i + 1] > 0)); + } + + // for (int i = elemcount - rem; i < elemcount - 1; i++) { + // // std::cout<((sendbuf[i] > 0) != (sendbuf[i + 1] > 0)); + // } + + // for (int i = 0; i < step; i++) { + // local_res += static_cast((recbuf[i] > 0) != (recbuf[i + 1] > 0)); + // } +} + +bool KonstantinovSBroadcastMPI::RunImpl() { + int pcount = 0; + MPI_Comm_size(MPI_COMM_WORLD, &pcount); + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + int step = 0; // chunk size = step+1 + EType *sendbuf = nullptr; + int rem = 0; + int elemcount = 0; // не пересылается, известен только корню + if (rank == 0) { + auto input = GetInput(); // получаем только на нулевом процессе - корне + elemcount = static_cast(input.size()); + // sendbuf = input.data(); //input инвалидируется позже???? + sendbuf = new EType[elemcount]; + std::memcpy(sendbuf, input.data(), input.size() * sizeof(EType)); + // нужно для перекрывающихся областей pcount= 3 [5] 6/3=2 -> 012 234 4 + step = (elemcount + pcount - 1) / pcount; + rem = elemcount - (step * (pcount - 1)); + } + if (step < 2) { + step = 0; + rem = elemcount; + } + + MPI_Bcast(&step, 1, MPI_INT, 0, MPI_COMM_WORLD); // корень отправляет, остальные получают + int chunksz = step + 1; + int *sendcounts = nullptr; + int *displs = nullptr; + EType *recbuf = nullptr; + + if (rank == 0) { + // std::cout< 1) { + CountSignChange(local_res, sendbuf, elemcount - rem, elemcount - 1); + } + + } else { + CountSignChange(local_res, recbuf, 0, step); + } + // std::cout<<"RANK "< +// #include +#include +#include + +#include "konstantinov_s_broadcast/common/include/common.hpp" +// #include "util/include/util.hpp" + +namespace konstantinov_s_broadcast { + +KonstantinovSBroadcastSEQ::KonstantinovSBroadcastSEQ(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; +} + +bool KonstantinovSBroadcastSEQ::ValidationImpl() { + // std::cout << "\t\tValidation seq\n"; + return !GetInput().empty(); +} + +bool KonstantinovSBroadcastSEQ::PreProcessingImpl() { + return true; +} + +bool KonstantinovSBroadcastSEQ::RunImpl() { + const auto invec = GetInput(); + int res = 0; + size_t iterations = invec.size() - 1; + const EType *v = invec.data(); + for (size_t i = 0; i < iterations; i++) { + res += static_cast((v[i] > 0) != (v[i + 1] > 0)); // + 1 если занки разные + } + GetOutput() = res; + return true; +} + +bool KonstantinovSBroadcastSEQ::PostProcessingImpl() { + return true; +} + +} // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/settings.json b/tasks/konstantinov_s_broadcast/settings.json new file mode 100644 index 0000000000..b1a0d52574 --- /dev/null +++ b/tasks/konstantinov_s_broadcast/settings.json @@ -0,0 +1,7 @@ +{ + "tasks_type": "processes", + "tasks": { + "mpi": "enabled", + "seq": "enabled" + } +} diff --git a/tasks/konstantinov_s_broadcast/tests/.clang-tidy b/tasks/konstantinov_s_broadcast/tests/.clang-tidy new file mode 100644 index 0000000000..ef43b7aa8a --- /dev/null +++ b/tasks/konstantinov_s_broadcast/tests/.clang-tidy @@ -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 diff --git a/tasks/konstantinov_s_broadcast/tests/functional/main.cpp b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp new file mode 100644 index 0000000000..21fdff7ec3 --- /dev/null +++ b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp @@ -0,0 +1,82 @@ +#include +#include + +// #include +#include +#include +// #include +// #include +// #include +#include +#include +// #include +// #include + +#include "konstantinov_s_broadcast/common/include/common.hpp" +#include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" +#include "konstantinov_s_broadcast/seq/include/ops_seq.hpp" +#include "konstantinov_s_broadcast/tests/testgen.h" +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" + +namespace konstantinov_s_broadcast { + +class KonstantinovSBroadcastTests : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + return std::to_string(test_param); + } + + protected: + void SetUp() override { + TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + + InType vec(params); + vec.resize(params); + std::array arr = {1, -1, 23, -11, -12, -167, 13, 42, -12, 2, -43, 33, 44, -7, 1}; + const int arrsz = 15; + const int chngcnt = 10; + + result_right_ = GenerateTestData(arr.data(), arrsz, chngcnt, vec); + input_data_ = vec; + } + + bool CheckTestOutputData(OutType &output_data) final { + // std::cout<<"CHECK: "; + // for(int i=0;i kTestParam = {1, 2, 3, 7, 15, 30, 33}; + +const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask( + kTestParam, PPC_SETTINGS_konstantinov_s_broadcast), + ppc::util::AddFuncTask( + kTestParam, PPC_SETTINGS_konstantinov_s_broadcast)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); + +const auto kPerfTestName = KonstantinovSBroadcastTests::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(CustomBroadcastTests, KonstantinovSBroadcastTests, kGtestValues, kPerfTestName); + +} // namespace + +} // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/tests/performance/main.cpp b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp new file mode 100644 index 0000000000..624cb429ab --- /dev/null +++ b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp @@ -0,0 +1,52 @@ +#include + +#include + +#include "konstantinov_s_broadcast/common/include/common.hpp" +#include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" +#include "konstantinov_s_broadcast/seq/include/ops_seq.hpp" +#include "konstantinov_s_broadcast/tests/testgen.h" +#include "util/include/perf_test_util.hpp" + +namespace konstantinov_s_broadcast { + +class KonstantinovSBroadcastTests : public ppc::util::BaseRunPerfTests { + const int kCount_ = 150000000; + InType input_data_; + OutType result_right_{}; + + void SetUp() override { + input_data_.resize(kCount_); + + const std::array arr = {1, -1, 23838, -121, -1223, -567, 12334, 42, -12, 2, -43, 33, 44, -7, 1}; + const int arrsz = 15; + const int chngcnt = 10; + + result_right_ = GenerateTestData(arr.data(), arrsz, chngcnt, input_data_); + // std::cout<( + PPC_SETTINGS_konstantinov_s_broadcast); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +const auto kPerfTestName = KonstantinovSBroadcastTests::CustomPerfTestName; + +INSTANTIATE_TEST_SUITE_P(RunModeTests, KonstantinovSBroadcastTests, kGtestValues, kPerfTestName); + +} // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/tests/testgen.h b/tasks/konstantinov_s_broadcast/tests/testgen.h new file mode 100644 index 0000000000..9e7b82eb7a --- /dev/null +++ b/tasks/konstantinov_s_broadcast/tests/testgen.h @@ -0,0 +1,66 @@ +#pragma once +#include // memcpy +// #include +// #include + +#include "konstantinov_s_broadcast/common/include/common.hpp" + +namespace konstantinov_s_broadcast { +// СТАБИЛЬНЫЙ генератор тестовых данных +// Нужно подать массив с известным колвом смен знаков и одинаковыми знаками первого и последнего элемента +inline int GenerateTestData(const EType *examplearr, size_t arrsz, int sign_change_count, InType &v) { + size_t m = v.size(); + // std::cout<<"Generating "<((examplearr[i] > 0) != (examplearr[i + 1] > 0)); + } + v[m - 1] = examplearr[m - 1]; + return res; + } + + size_t full_blocks = m / arrsz; + size_t tail = m % arrsz; + + EType *dst = v.data(); + + // Копируем первую копию массива + memcpy(dst, examplearr, arrsz * sizeof(EType)); + size_t filled = 1; // число заполненных блоков + + // Удвоительное копирование блоками + // пока удвоение не превысит количество нужных полных блоков + while (filled * 2 <= full_blocks) { + memcpy(dst + (filled * arrsz), dst, filled * arrsz * sizeof(EType)); + filled *= 2; + } + + // Дозаполняем оставшиеся полные блоки + while (filled < full_blocks) { + memcpy(dst + (filled * arrsz), dst, arrsz * sizeof(EType)); + filled++; + } + + // Хвост = последний элемент чтобы не считать смены знаков там + if (tail > 0) { + EType last = examplearr[arrsz - 1]; + for (size_t i = 0; i < tail; ++i) { + dst[(full_blocks * arrsz) + i] = last; + } + } + + // for(int i=0;i(sign_change_count * full_blocks); +} + +} // namespace konstantinov_s_broadcast From c9522be81b32546db0d414aa6c70af304469be47 Mon Sep 17 00:00:00 2001 From: Projectius_student Date: Fri, 2 Jan 2026 20:21:52 +0300 Subject: [PATCH 02/10] template --- .../mpi/include/ops_mpi.hpp | 18 ++++ .../mpi/src/ops_mpi.cpp | 95 +------------------ 2 files changed, 20 insertions(+), 93 deletions(-) diff --git a/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp b/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp index 2c2840051b..f0c8b92da2 100644 --- a/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp +++ b/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp @@ -20,4 +20,22 @@ class KonstantinovSBroadcastMPI : public BaseTask { bool PostProcessingImpl() override; }; +template +constexpr MPI_Datatype get_mpi_type(); + +template <> +constexpr MPI_Datatype get_mpi_type() { + return MPI_INT; +} + +template <> +constexpr MPI_Datatype get_mpi_type() { + return MPI_FLOAT; +} + +template <> +constexpr MPI_Datatype get_mpi_type() { + return MPI_DOUBLE; +} + } // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp index 37a9f0bcf2..7cd6064b73 100644 --- a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp +++ b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp @@ -41,100 +41,9 @@ void KonstantinovSBroadcastMPI::CountSignChange(int &res, const EType *data, int // } } +template bool KonstantinovSBroadcastMPI::RunImpl() { - int pcount = 0; - MPI_Comm_size(MPI_COMM_WORLD, &pcount); - int rank = 0; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - int step = 0; // chunk size = step+1 - EType *sendbuf = nullptr; - int rem = 0; - int elemcount = 0; // не пересылается, известен только корню - if (rank == 0) { - auto input = GetInput(); // получаем только на нулевом процессе - корне - elemcount = static_cast(input.size()); - // sendbuf = input.data(); //input инвалидируется позже???? - sendbuf = new EType[elemcount]; - std::memcpy(sendbuf, input.data(), input.size() * sizeof(EType)); - // нужно для перекрывающихся областей pcount= 3 [5] 6/3=2 -> 012 234 4 - step = (elemcount + pcount - 1) / pcount; - rem = elemcount - (step * (pcount - 1)); - } - if (step < 2) { - step = 0; - rem = elemcount; - } - - MPI_Bcast(&step, 1, MPI_INT, 0, MPI_COMM_WORLD); // корень отправляет, остальные получают - int chunksz = step + 1; - int *sendcounts = nullptr; - int *displs = nullptr; - EType *recbuf = nullptr; - - if (rank == 0) { - // std::cout< 1) { - CountSignChange(local_res, sendbuf, elemcount - rem, elemcount - 1); - } - - } else { - CountSignChange(local_res, recbuf, 0, step); - } - // std::cout<<"RANK "< Date: Fri, 2 Jan 2026 20:39:28 +0300 Subject: [PATCH 03/10] k tree logic --- .../mpi/include/ops_mpi.hpp | 4 +- .../mpi/src/ops_mpi.cpp | 51 +++++++++++-------- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp b/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp index f0c8b92da2..d3bbbb412a 100644 --- a/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp +++ b/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp @@ -2,9 +2,11 @@ #include "konstantinov_s_broadcast/common/include/common.hpp" #include "task/include/task.hpp" +#include namespace konstantinov_s_broadcast { +template class KonstantinovSBroadcastMPI : public BaseTask { public: static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { @@ -15,7 +17,6 @@ class KonstantinovSBroadcastMPI : public BaseTask { private: bool ValidationImpl() override; bool PreProcessingImpl() override; - static void CountSignChange(int &res, const EType *data, int start, int iterations); bool RunImpl() override; bool PostProcessingImpl() override; }; @@ -38,4 +39,5 @@ constexpr MPI_Datatype get_mpi_type() { return MPI_DOUBLE; } + } // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp index 7cd6064b73..e07763fd8c 100644 --- a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp +++ b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp @@ -1,6 +1,6 @@ #include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" -#include + // #include #include #include @@ -11,43 +11,54 @@ namespace konstantinov_s_broadcast { -KonstantinovSBroadcastMPI::KonstantinovSBroadcastMPI(const InType &in) { + template +KonstantinovSBroadcastMPI::KonstantinovSBroadcastMPI(const InType &in) { SetTypeOfTask(GetStaticTypeOfTask()); GetInput() = in; GetOutput() = 0; } -bool KonstantinovSBroadcastMPI::ValidationImpl() { +template +bool KonstantinovSBroadcastMPI::ValidationImpl() { // std::cout << "\t\tValidation mpi\n"; return !GetInput().empty(); } -bool KonstantinovSBroadcastMPI::PreProcessingImpl() { +template +bool KonstantinovSBroadcastMPI::PreProcessingImpl() { return true; } -void KonstantinovSBroadcastMPI::CountSignChange(int &res, const EType *data, int start, int iterations) { - for (int i = start; i < iterations; i++) { - res += static_cast((data[i] > 0) != (data[i + 1] > 0)); - } +template +bool KonstantinovSBroadcastMPI::RunImpl() { + int prank = 0, pcount = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &prank); + MPI_Comm_size(MPI_COMM_WORLD, &pcount); - // for (int i = elemcount - rem; i < elemcount - 1; i++) { - // // std::cout<((sendbuf[i] > 0) != (sendbuf[i + 1] > 0)); - // } + MPI_Datatype mpi_type = MPIDatatype::value(); + + auto& buffer = this->GetInput(); + int elem_count = static_cast(buffer.size()); + T* data = buffer.data(); + + constexpr int root_prank = 0; + constexpr int k = 4; // k-арное дерево + + // ранг процесса в дереве (root = 0) + int tree_rank = (prank - root_prank + pcount) % pcount; + + // родитель в дереве + int parent_tree_rank = (tree_rank - 1) / k; + int parent_prank = (parent_tree_rank < 0) + ? MPI_ANY_SOURCE + : (parent_tree_rank + root_prank) % pcount; - // for (int i = 0; i < step; i++) { - // local_res += static_cast((recbuf[i] > 0) != (recbuf[i + 1] > 0)); - // } -} -template -bool KonstantinovSBroadcastMPI::RunImpl() { - return true; } -bool KonstantinovSBroadcastMPI::PostProcessingImpl() { +template +bool KonstantinovSBroadcastMPI::PostProcessingImpl() { return true; } From 6245d98861e711c04828bf2fa3295b338715a5f6 Mon Sep 17 00:00:00 2001 From: Projectius_student Date: Fri, 2 Jan 2026 22:27:48 +0300 Subject: [PATCH 04/10] send logic --- .../mpi/src/ops_mpi.cpp | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp index e07763fd8c..ed7e3f7cfc 100644 --- a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp +++ b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp @@ -48,12 +48,41 @@ bool KonstantinovSBroadcastMPI::RunImpl() { int tree_rank = (prank - root_prank + pcount) % pcount; // родитель в дереве - int parent_tree_rank = (tree_rank - 1) / k; + int parent_tree_rank = (tree_rank == 0) ? -1 : (tree_rank - 1) / k; int parent_prank = (parent_tree_rank < 0) ? MPI_ANY_SOURCE : (parent_tree_rank + root_prank) % pcount; - + // приём данных от родителя + if (tree_rank != 0) { + MPI_Recv(data, elem_count, mpi_type, + parent_prank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + } + + // вычисляем потомков + std::vector child_pranks; + for (int i = 1; i <= k; ++i) { + int child_tree_rank = (k * tree_rank) + i; + if (child_tree_rank < pcount) { + int child_prank = (child_tree_rank + root_prank) % pcount; + child_pranks.push_back(child_prank); + } + } + + // неблокирующая рассылка детям + std::vector send_requests(child_pranks.size()); + for (std::size_t i = 0; i < child_pranks.size(); ++i) { + MPI_Isend(data, elem_count, mpi_type, + child_pranks[i], 0, MPI_COMM_WORLD, + &send_requests[i]); + } + + if (!send_requests.empty()) { + MPI_Waitall(static_cast(send_requests.size()), + send_requests.data(), MPI_STATUSES_IGNORE); + } + + this->GetOutput() = buffer; return true; } From 8ee3c24ff07fb45a6899ddce0ee6c67c32a305b9 Mon Sep 17 00:00:00 2001 From: Projectius_student Date: Sat, 3 Jan 2026 09:09:38 +0300 Subject: [PATCH 05/10] Tests done and logic revision --- .../common/include/common.hpp | 21 ++++-- tasks/konstantinov_s_broadcast/data/pic.jpg | Bin 23 -> 0 bytes tasks/konstantinov_s_broadcast/info.json | 6 +- .../mpi/include/ops_mpi.hpp | 9 ++- .../mpi/src/ops_mpi.cpp | 54 +++++++------- .../seq/include/ops_seq.hpp | 7 +- .../seq/src/ops_seq.cpp | 42 ++++++----- .../tests/functional/main.cpp | 39 +++++------ .../tests/performance/main.cpp | 18 ++--- .../konstantinov_s_broadcast/tests/testgen.h | 66 ------------------ 10 files changed, 95 insertions(+), 167 deletions(-) delete mode 100644 tasks/konstantinov_s_broadcast/data/pic.jpg delete mode 100644 tasks/konstantinov_s_broadcast/tests/testgen.h diff --git a/tasks/konstantinov_s_broadcast/common/include/common.hpp b/tasks/konstantinov_s_broadcast/common/include/common.hpp index 163b0f5a38..f7f90e2e6d 100644 --- a/tasks/konstantinov_s_broadcast/common/include/common.hpp +++ b/tasks/konstantinov_s_broadcast/common/include/common.hpp @@ -1,18 +1,25 @@ #pragma once -// #include -// #include -// #include +#include +#include +#include #include #include "task/include/task.hpp" namespace konstantinov_s_broadcast { -using EType = double; +using TestType = std::tuple; + +using ETypeInt = int; +using ETypeFloat = float; +using ETypeDouble = double; + +using EType = ETypeInt; using InType = std::vector; -using OutType = int; -using TestType = int; // std::tuple, int>, std::string>; -using BaseTask = ppc::task::Task; +using OutType = InType; + +template +using BaseTask = ppc::task::Task, std::vector>; } // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/data/pic.jpg b/tasks/konstantinov_s_broadcast/data/pic.jpg deleted file mode 100644 index 637624238c89d914613ed301968bffbf462bc110..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23 bcmWGA<1$h(;xaNd<@(RSzyQYo|NjR7KDY + +#include #include "konstantinov_s_broadcast/common/include/common.hpp" #include "task/include/task.hpp" -#include namespace konstantinov_s_broadcast { template -class KonstantinovSBroadcastMPI : public BaseTask { +class KonstantinovSBroadcastMPI : public BaseTask { public: + using InType = std::vector; + using OutType = InType; static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { return ppc::task::TypeOfTask::kMPI; } @@ -39,5 +43,4 @@ constexpr MPI_Datatype get_mpi_type() { return MPI_DOUBLE; } - } // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp index ed7e3f7cfc..47fe15f9fc 100644 --- a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp +++ b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp @@ -1,8 +1,9 @@ #include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" - +#include // #include #include +#include #include // #include @@ -11,17 +12,17 @@ namespace konstantinov_s_broadcast { - template +template KonstantinovSBroadcastMPI::KonstantinovSBroadcastMPI(const InType &in) { - SetTypeOfTask(GetStaticTypeOfTask()); - GetInput() = in; - GetOutput() = 0; + this->SetTypeOfTask(GetStaticTypeOfTask()); + this->GetInput() = in; + this->GetOutput().resize(this->GetInput().size()); } template bool KonstantinovSBroadcastMPI::ValidationImpl() { // std::cout << "\t\tValidation mpi\n"; - return !GetInput().empty(); + return !this->GetInput().empty(); } template @@ -35,28 +36,27 @@ bool KonstantinovSBroadcastMPI::RunImpl() { MPI_Comm_rank(MPI_COMM_WORLD, &prank); MPI_Comm_size(MPI_COMM_WORLD, &pcount); - MPI_Datatype mpi_type = MPIDatatype::value(); + MPI_Datatype mpi_type = get_mpi_type(); - auto& buffer = this->GetInput(); + auto &buffer = this->GetInput(); int elem_count = static_cast(buffer.size()); - T* data = buffer.data(); + T *data = buffer.data(); - constexpr int root_prank = 0; - constexpr int k = 4; // k-арное дерево + int root_prank = pcount - 1; + int k = std::min(4, pcount); // k-арное дерево - // ранг процесса в дереве (root = 0) + // ранг процесса в дереве int tree_rank = (prank - root_prank + pcount) % pcount; // родитель в дереве int parent_tree_rank = (tree_rank == 0) ? -1 : (tree_rank - 1) / k; - int parent_prank = (parent_tree_rank < 0) - ? MPI_ANY_SOURCE - : (parent_tree_rank + root_prank) % pcount; + int parent_prank = (parent_tree_rank < 0) ? -1 : (parent_tree_rank + root_prank) % pcount; - // приём данных от родителя + // приём данных от родителя (если не корень) if (tree_rank != 0) { - MPI_Recv(data, elem_count, mpi_type, - parent_prank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + // std::cout << "Rank " << prank << " (t " << tree_rank << ") recv from "<< parent_prank << " (t " << + // parent_tree_rank << ")\n"; + MPI_Recv(data, elem_count, mpi_type, parent_prank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } // вычисляем потомков @@ -69,17 +69,10 @@ bool KonstantinovSBroadcastMPI::RunImpl() { } } - // неблокирующая рассылка детям - std::vector send_requests(child_pranks.size()); - for (std::size_t i = 0; i < child_pranks.size(); ++i) { - MPI_Isend(data, elem_count, mpi_type, - child_pranks[i], 0, MPI_COMM_WORLD, - &send_requests[i]); - } - - if (!send_requests.empty()) { - MPI_Waitall(static_cast(send_requests.size()), - send_requests.data(), MPI_STATUSES_IGNORE); + // рассылка + for (int ch : child_pranks) { + // std::cout << "Rank " << prank << " (t " << tree_rank << ") send to " << ch << "\n"; + MPI_Send(data, elem_count, mpi_type, ch, 0, MPI_COMM_WORLD); } this->GetOutput() = buffer; @@ -90,5 +83,8 @@ template bool KonstantinovSBroadcastMPI::PostProcessingImpl() { return true; } +template class KonstantinovSBroadcastMPI; +template class KonstantinovSBroadcastMPI; +template class KonstantinovSBroadcastMPI; } // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/seq/include/ops_seq.hpp b/tasks/konstantinov_s_broadcast/seq/include/ops_seq.hpp index c0e490e8e0..323efa645f 100644 --- a/tasks/konstantinov_s_broadcast/seq/include/ops_seq.hpp +++ b/tasks/konstantinov_s_broadcast/seq/include/ops_seq.hpp @@ -1,12 +1,15 @@ #pragma once +#include #include "konstantinov_s_broadcast/common/include/common.hpp" #include "task/include/task.hpp" namespace konstantinov_s_broadcast { - -class KonstantinovSBroadcastSEQ : public BaseTask { +template +class KonstantinovSBroadcastSEQ : public BaseTask { public: + using InType = std::vector; + using OutType = InType; static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { return ppc::task::TypeOfTask::kSEQ; } diff --git a/tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp b/tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp index 99070fd2db..a3f3c2794a 100644 --- a/tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp +++ b/tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp @@ -3,42 +3,40 @@ // #include // #include #include +#include // memcpy #include #include "konstantinov_s_broadcast/common/include/common.hpp" // #include "util/include/util.hpp" namespace konstantinov_s_broadcast { - -KonstantinovSBroadcastSEQ::KonstantinovSBroadcastSEQ(const InType &in) { - SetTypeOfTask(GetStaticTypeOfTask()); - GetInput() = in; - GetOutput() = 0; +template +KonstantinovSBroadcastSEQ::KonstantinovSBroadcastSEQ(const InType &in) { + this->SetTypeOfTask(GetStaticTypeOfTask()); + this->GetInput() = in; + this->GetOutput().resize(this->GetInput().size()); } - -bool KonstantinovSBroadcastSEQ::ValidationImpl() { +template +bool KonstantinovSBroadcastSEQ::ValidationImpl() { // std::cout << "\t\tValidation seq\n"; - return !GetInput().empty(); + return !this->GetInput().empty(); } - -bool KonstantinovSBroadcastSEQ::PreProcessingImpl() { +template +bool KonstantinovSBroadcastSEQ::PreProcessingImpl() { return true; } - -bool KonstantinovSBroadcastSEQ::RunImpl() { - const auto invec = GetInput(); - int res = 0; - size_t iterations = invec.size() - 1; - const EType *v = invec.data(); - for (size_t i = 0; i < iterations; i++) { - res += static_cast((v[i] > 0) != (v[i + 1] > 0)); // + 1 если занки разные - } - GetOutput() = res; +template +bool KonstantinovSBroadcastSEQ::RunImpl() { + memcpy(this->GetOutput().data(), this->GetInput().data(), this->GetInput().size() * sizeof(T)); return true; } - -bool KonstantinovSBroadcastSEQ::PostProcessingImpl() { +template +bool KonstantinovSBroadcastSEQ::PostProcessingImpl() { return true; } +template class KonstantinovSBroadcastSEQ; +template class KonstantinovSBroadcastSEQ; +template class KonstantinovSBroadcastSEQ; + } // namespace konstantinov_s_broadcast diff --git a/tasks/konstantinov_s_broadcast/tests/functional/main.cpp b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp index 21fdff7ec3..39a0969031 100644 --- a/tasks/konstantinov_s_broadcast/tests/functional/main.cpp +++ b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp @@ -15,7 +15,6 @@ #include "konstantinov_s_broadcast/common/include/common.hpp" #include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" #include "konstantinov_s_broadcast/seq/include/ops_seq.hpp" -#include "konstantinov_s_broadcast/tests/testgen.h" #include "util/include/func_test_util.hpp" #include "util/include/util.hpp" @@ -24,29 +23,23 @@ namespace konstantinov_s_broadcast { class KonstantinovSBroadcastTests : public ppc::util::BaseRunFuncTests { public: static std::string PrintTestParam(const TestType &test_param) { - return std::to_string(test_param); + return std::get<1>(test_param) + "_" + std::to_string(std::get<0>(test_param)); } protected: void SetUp() override { TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - - InType vec(params); - vec.resize(params); - std::array arr = {1, -1, 23, -11, -12, -167, 13, 42, -12, 2, -43, 33, 44, -7, 1}; - const int arrsz = 15; - const int chngcnt = 10; - - result_right_ = GenerateTestData(arr.data(), arrsz, chngcnt, vec); - input_data_ = vec; + const int insz = std::get<0>(params); + input_data_.resize(insz); + for (int i = 0; i < insz; ++i) { + input_data_[i] = i; + } } bool CheckTestOutputData(OutType &output_data) final { - // std::cout<<"CHECK: "; - // for(int i=0;i kTestParam = {1, 2, 3, 7, 15, 30, 33}; +const std::array kTestParam = { + std::make_tuple(10, "10"), std::make_tuple(20, "20"), + std::make_tuple(100, "100")}; // тесты с разным корнем дерева не получится создать (неизвестно колво процессов), но + // корнем выбирается последний процесс в самой реализации для разнообразия -const auto kTestTasksList = std::tuple_cat(ppc::util::AddFuncTask( - kTestParam, PPC_SETTINGS_konstantinov_s_broadcast), - ppc::util::AddFuncTask( - kTestParam, PPC_SETTINGS_konstantinov_s_broadcast)); +const auto kTestTasksList = std::tuple_cat( + ppc::util::AddFuncTask, InType>(kTestParam, PPC_SETTINGS_konstantinov_s_broadcast), + ppc::util::AddFuncTask, InType>(kTestParam, + PPC_SETTINGS_konstantinov_s_broadcast)); const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); diff --git a/tasks/konstantinov_s_broadcast/tests/performance/main.cpp b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp index 624cb429ab..0c11025a58 100644 --- a/tasks/konstantinov_s_broadcast/tests/performance/main.cpp +++ b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp @@ -1,11 +1,10 @@ #include -#include +#include #include "konstantinov_s_broadcast/common/include/common.hpp" #include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" #include "konstantinov_s_broadcast/seq/include/ops_seq.hpp" -#include "konstantinov_s_broadcast/tests/testgen.h" #include "util/include/perf_test_util.hpp" namespace konstantinov_s_broadcast { @@ -13,21 +12,14 @@ namespace konstantinov_s_broadcast { class KonstantinovSBroadcastTests : public ppc::util::BaseRunPerfTests { const int kCount_ = 150000000; InType input_data_; - OutType result_right_{}; + // OutType result_right_{}; void SetUp() override { - input_data_.resize(kCount_); - - const std::array arr = {1, -1, 23838, -121, -1223, -567, 12334, 42, -12, 2, -43, 33, 44, -7, 1}; - const int arrsz = 15; - const int chngcnt = 10; - - result_right_ = GenerateTestData(arr.data(), arrsz, chngcnt, input_data_); - // std::cout<( + ppc::util::MakeAllPerfTasks, KonstantinovSBroadcastSEQ>( PPC_SETTINGS_konstantinov_s_broadcast); const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); diff --git a/tasks/konstantinov_s_broadcast/tests/testgen.h b/tasks/konstantinov_s_broadcast/tests/testgen.h deleted file mode 100644 index 9e7b82eb7a..0000000000 --- a/tasks/konstantinov_s_broadcast/tests/testgen.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -#include // memcpy -// #include -// #include - -#include "konstantinov_s_broadcast/common/include/common.hpp" - -namespace konstantinov_s_broadcast { -// СТАБИЛЬНЫЙ генератор тестовых данных -// Нужно подать массив с известным колвом смен знаков и одинаковыми знаками первого и последнего элемента -inline int GenerateTestData(const EType *examplearr, size_t arrsz, int sign_change_count, InType &v) { - size_t m = v.size(); - // std::cout<<"Generating "<((examplearr[i] > 0) != (examplearr[i + 1] > 0)); - } - v[m - 1] = examplearr[m - 1]; - return res; - } - - size_t full_blocks = m / arrsz; - size_t tail = m % arrsz; - - EType *dst = v.data(); - - // Копируем первую копию массива - memcpy(dst, examplearr, arrsz * sizeof(EType)); - size_t filled = 1; // число заполненных блоков - - // Удвоительное копирование блоками - // пока удвоение не превысит количество нужных полных блоков - while (filled * 2 <= full_blocks) { - memcpy(dst + (filled * arrsz), dst, filled * arrsz * sizeof(EType)); - filled *= 2; - } - - // Дозаполняем оставшиеся полные блоки - while (filled < full_blocks) { - memcpy(dst + (filled * arrsz), dst, arrsz * sizeof(EType)); - filled++; - } - - // Хвост = последний элемент чтобы не считать смены знаков там - if (tail > 0) { - EType last = examplearr[arrsz - 1]; - for (size_t i = 0; i < tail; ++i) { - dst[(full_blocks * arrsz) + i] = last; - } - } - - // for(int i=0;i(sign_change_count * full_blocks); -} - -} // namespace konstantinov_s_broadcast From e13559a299cc261e0d5bd91b91fddf8c2c5fde6a Mon Sep 17 00:00:00 2001 From: Projectius_student Date: Sat, 3 Jan 2026 16:36:50 +0300 Subject: [PATCH 06/10] tidy --- tasks/konstantinov_s_broadcast/common/include/common.hpp | 1 - tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp | 8 ++++---- tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp | 8 ++++---- tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp | 2 -- tasks/konstantinov_s_broadcast/tests/functional/main.cpp | 1 + tasks/konstantinov_s_broadcast/tests/performance/main.cpp | 3 +-- 6 files changed, 10 insertions(+), 13 deletions(-) diff --git a/tasks/konstantinov_s_broadcast/common/include/common.hpp b/tasks/konstantinov_s_broadcast/common/include/common.hpp index f7f90e2e6d..bfa6caacec 100644 --- a/tasks/konstantinov_s_broadcast/common/include/common.hpp +++ b/tasks/konstantinov_s_broadcast/common/include/common.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include diff --git a/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp b/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp index ac07e2242c..fa1971a72d 100644 --- a/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp +++ b/tasks/konstantinov_s_broadcast/mpi/include/ops_mpi.hpp @@ -26,20 +26,20 @@ class KonstantinovSBroadcastMPI : public BaseTask { }; template -constexpr MPI_Datatype get_mpi_type(); +constexpr MPI_Datatype GetMpiType(); template <> -constexpr MPI_Datatype get_mpi_type() { +constexpr MPI_Datatype GetMpiType() { return MPI_INT; } template <> -constexpr MPI_Datatype get_mpi_type() { +constexpr MPI_Datatype GetMpiType() { return MPI_FLOAT; } template <> -constexpr MPI_Datatype get_mpi_type() { +constexpr MPI_Datatype GetMpiType() { return MPI_DOUBLE; } diff --git a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp index 47fe15f9fc..f0c71af38c 100644 --- a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp +++ b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp @@ -1,11 +1,10 @@ #include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" #include -// #include #include -#include #include // #include +#include #include "konstantinov_s_broadcast/common/include/common.hpp" // #include "util/include/util.hpp" @@ -32,11 +31,12 @@ bool KonstantinovSBroadcastMPI::PreProcessingImpl() { template bool KonstantinovSBroadcastMPI::RunImpl() { - int prank = 0, pcount = 0; + int prank = 0; + int pcount = 0; MPI_Comm_rank(MPI_COMM_WORLD, &prank); MPI_Comm_size(MPI_COMM_WORLD, &pcount); - MPI_Datatype mpi_type = get_mpi_type(); + MPI_Datatype mpi_type = GetMpiType(); auto &buffer = this->GetInput(); int elem_count = static_cast(buffer.size()); diff --git a/tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp b/tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp index a3f3c2794a..227084a1b9 100644 --- a/tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp +++ b/tasks/konstantinov_s_broadcast/seq/src/ops_seq.cpp @@ -2,9 +2,7 @@ // #include // #include -#include #include // memcpy -#include #include "konstantinov_s_broadcast/common/include/common.hpp" // #include "util/include/util.hpp" diff --git a/tasks/konstantinov_s_broadcast/tests/functional/main.cpp b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp index 39a0969031..3e69acc330 100644 --- a/tasks/konstantinov_s_broadcast/tests/functional/main.cpp +++ b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp @@ -9,6 +9,7 @@ // #include #include #include +#include // #include // #include diff --git a/tasks/konstantinov_s_broadcast/tests/performance/main.cpp b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp index 0c11025a58..e432079591 100644 --- a/tasks/konstantinov_s_broadcast/tests/performance/main.cpp +++ b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp @@ -1,6 +1,5 @@ #include - -#include +#include #include "konstantinov_s_broadcast/common/include/common.hpp" #include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" From 8c634c12398949992fab672120d5c71eb74291be Mon Sep 17 00:00:00 2001 From: Projectius_student Date: Sat, 3 Jan 2026 16:37:12 +0300 Subject: [PATCH 07/10] format --- tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp | 1 + tasks/konstantinov_s_broadcast/tests/functional/main.cpp | 2 +- tasks/konstantinov_s_broadcast/tests/performance/main.cpp | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp index f0c71af38c..366f3cd614 100644 --- a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp +++ b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp @@ -1,6 +1,7 @@ #include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" #include + #include #include // #include diff --git a/tasks/konstantinov_s_broadcast/tests/functional/main.cpp b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp index 3e69acc330..39a0d00ec3 100644 --- a/tasks/konstantinov_s_broadcast/tests/functional/main.cpp +++ b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp @@ -7,9 +7,9 @@ // #include // #include // #include +#include #include #include -#include // #include // #include diff --git a/tasks/konstantinov_s_broadcast/tests/performance/main.cpp b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp index e432079591..f3d78f46b3 100644 --- a/tasks/konstantinov_s_broadcast/tests/performance/main.cpp +++ b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp @@ -1,5 +1,6 @@ #include -#include + +#include #include "konstantinov_s_broadcast/common/include/common.hpp" #include "konstantinov_s_broadcast/mpi/include/ops_mpi.hpp" From e69e7bfc137247404ec94a2e5433a8c3a9f4d53c Mon Sep 17 00:00:00 2001 From: Projectius_student Date: Sat, 3 Jan 2026 20:07:10 +0300 Subject: [PATCH 08/10] more fair MPI no shared memory imitation --- .../mpi/src/ops_mpi.cpp | 43 ++++++++++++------- .../tests/functional/main.cpp | 4 +- .../tests/performance/main.cpp | 2 +- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp index 366f3cd614..6fbb1b20ab 100644 --- a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp +++ b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp @@ -37,14 +37,15 @@ bool KonstantinovSBroadcastMPI::RunImpl() { MPI_Comm_rank(MPI_COMM_WORLD, &prank); MPI_Comm_size(MPI_COMM_WORLD, &pcount); + const int TAG_COUNT = 1; + const int TAG_DATA = 2; + MPI_Datatype mpi_type = GetMpiType(); - auto &buffer = this->GetInput(); - int elem_count = static_cast(buffer.size()); - T *data = buffer.data(); + T *odata = nullptr; int root_prank = pcount - 1; - int k = std::min(4, pcount); // k-арное дерево + int k = std::min(2, pcount); // k-арное дерево // ранг процесса в дереве int tree_rank = (prank - root_prank + pcount) % pcount; @@ -53,30 +54,40 @@ bool KonstantinovSBroadcastMPI::RunImpl() { int parent_tree_rank = (tree_rank == 0) ? -1 : (tree_rank - 1) / k; int parent_prank = (parent_tree_rank < 0) ? -1 : (parent_tree_rank + root_prank) % pcount; - // приём данных от родителя (если не корень) - if (tree_rank != 0) { + int recv_count = 0; + // приём данных от родителя (корень читает доступные ему данные) + if (tree_rank == 0) { + auto &ibuffer = this->GetInput(); + int elem_count = static_cast(ibuffer.size()); + odata = ibuffer.data(); + recv_count = elem_count; + this->GetOutput() = ibuffer; + } else { // std::cout << "Rank " << prank << " (t " << tree_rank << ") recv from "<< parent_prank << " (t " << // parent_tree_rank << ")\n"; - MPI_Recv(data, elem_count, mpi_type, parent_prank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&recv_count, 1, MPI_INT, parent_prank, TAG_COUNT, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + odata = new T[recv_count]; + MPI_Recv(odata, recv_count, mpi_type, parent_prank, TAG_DATA, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + memcpy(this->GetOutput().data(), odata, recv_count * sizeof(T)); } - // вычисляем потомков - std::vector child_pranks; + // вычисляем потомков и рассылаем + // std::vector child_pranks; for (int i = 1; i <= k; ++i) { int child_tree_rank = (k * tree_rank) + i; if (child_tree_rank < pcount) { int child_prank = (child_tree_rank + root_prank) % pcount; - child_pranks.push_back(child_prank); + // std::cout << "Rank " << prank << " (t " << tree_rank << ") send to " << ch << "\n"; + MPI_Send(&recv_count, 1, MPI_INT, child_prank, TAG_COUNT, MPI_COMM_WORLD); + MPI_Send(odata, recv_count, mpi_type, child_prank, TAG_DATA, MPI_COMM_WORLD); + // child_pranks.push_back(child_prank); } } - - // рассылка - for (int ch : child_pranks) { - // std::cout << "Rank " << prank << " (t " << tree_rank << ") send to " << ch << "\n"; - MPI_Send(data, elem_count, mpi_type, ch, 0, MPI_COMM_WORLD); + if (tree_rank != 0) { + delete[] odata; } - this->GetOutput() = buffer; + // this->GetOutput() = ibuffer; return true; } diff --git a/tasks/konstantinov_s_broadcast/tests/functional/main.cpp b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp index 39a0d00ec3..de12fb9c81 100644 --- a/tasks/konstantinov_s_broadcast/tests/functional/main.cpp +++ b/tasks/konstantinov_s_broadcast/tests/functional/main.cpp @@ -57,8 +57,8 @@ TEST_P(KonstantinovSBroadcastTests, CustomBroadcast) { ExecuteTest(GetParam()); } -const std::array kTestParam = { - std::make_tuple(10, "10"), std::make_tuple(20, "20"), +const std::array kTestParam = { + std::make_tuple(1, "1"), std::make_tuple(2, "2"), std::make_tuple(10, "10"), std::make_tuple(100, "100")}; // тесты с разным корнем дерева не получится создать (неизвестно колво процессов), но // корнем выбирается последний процесс в самой реализации для разнообразия diff --git a/tasks/konstantinov_s_broadcast/tests/performance/main.cpp b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp index f3d78f46b3..7d7405f171 100644 --- a/tasks/konstantinov_s_broadcast/tests/performance/main.cpp +++ b/tasks/konstantinov_s_broadcast/tests/performance/main.cpp @@ -10,7 +10,7 @@ namespace konstantinov_s_broadcast { class KonstantinovSBroadcastTests : public ppc::util::BaseRunPerfTests { - const int kCount_ = 150000000; + const int kCount_ = 10000000; InType input_data_; // OutType result_right_{}; From 3ba4fa6eca2dc0b2c8f160e910d18c769422a620 Mon Sep 17 00:00:00 2001 From: Projectius_student Date: Sat, 3 Jan 2026 21:37:03 +0300 Subject: [PATCH 09/10] tidy and report --- .../mpi/src/ops_mpi.cpp | 13 +++-- tasks/konstantinov_s_broadcast/report.md | 53 +++++++++---------- 2 files changed, 30 insertions(+), 36 deletions(-) diff --git a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp index 6fbb1b20ab..af692f2a34 100644 --- a/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp +++ b/tasks/konstantinov_s_broadcast/mpi/src/ops_mpi.cpp @@ -3,7 +3,6 @@ #include #include -#include // #include #include @@ -37,8 +36,8 @@ bool KonstantinovSBroadcastMPI::RunImpl() { MPI_Comm_rank(MPI_COMM_WORLD, &prank); MPI_Comm_size(MPI_COMM_WORLD, &pcount); - const int TAG_COUNT = 1; - const int TAG_DATA = 2; + const int tag_count = 1; + const int tag_data = 2; MPI_Datatype mpi_type = GetMpiType(); @@ -65,9 +64,9 @@ bool KonstantinovSBroadcastMPI::RunImpl() { } else { // std::cout << "Rank " << prank << " (t " << tree_rank << ") recv from "<< parent_prank << " (t " << // parent_tree_rank << ")\n"; - MPI_Recv(&recv_count, 1, MPI_INT, parent_prank, TAG_COUNT, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(&recv_count, 1, MPI_INT, parent_prank, tag_count, MPI_COMM_WORLD, MPI_STATUS_IGNORE); odata = new T[recv_count]; - MPI_Recv(odata, recv_count, mpi_type, parent_prank, TAG_DATA, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(odata, recv_count, mpi_type, parent_prank, tag_data, MPI_COMM_WORLD, MPI_STATUS_IGNORE); memcpy(this->GetOutput().data(), odata, recv_count * sizeof(T)); } @@ -78,8 +77,8 @@ bool KonstantinovSBroadcastMPI::RunImpl() { if (child_tree_rank < pcount) { int child_prank = (child_tree_rank + root_prank) % pcount; // std::cout << "Rank " << prank << " (t " << tree_rank << ") send to " << ch << "\n"; - MPI_Send(&recv_count, 1, MPI_INT, child_prank, TAG_COUNT, MPI_COMM_WORLD); - MPI_Send(odata, recv_count, mpi_type, child_prank, TAG_DATA, MPI_COMM_WORLD); + MPI_Send(&recv_count, 1, MPI_INT, child_prank, tag_count, MPI_COMM_WORLD); + MPI_Send(odata, recv_count, mpi_type, child_prank, tag_data, MPI_COMM_WORLD); // child_pranks.push_back(child_prank); } } diff --git a/tasks/konstantinov_s_broadcast/report.md b/tasks/konstantinov_s_broadcast/report.md index 3f1a0bdc6c..6c0e25b090 100644 --- a/tasks/konstantinov_s_broadcast/report.md +++ b/tasks/konstantinov_s_broadcast/report.md @@ -1,55 +1,50 @@ -# Нахождение числа чередований знаков значений соседних элементов вектора +# Передача от одного всем (broadcast) - Student: Константинов Семён Анатольевич, group 3823Б1ФИ3 - Technology: SEQ | MPI -- Variant: 5 +- Variant: 1 ## 1. Introduction -Задача подсчёта числа чередований знака элементов вектора - простая задача с немного нетривиальными способами распараллеливания. Ускорение параллельного решения должно быть близко к количеству процессов. - +Эффективная рассылка данных от одного процесса всем остальным - важная часть в работе MPI, реализуемая функцией MPI_Bcast. Алгоритм пересылки данных можно повторить, взяв за основу идею k-арного дерева и используя только базовые операции `MPI_Recv` и `MPI_Send`. ## 2. Problem Statement ### Входные данные: - -Дан вектор длины `N`, состоящий из элементов типа `double`. Считаем что элементов-нулей во входном векторе нет. - +- Ранг процесса, который будет корневым в дереве +- Массив входных данных ### Выходные данные: - -Значение типа `int`, равное количеству смен знака значения соседних элементов вектора. - +- Одинаковые массивы на всех процессах, совпадающие с входным массивом ## 3. Baseline Algorithm (Sequential) -Инициализируем ответ значением 0. Проходимся циклом по элементам вектора от 0 до `N-2`, прибавляя к ответу 1 если знак текущего элемента не соответствует знаку следующего. +Последовательный алгоритм не имеет смысла в контексте алгоритмов обмена данными между процессами. Реализовано копирование входного массива в выходной. ## 4. Parallelization Scheme -Нулевой ранг (будем называть его корень) вычисляет и отправляет другим процессам step - число элементов вектора, выделяемых каждому процессу. -Процессам выделяются подряд идущие подмассивы так, что последний элемент текущего массива совпадает с первым элементом следующего, это необходимо для правильного подсчёта чередований знаков на границе блоков. -Корень рассылает по step элементов на остальные процессы с помощью MPI_Scatterv, последний неполный блок оставляет себе. -Каждый процесс обрабатывает свою часть данных по ранее описанному последовательному алгоритму. -Благодаря тому что блоки пересекаются не теряются смены знака на стыках, поэтому для получения итогового количества используется редукция суммой (MPI_Allreduce). +Алгоритм основан на k-арном дереве: каждый процесс из своего ранга процесса `prank`, ранга корня дерева `root_prank` и количества процессов `pcount` получает свой ранг в дереве `tree_rank = (prank - root_prank + pcount) % pcount`. Из тех же данных вычисляются ранги в дереве и ранги процесса у родителя процесса и каждого из от 0 до k детей процесса. Сначала процессы ожидают данные от своего родителя (сначала данные о размере массива, затем сам массив). Уже имеющие данные (сначала только корень) отсылают их своим детям. +Таким образом данные достигают всех процессов за log от числа процессов операций. ## 5. Experimental Setup - Hardware/OS: ЦП AMD Ryzen 5 3600 6-Core Processor, 16 GB RAM, Windows 10 x64 - Toolchain: Cmake 4.2.0, Visual Studio 2022, MSVC, x64 Release - Environment: PPC_NUM_THREADS=PPC_NUM_PROC=1/2/4/6/8/10/12/14/16/20/24/32/40/60/80, PPC_PERF_MAX_TIME=10000 -- Data: стабильная генерация тестовых данных путём повторения вектора-образца, для теста производительности генерируется вектор в 150000000 элементов +- Data: стабильная генерация тестовых данных разного размера, различный выбор корня дерева ## 6. Results and Discussion ### 6.1 Correctness -Вектор-образец для генерации тестов имеет известное число смен знака (образец все комбинации знаков соседних элементов) и одинаковый знак первого и последнего элемента, верное число смен знака для тестовых данных вычисляется на этапе генерации умножением этого числа из образца на количество целых образцов в итоговом массиве (остаток не содержит смен знака). +Корректность проверяется сравнением входного и выходного массивов. Корректность проверена на векторах разных размеров. ### 6.2 Performance - -| Mode | Count | Time, s | Speedup | Efficiency | -|-------------|-------|---------|---------|------------| -| seq | 1 | 0.706 | 1.00 | N/A | -| omp | 2 | 1.080 | 0.65 | 32.5% | -| omp | 3 | 1.065 | 0.66 | 22% | -| omp | 4 | 1.011 | 0.69 | 17.25% | +Измерение производительности не имеет смысла, так как количество работы зависит от числа процессов, но оно было проведено. +За эталон производительности взято время выполнения mpi версии на одном процессе. + +| Count | Time, s | Speedup | Efficiency | +| ----- | ------- | ------- | ---------- | +| 1 | 0.0260 | 1.00 | N/A | +| 2 | 0.0263 | 0.98 | 49.4% | +| 4 | 0.0422 | 0.61 | 15.4% | +| 8 | 0.0894 | 0.29 | 0.036% | +| 12 | 0.1256 | 0.207 | 0.017% | +| 24 | 0.2550 | 0.102 | 0.004% | ## 7. Conclusions -Данных много, операции недорогие и их мало - больше времени уходит на работу с памятью, чем на вычисления. Накладные расходы MPI на пересылку данных серьёзно уменьшают эффективность. Без пересылки данных ускорение могло бы быть близким к линейному (параллелизация вынуждает обрабатывать лишь на один элемент больше каждому процессу). - +Была разработана реализация алгоритма передачи данных от одного процесса на все. Реализация шаблонная, позволяет пересылать любые тривиально копируемые типы данных, алгоритм построения дерева позволяет выбрать любой процесс в качестве корня. ## 8. References -1. Курс лекций ННГУ "Параллельное программирование для кластерных систем" - +1. Курс лекций ННГУ "Параллельное программирование для кластерных систем" \ No newline at end of file From cf18c1bd397040341e47a981d5228353795fd10e Mon Sep 17 00:00:00 2001 From: Projectius_student Date: Sat, 3 Jan 2026 21:54:16 +0300 Subject: [PATCH 10/10] report++ --- tasks/konstantinov_s_broadcast/report.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tasks/konstantinov_s_broadcast/report.md b/tasks/konstantinov_s_broadcast/report.md index 6c0e25b090..9a3129db0c 100644 --- a/tasks/konstantinov_s_broadcast/report.md +++ b/tasks/konstantinov_s_broadcast/report.md @@ -16,7 +16,14 @@ Последовательный алгоритм не имеет смысла в контексте алгоритмов обмена данными между процессами. Реализовано копирование входного массива в выходной. ## 4. Parallelization Scheme -Алгоритм основан на k-арном дереве: каждый процесс из своего ранга процесса `prank`, ранга корня дерева `root_prank` и количества процессов `pcount` получает свой ранг в дереве `tree_rank = (prank - root_prank + pcount) % pcount`. Из тех же данных вычисляются ранги в дереве и ранги процесса у родителя процесса и каждого из от 0 до k детей процесса. Сначала процессы ожидают данные от своего родителя (сначала данные о размере массива, затем сам массив). Уже имеющие данные (сначала только корень) отсылают их своим детям. +Алгоритм основан на k-арном дереве: каждый процесс из своего ранга процесса `prank`, ранга корня дерева `root_prank` и количества процессов `pcount` получает свой ранг в дереве `tree_rank = (prank - root_prank + pcount) % pcount`. Из тех же данных вычисляются ранги в дереве и ранги процесса у родителя процесса и каждого из от 0 до k детей процесса. +``` + parent_tree_rank = (tree_rank == 0) ? -1 : (tree_rank - 1) / k; + parent_prank = (parent_tree_rank < 0) ? -1 : (parent_tree_rank + root_prank) % pcount; + child_tree_rank = (k * tree_rank) + i