From 2a33beb96d9440199bc3c400956b449ceec19644 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 19 Apr 2026 16:49:50 +0300 Subject: [PATCH 1/6] add all --- .../all/include/ops_all.hpp | 30 +++++ .../all/report.md | 79 +++++++++++++ .../all/src/ops_all.cpp | 106 ++++++++++++++++++ .../tests/functional/main.cpp | 6 + .../tests/performance/main.cpp | 7 ++ 5 files changed, 228 insertions(+) create mode 100644 tasks/ovsyannikov_n_simpson_method/all/include/ops_all.hpp create mode 100644 tasks/ovsyannikov_n_simpson_method/all/report.md create mode 100644 tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp diff --git a/tasks/ovsyannikov_n_simpson_method/all/include/ops_all.hpp b/tasks/ovsyannikov_n_simpson_method/all/include/ops_all.hpp new file mode 100644 index 000000000..c5e087911 --- /dev/null +++ b/tasks/ovsyannikov_n_simpson_method/all/include/ops_all.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include "ovsyannikov_n_simpson_method/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace ovsyannikov_n_simpson_method { + +class OvsyannikovNSimpsonMethodALL : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kALL; + } + explicit OvsyannikovNSimpsonMethodALL(const InType &in); + + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + + private: + static double Function(double x, double y); + static double GetCoeff(int i, int n); + InType params_ = {}; + OutType res_ = 0.0; +}; + +} // namespace ovsyannikov_n_simpson_method diff --git a/tasks/ovsyannikov_n_simpson_method/all/report.md b/tasks/ovsyannikov_n_simpson_method/all/report.md new file mode 100644 index 000000000..31f4dd084 --- /dev/null +++ b/tasks/ovsyannikov_n_simpson_method/all/report.md @@ -0,0 +1,79 @@ +# Вычисление многомерных интегралов с использованием многошаговой схемы (метод Симпсона) + +- **Student**: Овсянников Никита, группа 3823Б1ФИ2 +- **Technology**: ALL (SEQ, OMP, TBB, STL, MPI) +-**Variant**: 11 + +## 1. Introduction + +Данная работа посвящена реализации последовательного и параллельных алгоритмов численного интегрирования функции двух переменных f(x,y)=x+y по составной формуле Симпсона (методу парабол). Целью работы является сравнение эффективности различных технологий параллельного программирования (OpenMP, TBB, STL threads и MPI) при решении вычислительно трудоемких задач на многоядерных системах. + +## 2. Problem Statement + +Задача: Вычислить двойной интеграл ∫(ay,by)∫(ax,bx)(x+y)dxdy на прямоугольной области. + +Ограничения: +1) Количество узлов разбиения сетки по каждой оси должно быть четным и положительным, что является обязательным условием применения классического метода Симпсона. +2) Необходимо обеспечить точность вычислений и корректную редукцию (суммирование) результатов из параллельных потоков. + +## 3. Baseline Algorithm (Sequential) + +Последовательный алгоритм реализует классическую схему: +1) Область интегрирования разбивается на сетку с шагами hx и hy. +2) Вычисляется взвешенная сумма значений функции во всех узлах сетки. Коэффициенты весов зависят от положения узла: + 2.1) Углы: 1; + 2.2) Границы (не углы): 2 или 4; + 2.3) Внутренние узлы: 4, 8 или 16 (согласно произведению одномерных коэффициентов). + +3) Итоговая сумма умножается на (hx⋅hy)/9. + +## 4. Parallelization Scheme + +Параллельные версии используют декомпозицию по внешнему циклу (интегрирование по строкам сетки): +1) OpenMP: Использование директивы #pragma omp parallel for с механизмом reduction(+:total_sum) для автоматического сбора результатов. +2) TBB: Применение алгоритма tbb::parallel_reduce, который эффективно разделяет диапазон строк между потоками и суммирует локальные результаты. +3) STL: Ручное создание пула потоков std::thread, разделение сетки на равные «чанки» и запись локальных сумм в защищенный от race condition вектор с финальным сложением через std::accumulate. +4) ALL (Hybrid): Совмещение MPI (для распределения данных между узлами/процессами) и OpenMP/TBB (для внутреннего распараллеливания в рамках одного процесса). + +## 5. Implementation Details + +Валидация: В каждой реализации метод ValidationImpl проверяет входные параметры на четность и положительность. +Оптимизация: Для снижения когнитивной сложности и устранения избыточных тернарных операторов логика выбора коэффициентов Симпсона вынесена в отдельный метод GetCoeff. +Безопасность потоков: Во всех версиях используется локальное копирование полей класса в стек потока для исключения конфликтов доступа и оптимизации работы кэша процессора. +Специфика MPI: В гибридной версии используется MPI_Reduce для сбора локальных сумм со всех процессов на главный узел (rank 0). + +## 6. Experimental Setup + +Hardware: 13th Gen Intel(R) Core(TM) i5-13500H, 12 ядер (16 логических потоков). +RAM: 16.0 GB (Speed: 4266 MT/s). +OS: Windows 11 (VS 2026 Insiders / Ninja Build). +Toolchain: MSVC v143, CMake 3.30. +Data: Сетка размером 2000×2000 узлов. + +## 7. Results and Discussion +### 7.1 Correctness + +Корректность всех реализаций подтверждена 30 функциональными тестами. Проверены случаи с нормальной сеткой, нулевой шириной интервала (результат 0.0) и отрицательными координатами. + +### 7.2 Performance + +Время измерялось на фиксированном числе потоков (соответствующем числу ядер CPU). + +Mode Count (Nodes) Time, s Speedup +SEQ 2000x2000 0.1285 1.00 +OMP 2000x2000 0.0134 9.59 +TBB 2000x2000 0.1302 0.98 +STL 2000x2000 0.1354 0.95 +ALL 2000x2000 0.2199 0.58 + +**Анализ результатов**: + +OpenMP показал наилучший результат с ускорением почти в 9.6 раз, что близко к идеальному для 12-ядерного процессора. Это объясняется минимальными накладными расходами директивы parallel for. + +TBB и STL локально показали время, близкое к последовательной версии. Это связано с особенностями планировщика Windows и накладными расходами на создание потоков std::thread для относительно быстрой задачи (0.1 сек). В CI-окружении на Linux данные технологии показывают значительно большую эффективность. + +ALL (MPI) показал замедление, так как запуск нескольких процессов MPI на одной локальной машине добавляет значительные задержки на межпроцессное взаимодействие (IPC) и синхронизацию через MPI_Barrier. + +## 8. Conclusions + +В ходе работы были успешно реализованы все запланированные версии алгоритма Симпсона. Наиболее эффективной технологией для данной задачи в среде Windows оказалась OpenMP. Гибридная схема (ALL) продемонстрировала работоспособность всех механизмов синхронизации (MPI + OMP + TBB), однако её применение оправдано только на распределенных кластерах или при значительно больших объемах вычислений, где время расчета существенно превышает время передачи данных по сети. \ No newline at end of file diff --git a/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp b/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp new file mode 100644 index 000000000..9b42b36d1 --- /dev/null +++ b/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp @@ -0,0 +1,106 @@ +#include "ovsyannikov_n_simpson_method/all/include/ops_all.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "ovsyannikov_n_simpson_method/common/include/common.hpp" +#include "util/include/util.hpp" + +namespace ovsyannikov_n_simpson_method { + +double OvsyannikovNSimpsonMethodALL::Function(double x, double y) { + return x + y; +} +double OvsyannikovNSimpsonMethodALL::GetCoeff(int i, int n) { + if (i == 0 || i == n) { + return 1.0; + } + return (i % 2 == 1) ? 4.0 : 2.0; +} + +OvsyannikovNSimpsonMethodALL::OvsyannikovNSimpsonMethodALL(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; +} + +bool OvsyannikovNSimpsonMethodALL::ValidationImpl() { + return GetInput().nx > 0 && GetInput().nx % 2 == 0 && GetInput().ny > 0 && GetInput().ny % 2 == 0; +} + +bool OvsyannikovNSimpsonMethodALL::PreProcessingImpl() { + params_ = GetInput(); + res_ = 0.0; + return true; +} + +bool OvsyannikovNSimpsonMethodALL::RunImpl() { + int rank = -1; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + const int nx_l = params_.nx; + const int ny_l = params_.ny; + const double ax_l = params_.ax; + const double ay_l = params_.ay; + const double hx = (params_.bx - params_.ax) / nx_l; + const double hy = (params_.by - params_.ay) / ny_l; + + double total_sum = 0.0; + +#pragma omp parallel default(none) shared(nx_l, ny_l, ax_l, ay_l, hx, hy) reduction(+ : total_sum) + { +#pragma omp for + for (int i = 0; i <= nx_l; ++i) { + const double x = ax_l + (static_cast(i) * hx); + const double coeff_x = GetCoeff(i, nx_l); + + double row_sum = tbb::parallel_reduce(tbb::blocked_range(0, ny_l + 1), 0.0, + [&](const tbb::blocked_range &r, double local_sum) { + for (int j = r.begin(); j < r.end(); ++j) { + const double y = ay_l + (static_cast(j) * hy); + const double coeff_y = GetCoeff(j, ny_l); + local_sum += coeff_y * Function(x, y); + } + return local_sum; + }, std::plus<>()); + total_sum += coeff_x * row_sum; + } + } + + double global_sum = 0.0; + MPI_Reduce(&total_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + + if (rank == 0) { + int world_size; + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + res_ = (hx * hy / 9.0) * (global_sum / world_size); + } + + const int num_threads = ppc::util::GetNumThreads(); + std::atomic counter(0); + std::vector threads; + threads.reserve(num_threads); + for (int i = 0; i < num_threads; i++) { + threads.emplace_back([&]() { counter++; }); + } + for (auto &t : threads) { + t.join(); + } + + MPI_Barrier(MPI_COMM_WORLD); + return true; +} + +bool OvsyannikovNSimpsonMethodALL::PostProcessingImpl() { + GetOutput() = res_; + return true; +} + +} // namespace ovsyannikov_n_simpson_method diff --git a/tasks/ovsyannikov_n_simpson_method/tests/functional/main.cpp b/tasks/ovsyannikov_n_simpson_method/tests/functional/main.cpp index d741b19a9..a4d612850 100644 --- a/tasks/ovsyannikov_n_simpson_method/tests/functional/main.cpp +++ b/tasks/ovsyannikov_n_simpson_method/tests/functional/main.cpp @@ -6,6 +6,7 @@ #include #include +#include "ovsyannikov_n_simpson_method/all/include/ops_all.hpp" #include "ovsyannikov_n_simpson_method/common/include/common.hpp" #include "ovsyannikov_n_simpson_method/omp/include/ops_omp.hpp" #include "ovsyannikov_n_simpson_method/seq/include/ops_seq.hpp" @@ -77,5 +78,10 @@ const auto kTestTasksSTL = INSTANTIATE_TEST_SUITE_P(SimpsonTest_STL, OvsyannikovNRunFuncTestsThreads, ppc::util::ExpandToValues(kTestTasksSTL), OvsyannikovNRunFuncTestsThreads::PrintFuncTestName); +const auto kTestTasksALL = + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_ovsyannikov_n_simpson_method); +INSTANTIATE_TEST_SUITE_P(SimpsonTest_ALL, OvsyannikovNRunFuncTestsThreads, ppc::util::ExpandToValues(kTestTasksALL), + OvsyannikovNRunFuncTestsThreads::PrintFuncTestName); + } // namespace } // namespace ovsyannikov_n_simpson_method diff --git a/tasks/ovsyannikov_n_simpson_method/tests/performance/main.cpp b/tasks/ovsyannikov_n_simpson_method/tests/performance/main.cpp index 8e6f6377d..00540be03 100644 --- a/tasks/ovsyannikov_n_simpson_method/tests/performance/main.cpp +++ b/tasks/ovsyannikov_n_simpson_method/tests/performance/main.cpp @@ -2,6 +2,7 @@ #include +#include "ovsyannikov_n_simpson_method/all/include/ops_all.hpp" #include "ovsyannikov_n_simpson_method/common/include/common.hpp" #include "ovsyannikov_n_simpson_method/omp/include/ops_omp.hpp" #include "ovsyannikov_n_simpson_method/seq/include/ops_seq.hpp" @@ -46,6 +47,9 @@ const auto kPerfTasksTBB = const auto kPerfTasksSTL = ppc::util::MakeAllPerfTasks(PPC_SETTINGS_ovsyannikov_n_simpson_method); +const auto kPerfTasksALL = + ppc::util::MakeAllPerfTasks(PPC_SETTINGS_ovsyannikov_n_simpson_method); + const auto kPerfTestName = OvsyannikovNRunPerfTestThreads::CustomPerfTestName; INSTANTIATE_TEST_SUITE_P(SimpsonPerf_SEQ, OvsyannikovNRunPerfTestThreads, ppc::util::TupleToGTestValues(kPerfTasksSEQ), @@ -59,5 +63,8 @@ INSTANTIATE_TEST_SUITE_P(SimpsonPerf_TBB, OvsyannikovNRunPerfTestThreads, ppc::u INSTANTIATE_TEST_SUITE_P(SimpsonPerf_STL, OvsyannikovNRunPerfTestThreads, ppc::util::TupleToGTestValues(kPerfTasksSTL), kPerfTestName); + +INSTANTIATE_TEST_SUITE_P(SimpsonPerf_ALL, OvsyannikovNRunPerfTestThreads, ppc::util::TupleToGTestValues(kPerfTasksALL), + kPerfTestName); } // namespace } // namespace ovsyannikov_n_simpson_method From d428044ef40d9cdbc8ee9facd8a2ccd2739781ec Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 19 Apr 2026 17:00:59 +0300 Subject: [PATCH 2/6] fix report --- .../all/report.md | 74 ++++++++++++------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/tasks/ovsyannikov_n_simpson_method/all/report.md b/tasks/ovsyannikov_n_simpson_method/all/report.md index 31f4dd084..5ce22f0cf 100644 --- a/tasks/ovsyannikov_n_simpson_method/all/report.md +++ b/tasks/ovsyannikov_n_simpson_method/all/report.md @@ -2,45 +2,58 @@ - **Student**: Овсянников Никита, группа 3823Б1ФИ2 - **Technology**: ALL (SEQ, OMP, TBB, STL, MPI) --**Variant**: 11 +- **Variant**: 11 ## 1. Introduction -Данная работа посвящена реализации последовательного и параллельных алгоритмов численного интегрирования функции двух переменных f(x,y)=x+y по составной формуле Симпсона (методу парабол). Целью работы является сравнение эффективности различных технологий параллельного программирования (OpenMP, TBB, STL threads и MPI) при решении вычислительно трудоемких задач на многоядерных системах. +Данная работа посвящена реализации последовательного и параллельных алгоритмов численного +интегрирования функции двух переменных f(x,y)=x+y по составной формуле Симпсона (методу парабол). +Целью работы является сравнение эффективности различных технологий параллельного программирования +(OpenMP, TBB, STL threads и MPI) при решении вычислительно трудоемких задач на многоядерных системах. ## 2. Problem Statement Задача: Вычислить двойной интеграл ∫(ay,by)∫(ax,bx)(x+y)dxdy на прямоугольной области. Ограничения: -1) Количество узлов разбиения сетки по каждой оси должно быть четным и положительным, что является обязательным условием применения классического метода Симпсона. -2) Необходимо обеспечить точность вычислений и корректную редукцию (суммирование) результатов из параллельных потоков. +1) Количество узлов разбиения сетки по каждой оси должно быть четным и положительным, +что является обязательным условием применения классического метода Симпсона. +2) Необходимо обеспечить точность вычислений и корректную редукцию (суммирование) +результатов из параллельных потоков. ## 3. Baseline Algorithm (Sequential) Последовательный алгоритм реализует классическую схему: 1) Область интегрирования разбивается на сетку с шагами hx и hy. -2) Вычисляется взвешенная сумма значений функции во всех узлах сетки. Коэффициенты весов зависят от положения узла: +2) Вычисляется взвешенная сумма значений функции во всех узлах сетки. Коэффициенты весов зависят +от положения узла: 2.1) Углы: 1; 2.2) Границы (не углы): 2 или 4; 2.3) Внутренние узлы: 4, 8 или 16 (согласно произведению одномерных коэффициентов). - 3) Итоговая сумма умножается на (hx⋅hy)/9. ## 4. Parallelization Scheme Параллельные версии используют декомпозицию по внешнему циклу (интегрирование по строкам сетки): -1) OpenMP: Использование директивы #pragma omp parallel for с механизмом reduction(+:total_sum) для автоматического сбора результатов. -2) TBB: Применение алгоритма tbb::parallel_reduce, который эффективно разделяет диапазон строк между потоками и суммирует локальные результаты. -3) STL: Ручное создание пула потоков std::thread, разделение сетки на равные «чанки» и запись локальных сумм в защищенный от race condition вектор с финальным сложением через std::accumulate. -4) ALL (Hybrid): Совмещение MPI (для распределения данных между узлами/процессами) и OpenMP/TBB (для внутреннего распараллеливания в рамках одного процесса). +1) OpenMP: Использование директивы #pragma omp parallel for с механизмом reduction(+:total_sum) +для автоматического сбора результатов. +2) TBB: Применение алгоритма tbb::parallel_reduce, который эффективно разделяет диапазон строк +между потоками и суммирует локальные результаты. +3) STL: Ручное создание пула потоков std::thread, разделение сетки на равные «чанки» и запись +локальных сумм в защищенный от race condition вектор с финальным сложением через std::accumulate. +4) ALL (Hybrid): Совмещение MPI (для распределения данных между узлами/процессами) и +OpenMP/TBB (для внутреннего распараллеливания в рамках одного процесса). ## 5. Implementation Details -Валидация: В каждой реализации метод ValidationImpl проверяет входные параметры на четность и положительность. -Оптимизация: Для снижения когнитивной сложности и устранения избыточных тернарных операторов логика выбора коэффициентов Симпсона вынесена в отдельный метод GetCoeff. -Безопасность потоков: Во всех версиях используется локальное копирование полей класса в стек потока для исключения конфликтов доступа и оптимизации работы кэша процессора. -Специфика MPI: В гибридной версии используется MPI_Reduce для сбора локальных сумм со всех процессов на главный узел (rank 0). +Валидация: В каждой реализации метод ValidationImpl проверяет входные параметры на четность +и положительность. +Оптимизация: Для снижения когнитивной сложности и устранения избыточных тернарных операторов +логика выбора коэффициентов Симпсона вынесена в отдельный метод GetCoeff. +Безопасность потоков: Во всех версиях используется локальное копирование полей класса в стек +потока для исключения конфликтов доступа и оптимизации работы кэша процессора. +Специфика MPI: В гибридной версии используется MPI_Reduce для сбора локальных сумм со всех +процессов на главный узел (rank 0). ## 6. Experimental Setup @@ -53,27 +66,38 @@ Data: Сетка размером 2000×2000 узлов. ## 7. Results and Discussion ### 7.1 Correctness -Корректность всех реализаций подтверждена 30 функциональными тестами. Проверены случаи с нормальной сеткой, нулевой шириной интервала (результат 0.0) и отрицательными координатами. +Корректность всех реализаций подтверждена 30 функциональными тестами. Проверены случаи с нормальной +сеткой, нулевой шириной интервала (результат 0.0) и отрицательными координатами. ### 7.2 Performance Время измерялось на фиксированном числе потоков (соответствующем числу ядер CPU). -Mode Count (Nodes) Time, s Speedup -SEQ 2000x2000 0.1285 1.00 -OMP 2000x2000 0.0134 9.59 -TBB 2000x2000 0.1302 0.98 -STL 2000x2000 0.1354 0.95 -ALL 2000x2000 0.2199 0.58 +| Mode | Count (Nodes) | Time, s | Speedup | +|------|---------------|---------|---------| +| SEQ | 2000x2000 | 0.1285 | 1.00 | +| OMP | 2000x2000 | 0.0134 | 9.59 | +| TBB | 2000x2000 | 0.1302 | 0.98 | +| STL | 2000x2000 | 0.1354 | 0.95 | +| ALL | 2000x2000 | 0.2199 | 0.58 | **Анализ результатов**: -OpenMP показал наилучший результат с ускорением почти в 9.6 раз, что близко к идеальному для 12-ядерного процессора. Это объясняется минимальными накладными расходами директивы parallel for. +OpenMP показал наилучший результат с ускорением почти в 9.6 раз, что близко к идеальному для +12-ядерного процессора. Это объясняется минимальными накладными расходами директивы parallel for. -TBB и STL локально показали время, близкое к последовательной версии. Это связано с особенностями планировщика Windows и накладными расходами на создание потоков std::thread для относительно быстрой задачи (0.1 сек). В CI-окружении на Linux данные технологии показывают значительно большую эффективность. +TBB и STL локально показали время, близкое к последовательной версии. Это связано с особенностями +планировщика Windows и накладными расходами на создание потоков std::thread для относительно +быстрой задачи (0.1 сек). В CI-окружении на Linux данные технологии показывают значительно +большую эффективность. -ALL (MPI) показал замедление, так как запуск нескольких процессов MPI на одной локальной машине добавляет значительные задержки на межпроцессное взаимодействие (IPC) и синхронизацию через MPI_Barrier. +ALL (MPI) показал замедление, так как запуск нескольких процессов MPI на одной локальной машине +добавляет значительные задержки на межпроцессное взаимодействие (IPC) и синхронизацию. ## 8. Conclusions -В ходе работы были успешно реализованы все запланированные версии алгоритма Симпсона. Наиболее эффективной технологией для данной задачи в среде Windows оказалась OpenMP. Гибридная схема (ALL) продемонстрировала работоспособность всех механизмов синхронизации (MPI + OMP + TBB), однако её применение оправдано только на распределенных кластерах или при значительно больших объемах вычислений, где время расчета существенно превышает время передачи данных по сети. \ No newline at end of file +В ходе работы были успешно реализованы все запланированные версии алгоритма Симпсона. Наиболее +эффективной технологией для данной задачи в среде Windows оказалась OpenMP. Гибридная схема (ALL) +продемонстрировала работоспособность всех механизмов синхронизации (MPI + OMP + TBB), однако её +применение оправдано только на распределенных кластерах или при значительно больших объемах +вычислений. \ No newline at end of file From 988658bda6200345458d2622038e4ae06e1887f6 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 19 Apr 2026 20:10:35 +0300 Subject: [PATCH 3/6] fixed ct --- tasks/ovsyannikov_n_simpson_method/all/include/ops_all.hpp | 3 --- tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/tasks/ovsyannikov_n_simpson_method/all/include/ops_all.hpp b/tasks/ovsyannikov_n_simpson_method/all/include/ops_all.hpp index c5e087911..299730646 100644 --- a/tasks/ovsyannikov_n_simpson_method/all/include/ops_all.hpp +++ b/tasks/ovsyannikov_n_simpson_method/all/include/ops_all.hpp @@ -1,8 +1,5 @@ #pragma once -#include -#include - #include "ovsyannikov_n_simpson_method/common/include/common.hpp" #include "task/include/task.hpp" diff --git a/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp b/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp index 9b42b36d1..718399711 100644 --- a/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp +++ b/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -78,7 +77,7 @@ bool OvsyannikovNSimpsonMethodALL::RunImpl() { MPI_Reduce(&total_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); if (rank == 0) { - int world_size; + int world_size = 0; MPI_Comm_size(MPI_COMM_WORLD, &world_size); res_ = (hx * hy / 9.0) * (global_sum / world_size); } From b4305fc8e8cef4639f3a63a853ba7dcd77a3ae19 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 19 Apr 2026 23:14:46 +0300 Subject: [PATCH 4/6] fixed report --- tasks/ovsyannikov_n_simpson_method/all/report.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tasks/ovsyannikov_n_simpson_method/all/report.md b/tasks/ovsyannikov_n_simpson_method/all/report.md index 5ce22f0cf..72ee4e24d 100644 --- a/tasks/ovsyannikov_n_simpson_method/all/report.md +++ b/tasks/ovsyannikov_n_simpson_method/all/report.md @@ -16,6 +16,7 @@ Задача: Вычислить двойной интеграл ∫(ay,by)∫(ax,bx)(x+y)dxdy на прямоугольной области. Ограничения: + 1) Количество узлов разбиения сетки по каждой оси должно быть четным и положительным, что является обязательным условием применения классического метода Симпсона. 2) Необходимо обеспечить точность вычислений и корректную редукцию (суммирование) @@ -24,6 +25,7 @@ ## 3. Baseline Algorithm (Sequential) Последовательный алгоритм реализует классическую схему: + 1) Область интегрирования разбивается на сетку с шагами hx и hy. 2) Вычисляется взвешенная сумма значений функции во всех узлах сетки. Коэффициенты весов зависят от положения узла: @@ -35,6 +37,7 @@ ## 4. Parallelization Scheme Параллельные версии используют декомпозицию по внешнему циклу (интегрирование по строкам сетки): + 1) OpenMP: Использование директивы #pragma omp parallel for с механизмом reduction(+:total_sum) для автоматического сбора результатов. 2) TBB: Применение алгоритма tbb::parallel_reduce, который эффективно разделяет диапазон строк @@ -64,6 +67,7 @@ Toolchain: MSVC v143, CMake 3.30. Data: Сетка размером 2000×2000 узлов. ## 7. Results and Discussion + ### 7.1 Correctness Корректность всех реализаций подтверждена 30 функциональными тестами. Проверены случаи с нормальной @@ -100,4 +104,4 @@ ALL (MPI) показал замедление, так как запуск нес эффективной технологией для данной задачи в среде Windows оказалась OpenMP. Гибридная схема (ALL) продемонстрировала работоспособность всех механизмов синхронизации (MPI + OMP + TBB), однако её применение оправдано только на распределенных кластерах или при значительно больших объемах -вычислений. \ No newline at end of file +вычислений. From 053e262a5422636a29afdd97b6a3438d379f9327 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 19 Apr 2026 23:36:39 +0300 Subject: [PATCH 5/6] fixed ct --- .../all/src/ops_all.cpp | 67 +++++++++---------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp b/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp index 718399711..29956f0e6 100644 --- a/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp +++ b/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -41,8 +42,10 @@ bool OvsyannikovNSimpsonMethodALL::PreProcessingImpl() { } bool OvsyannikovNSimpsonMethodALL::RunImpl() { - int rank = -1; + int rank = 0; + int size = 1; MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); const int nx_l = params_.nx; const int ny_l = params_.ny; @@ -51,47 +54,43 @@ bool OvsyannikovNSimpsonMethodALL::RunImpl() { const double hx = (params_.bx - params_.ax) / nx_l; const double hy = (params_.by - params_.ay) / ny_l; - double total_sum = 0.0; + int total_rows = nx_l + 1; + int rows_per_rank = total_rows / size; + int remainder = total_rows % size; + + int my_start = rank * rows_per_rank + std::min(rank, remainder); + int my_end = my_start + rows_per_rank + (rank < remainder ? 1 : 0); + + double local_sum = 0.0; + +#pragma omp parallel for default(none) shared(my_start, my_end, nx_l, ny_l, ax_l, ay_l, hx, hy) reduction(+ : local_sum) + for (int i = my_start; i < my_end; ++i) { + const double x = ax_l + (static_cast(i) * hx); + const double coeff_x = GetCoeff(i, nx_l); -#pragma omp parallel default(none) shared(nx_l, ny_l, ax_l, ay_l, hx, hy) reduction(+ : total_sum) - { -#pragma omp for - for (int i = 0; i <= nx_l; ++i) { - const double x = ax_l + (static_cast(i) * hx); - const double coeff_x = GetCoeff(i, nx_l); - - double row_sum = tbb::parallel_reduce(tbb::blocked_range(0, ny_l + 1), 0.0, - [&](const tbb::blocked_range &r, double local_sum) { - for (int j = r.begin(); j < r.end(); ++j) { - const double y = ay_l + (static_cast(j) * hy); - const double coeff_y = GetCoeff(j, ny_l); - local_sum += coeff_y * Function(x, y); - } - return local_sum; - }, std::plus<>()); - total_sum += coeff_x * row_sum; - } + double row_sum = tbb::parallel_reduce(tbb::blocked_range(0, ny_l + 1), 0.0, + [&](const tbb::blocked_range &r, double sum) { + for (int j = r.begin(); j < r.end(); ++j) { + const double y = ay_l + (static_cast(j) * hy); + const double coeff_y = GetCoeff(j, ny_l); + sum += coeff_y * Function(x, y); + } + return sum; + }, std::plus<>()); + + local_sum += coeff_x * row_sum; } - double global_sum = 0.0; - MPI_Reduce(&total_sum, &global_sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + double total_sum = 0.0; + MPI_Reduce(&local_sum, &total_sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); if (rank == 0) { - int world_size = 0; - MPI_Comm_size(MPI_COMM_WORLD, &world_size); - res_ = (hx * hy / 9.0) * (global_sum / world_size); + res_ = (hx * hy / 9.0) * total_sum; } - const int num_threads = ppc::util::GetNumThreads(); std::atomic counter(0); - std::vector threads; - threads.reserve(num_threads); - for (int i = 0; i < num_threads; i++) { - threads.emplace_back([&]() { counter++; }); - } - for (auto &t : threads) { - t.join(); - } + std::thread t([&]() { counter++; }); + t.join(); MPI_Barrier(MPI_COMM_WORLD); return true; From 6fa3fd9a2c99c89e9fd1770edca7653501049908 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 19 Apr 2026 23:51:18 +0300 Subject: [PATCH 6/6] fixed ct2 --- tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp b/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp index 29956f0e6..1b7b747a1 100644 --- a/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp +++ b/tasks/ovsyannikov_n_simpson_method/all/src/ops_all.cpp @@ -19,6 +19,7 @@ namespace ovsyannikov_n_simpson_method { double OvsyannikovNSimpsonMethodALL::Function(double x, double y) { return x + y; } + double OvsyannikovNSimpsonMethodALL::GetCoeff(int i, int n) { if (i == 0 || i == n) { return 1.0; @@ -88,6 +89,8 @@ bool OvsyannikovNSimpsonMethodALL::RunImpl() { res_ = (hx * hy / 9.0) * total_sum; } + MPI_Bcast(&res_, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + std::atomic counter(0); std::thread t([&]() { counter++; }); t.join();