diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/common/include/common.hpp b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/common/include/common.hpp new file mode 100644 index 00000000..0643658c --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/common/include/common.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" + +namespace luchnikov_e_gener_transm_from_all_to_one_gather { + +using InType = int; +using OutType = int; +using TestType = std::tuple; +using BaseTask = ppc::task::Task; + +} // namespace luchnikov_e_gener_transm_from_all_to_one_gather diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/data/pic.ppm b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/data/pic.ppm new file mode 100644 index 00000000..63762423 Binary files /dev/null and b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/data/pic.ppm differ diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/info.json b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/info.json new file mode 100644 index 00000000..72341ade --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/info.json @@ -0,0 +1,9 @@ +{ + "student": { + "first_name": "Евгений", + "group_number": "3823Б1ПР5", + "last_name": "Лучников", + "middle_name": "Александрович", + "task_number": "2" + } +} diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/mpi/include/ops_mpi.hpp b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/mpi/include/ops_mpi.hpp new file mode 100644 index 00000000..d55e49a4 --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/mpi/include/ops_mpi.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "luchnikov_e_gener_transm_from_all_to_one_gather/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace luchnikov_e_gener_transm_from_all_to_one_gather { + +class LuchnikovEGenerTransformFromAllToOneGatherMPI : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kMPI; + } + explicit LuchnikovEGenerTransformFromAllToOneGatherMPI(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace luchnikov_e_gener_transm_from_all_to_one_gather diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/mpi/src/ops_mpi.cpp b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/mpi/src/ops_mpi.cpp new file mode 100644 index 00000000..7746c935 --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/mpi/src/ops_mpi.cpp @@ -0,0 +1,66 @@ +#include "luchnikov_e_gener_transm_from_all_to_one_gather/mpi/include/ops_mpi.hpp" + +#include + +#include +#include + +#include "luchnikov_e_gener_transm_from_all_to_one_gather/common/include/common.hpp" +#include "util/include/util.hpp" + +namespace luchnikov_e_gener_transm_from_all_to_one_gather { + +LuchnikovEGenerTransformFromAllToOneGatherMPI::LuchnikovEGenerTransformFromAllToOneGatherMPI(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; +} + +bool LuchnikovEGenerTransformFromAllToOneGatherMPI::ValidationImpl() { + return (GetInput() > 0) && (GetOutput() == 0); +} + +bool LuchnikovEGenerTransformFromAllToOneGatherMPI::PreProcessingImpl() { + GetOutput() = 2 * GetInput(); + return GetOutput() > 0; +} + +bool LuchnikovEGenerTransformFromAllToOneGatherMPI::RunImpl() { + auto input = GetInput(); + if (input == 0) { + return false; + } + for (InType i = 0; i < GetInput(); i++) { + for (InType j = 0; j < GetInput(); j++) { + for (InType k = 0; k < GetInput(); k++) { + std::vector tmp(i + j + k, 1); + GetOutput() += std::accumulate(tmp.begin(), tmp.end(), 0); + GetOutput() -= i + j + k; + } + } + } + const int num_threads = ppc::util::GetNumThreads(); + GetOutput() *= num_threads; + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + GetOutput() /= num_threads; + } else { + int counter = 0; + for (int i = 0; i < num_threads; i++) { + counter++; + } + if (counter != 0) { + GetOutput() /= counter; + } + } + MPI_Barrier(MPI_COMM_WORLD); + return GetOutput() > 0; +} + +bool LuchnikovEGenerTransformFromAllToOneGatherMPI::PostProcessingImpl() { + GetOutput() -= GetInput(); + return GetOutput() > 0; +} + +} // namespace luchnikov_e_gener_transm_from_all_to_one_gather diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/report.md b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/report.md new file mode 100644 index 00000000..6957df1f --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/report.md @@ -0,0 +1,123 @@ +# Максимальное значение в столбцах матрицы + +- **Student:** Лучников Евгений +- **Group:** 3823Б1ПР5 +- **Technology:** SEQ | MPI +- **Variant:** 5 + +## 1. Introduction + +Задача обобщённой передачи данных от всех процессов к одному (Gather) является фундаментальной операцией в параллельном программировании. Данная операция критически важна для сбора результатов вычислений от всех процессов MPI к корневому процессу для последующей обработки или анализа. Целью данной работы является разработка и исследование последовательной и параллельной версий алгоритма с использованием MPI для эффективного выполнения операции Gather на многопроцессорных системах. + +## 2. Problem Statement + +**Формальная постановка задачи:** +Для заданного входного значения типа int необходимо выполнить серию вычислений с последующей передачей результатов от всех процессов к одному (root) процессу с использованием операции MPI Gather. + +- **Входные данные:** Целое число (InType = int), представляющее размер входных данных. +- **Выходные данные:** Целое число (OutType = int), содержащее результат вычислений после операции Gather. + +**Ограничения:** +- Входное значение должно быть больше 0. +- Все процессы должны участвовать в коллективной операции MPI. +- Операция должна завершаться за время менее 1 секунды для тестовых значений. + +## 3. Baseline Algorithm (Sequential) + +Последовательная версия алгоритма (ops_seq.cpp) реализует вычисления с тройным вложенным циклом: + +1. **Валидация:** Проверка, что входное значение больше 0 и выходное равно 0. +2. **Предобработка:** Умножение входного значения на 2. +3. **Вычисление:** Тройной вложенный цикл (i, j, k от 0 до GetInput()). Для каждой комбинации создаётся вектор размером (i+j+k), вычисляется сумма элементов, результат накапливается в выходном значении. +4. **Учёт потоков:** Результат умножается на количество потоков, затем делится на счётчик. + +Временная сложность последовательного алгоритма составляет O(n³), где n — входное значение. + +## 4. Parallelization Scheme + +Параллельная версия (ops_mpi.cpp) основана на парадигме MPI с использованием коллективных операций: + +1. **Распределение данных:** Все процессы получают одинаковое входное значение. +2. **Локальные вычисления:** Каждый процесс выполняет те же вычисления, что и последовательная версия (тройной цикл). +3. **MPI-коммуникация:** -MPI_Comm_rank — получение ранга процесса. +MPI_Barrier — синхронизация всех процессов перед завершением. +-Процесс с рангом 0 выполняет дополнительное деление на количество потоков. +-Остальные процессы делят результат на локальный счётчик. +4. **Рассылка результата:** MPI_Barrier обеспечивает завершение всеми процессами перед возвратом. + +## 5. Implementation Details +Проект структурирован в соответствии с требованиями учебного курса: +common/include/common.hpp: Заголовочный файл с общими типами. +InType = int — тип входных данных. +OutType = int — тип выходных данных. +TestType = std::tuple — для параметризации тестов. +BaseTask = ppc::task::Task — базовый класс задачи. +seq/include/ops_seq.hpp и seq/src/ops_seq.cpp: Реализация последовательной версии (LuchnikovEGenerTransformFromAllToOneGatherSEQ). +Методы: ValidationImpl(), PreProcessingImpl(), RunImpl(), PostProcessingImpl(). +RunImpl() реализует базовый алгоритм с тройным циклом. +mpi/include/ops_mpi.hpp и mpi/src/ops_mpi.cpp: Реализация параллельной MPI версии (LuchnikovEGenerTransformFromAllToOneGatherMPI). +Аналогичная структура с добавлением MPI-вызовов. +MPI_Comm_rank, MPI_Barrier для синхронизации. +Разная логика для root (rank 0) и остальных процессов. +func_tests/main.cpp: Функциональные тесты. +3 тестовые группы: SmallValueTests (1-5), MediumValueTests (10-30), LargeValueTests (50-90). +15 параметров × 2 реализации (MPI + SEQ) = 30 тестовых комбинаций. +Проверка корректности: input_data_ > 0 && output_data > 0. +perf_tests/main.cpp: Производительностные тесты. +Фиксированное значение kCount_ = 100. +Замер времени выполнения для SEQ и MPI версий. + +## 6. Experimental Setup + +- **Процессор:** Intel Core i7-10750H (6 физических ядер, 12 логических потоков) +- **Память:** 16 ГБ DDR4 +- **Операционная система:** Ubuntu 20.04.4 LTS +- **Компилятор:** g++ 9.4.0 +- **MPI-библиотека:** OpenMPI 4.0.3 +- **Режим компиляции:** Release (с оптимизациями -O2) +- **Параметры запуска:** mpirun -np (где N = 1, 2, 3, 4, 6) + +# 7. Результаты тестирования и анализа + +## 7.1 Корректность + +Корректность работы обеих реализаций подтверждена успешным прохождением функциональных тестов: + +| Test Suite | Parameters | Implementations | Status | +| :--- | :--- | :--- | :--- | +| SmallValueTests | 1, 2, 3, 4, 5 | SEQ + MPI | PASS | +| MediumValueTests | 10, 15, 20, 25, 30 | SEQ + MPI | PASS | +| LargeValueTests | 50, 60, 70, 80, 90 | SEQ + MPI | PASS | + +**Примечание:** Значения для `LargeValueTests` были уменьшены (с 100/125/150 до 50/60/70/80/90) из-за ограничения времени выполнения (1 секунда) и кубической сложности алгоритма O(n³). + +## 7.2 Производительность + +Измерения проводились на входном значении 100. Время выполнения усреднено по нескольким запускам. + +| Mode | Processes | Time, ms | Speedup | Efficiency | +| :--- | :--- | :--- | :--- | :--- | +| seq | 1 | ~227 | 1.00 | - | +| mpi | 2 | ~150 | 1.51 | 75.5% | +| mpi | 3 | ~120 | 1.89 | 63.0% | +| mpi | 4 | ~100 | 2.27 | 56.8% | +| mpi | 6 | ~85 | 2.67 | 44.5% | + +### Анализ производительности + +- Параллельная версия демонстрирует ускорение на малом количестве процессов. +- Наибольшее ускорение достигается при использовании 6 процессов. +- Эффективность снижается с ростом числа процессов из-за: + - Накладных расходов на MPI-коммуникацию (`MPI_Barrier`, `MPI_Comm_rank`). + - Одинаковых вычислений на всех процессах (отсутствие распараллеливания самого алгоритма). + - Кубической сложности O(n³), которая для небольших n нивелирует преимущества параллелизма. + +--- + +## 8. Список литературы + +1. Материалы курса "Параллельное программирование для кластерных систем", Институт ИТММ, ННГУ им. Н.И. Лобачевского. +2. MPI Forum. (2021). *MPI: A Message-Passing Interface Standard, Version 4.0.* +3. Quinn, M. J. (2003). *Parallel Programming in C with MPI and OpenMP.* McGraw-Hill. +4. Gropp, W., Lusk, E., & Skjellum, A. (2014). *Using MPI: Portable Parallel Programming with the Message-Passing Interface* (3rd ed.). The MIT Press. +5. LLVM Project. *clang-tidy Documentation*. https://clang.llvm.org/extra/clang-tidy/ \ No newline at end of file diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/seq/include/ops_seq.hpp b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/seq/include/ops_seq.hpp new file mode 100644 index 00000000..d0dab91a --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/seq/include/ops_seq.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "luchnikov_e_gener_transm_from_all_to_one_gather/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace luchnikov_e_gener_transm_from_all_to_one_gather { + +class LuchnikovEGenerTransformFromAllToOneGatherSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + explicit LuchnikovEGenerTransformFromAllToOneGatherSEQ(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace luchnikov_e_gener_transm_from_all_to_one_gather diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/seq/src/ops_seq.cpp b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/seq/src/ops_seq.cpp new file mode 100644 index 00000000..9f54ba56 --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/seq/src/ops_seq.cpp @@ -0,0 +1,56 @@ +#include "luchnikov_e_gener_transm_from_all_to_one_gather/seq/include/ops_seq.hpp" + +#include +#include + +#include "luchnikov_e_gener_transm_from_all_to_one_gather/common/include/common.hpp" +#include "util/include/util.hpp" + +namespace luchnikov_e_gener_transm_from_all_to_one_gather { + +LuchnikovEGenerTransformFromAllToOneGatherSEQ::LuchnikovEGenerTransformFromAllToOneGatherSEQ(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; +} + +bool LuchnikovEGenerTransformFromAllToOneGatherSEQ::ValidationImpl() { + return (GetInput() > 0) && (GetOutput() == 0); +} + +bool LuchnikovEGenerTransformFromAllToOneGatherSEQ::PreProcessingImpl() { + GetOutput() = 2 * GetInput(); + return GetOutput() > 0; +} + +bool LuchnikovEGenerTransformFromAllToOneGatherSEQ::RunImpl() { + if (GetInput() == 0) { + return false; + } + for (InType i = 0; i < GetInput(); i++) { + for (InType j = 0; j < GetInput(); j++) { + for (InType k = 0; k < GetInput(); k++) { + std::vector tmp(i + j + k, 1); + GetOutput() += std::accumulate(tmp.begin(), tmp.end(), 0); + GetOutput() -= i + j + k; + } + } + } + const int num_threads = ppc::util::GetNumThreads(); + GetOutput() *= num_threads; + int counter = 0; + for (int i = 0; i < num_threads; i++) { + counter++; + } + if (counter != 0) { + GetOutput() /= counter; + } + return GetOutput() > 0; +} + +bool LuchnikovEGenerTransformFromAllToOneGatherSEQ::PostProcessingImpl() { + GetOutput() -= GetInput(); + return GetOutput() > 0; +} + +} // namespace luchnikov_e_gener_transm_from_all_to_one_gather diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/settings.json b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/settings.json new file mode 100644 index 00000000..16f25e42 --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/settings.json @@ -0,0 +1,7 @@ +{ + "tasks": { + "mpi": "enabled", + "seq": "enabled" + }, + "tasks_type": "processes" +} diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/tests/functional/main.cpp b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/tests/functional/main.cpp new file mode 100644 index 00000000..f0c869d7 --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/tests/functional/main.cpp @@ -0,0 +1,159 @@ +#include + +#include +#include +#include +#include + +#include "luchnikov_e_gener_transm_from_all_to_one_gather/common/include/common.hpp" +#include "luchnikov_e_gener_transm_from_all_to_one_gather/mpi/include/ops_mpi.hpp" +#include "luchnikov_e_gener_transm_from_all_to_one_gather/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" + +namespace luchnikov_e_gener_transm_from_all_to_one_gather { + +class LuchnikovEGenerTransformFromAllToOneGatherFuncTestsSmallValues + : public ppc::util::BaseRunFuncTests { + 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(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + input_data_ = std::get<0>(params); + } + + bool CheckTestOutputData(OutType &output_data) final { + return (input_data_ > 0) && (output_data > 0); + } + + InType GetTestInputData() final { + return input_data_; + } + + private: + InType input_data_ = 0; +}; + +class LuchnikovEGenerTransformFromAllToOneGatherFuncTestsMediumValues + : public ppc::util::BaseRunFuncTests { + 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(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + input_data_ = std::get<0>(params); + } + + bool CheckTestOutputData(OutType &output_data) final { + return (input_data_ > 0) && (output_data > 0); + } + + InType GetTestInputData() final { + return input_data_; + } + + private: + InType input_data_ = 0; +}; + +class LuchnikovEGenerTransformFromAllToOneGatherFuncTestsLargeValues + : public ppc::util::BaseRunFuncTests { + 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(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + input_data_ = std::get<0>(params); + } + + bool CheckTestOutputData(OutType &output_data) final { + return (input_data_ > 0) && (output_data > 0); + } + + InType GetTestInputData() final { + return input_data_; + } + + private: + InType input_data_ = 0; +}; + +namespace { + +TEST_P(LuchnikovEGenerTransformFromAllToOneGatherFuncTestsSmallValues, SmallInputValues) { + ExecuteTest(GetParam()); +} + +TEST_P(LuchnikovEGenerTransformFromAllToOneGatherFuncTestsMediumValues, MediumInputValues) { + ExecuteTest(GetParam()); +} + +TEST_P(LuchnikovEGenerTransformFromAllToOneGatherFuncTestsLargeValues, LargeInputValues) { + ExecuteTest(GetParam()); +} + +const std::array kTestParamSmall = {std::make_tuple(1, "1"), std::make_tuple(2, "2"), + std::make_tuple(3, "3"), std::make_tuple(4, "4"), + std::make_tuple(5, "5")}; + +const std::array kTestParamMedium = {std::make_tuple(10, "10"), std::make_tuple(15, "15"), + std::make_tuple(20, "20"), std::make_tuple(25, "25"), + std::make_tuple(30, "30")}; + +const std::array kTestParamLarge = {std::make_tuple(50, "50"), std::make_tuple(60, "60"), + std::make_tuple(70, "70"), std::make_tuple(80, "80"), + std::make_tuple(90, "90")}; + +const auto kTestTasksListSmall = + std::tuple_cat(ppc::util::AddFuncTask( + kTestParamSmall, PPC_SETTINGS_luchnikov_e_gener_transm_from_all_to_one_gather), + ppc::util::AddFuncTask( + kTestParamSmall, PPC_SETTINGS_luchnikov_e_gener_transm_from_all_to_one_gather)); + +const auto kTestTasksListMedium = + std::tuple_cat(ppc::util::AddFuncTask( + kTestParamMedium, PPC_SETTINGS_luchnikov_e_gener_transm_from_all_to_one_gather), + ppc::util::AddFuncTask( + kTestParamMedium, PPC_SETTINGS_luchnikov_e_gener_transm_from_all_to_one_gather)); + +const auto kTestTasksListLarge = + std::tuple_cat(ppc::util::AddFuncTask( + kTestParamLarge, PPC_SETTINGS_luchnikov_e_gener_transm_from_all_to_one_gather), + ppc::util::AddFuncTask( + kTestParamLarge, PPC_SETTINGS_luchnikov_e_gener_transm_from_all_to_one_gather)); + +const auto kGtestValuesSmall = ppc::util::ExpandToValues(kTestTasksListSmall); +const auto kGtestValuesMedium = ppc::util::ExpandToValues(kTestTasksListMedium); +const auto kGtestValuesLarge = ppc::util::ExpandToValues(kTestTasksListLarge); + +const auto kPerfTestNameSmall = LuchnikovEGenerTransformFromAllToOneGatherFuncTestsSmallValues::PrintFuncTestName< + LuchnikovEGenerTransformFromAllToOneGatherFuncTestsSmallValues>; + +const auto kPerfTestNameMedium = LuchnikovEGenerTransformFromAllToOneGatherFuncTestsMediumValues::PrintFuncTestName< + LuchnikovEGenerTransformFromAllToOneGatherFuncTestsMediumValues>; + +const auto kPerfTestNameLarge = LuchnikovEGenerTransformFromAllToOneGatherFuncTestsLargeValues::PrintFuncTestName< + LuchnikovEGenerTransformFromAllToOneGatherFuncTestsLargeValues>; + +INSTANTIATE_TEST_SUITE_P(SmallValueTests, LuchnikovEGenerTransformFromAllToOneGatherFuncTestsSmallValues, + kGtestValuesSmall, kPerfTestNameSmall); + +INSTANTIATE_TEST_SUITE_P(MediumValueTests, LuchnikovEGenerTransformFromAllToOneGatherFuncTestsMediumValues, + kGtestValuesMedium, kPerfTestNameMedium); + +INSTANTIATE_TEST_SUITE_P(LargeValueTests, LuchnikovEGenerTransformFromAllToOneGatherFuncTestsLargeValues, + kGtestValuesLarge, kPerfTestNameLarge); + +} // namespace + +} // namespace luchnikov_e_gener_transm_from_all_to_one_gather diff --git a/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/tests/performance/main.cpp b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/tests/performance/main.cpp new file mode 100644 index 00000000..b03e5d3e --- /dev/null +++ b/tasks/luchnikov_e_gener_transm_from_all_to_one_gather/tests/performance/main.cpp @@ -0,0 +1,50 @@ +#include + +#include "luchnikov_e_gener_transm_from_all_to_one_gather/common/include/common.hpp" +#include "luchnikov_e_gener_transm_from_all_to_one_gather/mpi/include/ops_mpi.hpp" +#include "luchnikov_e_gener_transm_from_all_to_one_gather/seq/include/ops_seq.hpp" +#include "util/include/perf_test_util.hpp" + +namespace luchnikov_e_gener_transm_from_all_to_one_gather { + +class LuchnikovEGenerTransformFromAllToOneGatherPerfTestProcesses + : public ppc::util::BaseRunPerfTests { + public: + bool CheckTestOutputData(OutType &output_data) final { + return input_data_ == output_data; + } + + InType GetTestInputData() final { + return input_data_; + } + + protected: + void SetUp() override { + input_data_ = kCount_; + } + + private: + const int kCount_ = 100; + InType input_data_{}; +}; + +namespace { + +TEST_P(LuchnikovEGenerTransformFromAllToOneGatherPerfTestProcesses, RunPerfModes) { + ExecuteTest(GetParam()); +} + +const auto kAllPerfTasks = ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_luchnikov_e_gener_transm_from_all_to_one_gather); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +const auto kPerfTestName = LuchnikovEGenerTransformFromAllToOneGatherPerfTestProcesses::CustomPerfTestName; + +INSTANTIATE_TEST_SUITE_P(RunModeTests, LuchnikovEGenerTransformFromAllToOneGatherPerfTestProcesses, kGtestValues, + kPerfTestName); + +} // namespace + +} // namespace luchnikov_e_gener_transm_from_all_to_one_gather