diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b70f3d31c9..e8751bf609 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: # Ruff Python linter - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.14.0 + rev: v0.14.4 hooks: - id: ruff args: [--fix] diff --git a/tasks/papulina_y_count_of_letters/common/include/common.hpp b/tasks/papulina_y_count_of_letters/common/include/common.hpp new file mode 100644 index 0000000000..87cdb26d97 --- /dev/null +++ b/tasks/papulina_y_count_of_letters/common/include/common.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#include "task/include/task.hpp" + +namespace papulina_y_count_of_letters { + +using InType = std::string; +using OutType = int; +using TestType = std::tuple, std::string>; // патерн + длина строки +using BaseTask = ppc::task::Task; + +} // namespace papulina_y_count_of_letters diff --git a/tasks/papulina_y_count_of_letters/info.json b/tasks/papulina_y_count_of_letters/info.json new file mode 100644 index 0000000000..b343e6c39b --- /dev/null +++ b/tasks/papulina_y_count_of_letters/info.json @@ -0,0 +1,9 @@ +{ + "student": { + "first_name": "Юлия", + "last_name": "Папулина", + "middle_name": "Андреевна", + "group_number": "3823Б1ФИ3", + "task_number": "1" + } +} diff --git a/tasks/papulina_y_count_of_letters/mpi/include/ops_mpi.hpp b/tasks/papulina_y_count_of_letters/mpi/include/ops_mpi.hpp new file mode 100644 index 0000000000..71a1d03ad6 --- /dev/null +++ b/tasks/papulina_y_count_of_letters/mpi/include/ops_mpi.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include "papulina_y_count_of_letters/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace papulina_y_count_of_letters { + +class PapulinaYCountOfLettersMPI : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kMPI; + } + explicit PapulinaYCountOfLettersMPI(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + static int CountOfLetters(const char *s, const int &n); + + int procNum_ = 0; +}; + +} // namespace papulina_y_count_of_letters diff --git a/tasks/papulina_y_count_of_letters/mpi/src/ops_mpi.cpp b/tasks/papulina_y_count_of_letters/mpi/src/ops_mpi.cpp new file mode 100644 index 0000000000..d7ff546e57 --- /dev/null +++ b/tasks/papulina_y_count_of_letters/mpi/src/ops_mpi.cpp @@ -0,0 +1,95 @@ +#include "papulina_y_count_of_letters/mpi/include/ops_mpi.hpp" + +#include + +#include +#include +#include + +#include "papulina_y_count_of_letters/common/include/common.hpp" + +namespace papulina_y_count_of_letters { + +PapulinaYCountOfLettersMPI::PapulinaYCountOfLettersMPI(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; + MPI_Comm_size(MPI_COMM_WORLD, &procNum_); +} +int PapulinaYCountOfLettersMPI::CountOfLetters(const char *s, const int &n) { + int k = 0; + if (n <= 0) { + return 0; + } + for (int i = 0; i < n; i++) { + char c = s[i]; + if (isalpha(c) != 0) { + k++; + } + } + return k; +} +bool PapulinaYCountOfLettersMPI::ValidationImpl() { + return procNum_ > 0; +} + +bool PapulinaYCountOfLettersMPI::PreProcessingImpl() { + return true; +} + +bool PapulinaYCountOfLettersMPI::RunImpl() { + int proc_rank = 0; + int result = 0; + std::string part_of_string; // части строки, которая будет обрабатываться потоком + unsigned int len = 0; // предполагаемая длина обрабатываемой части + unsigned int remainder = 0; // остаток, если длина строки не кратна числу потоков + unsigned int true_len = 0; // реальная длина обрабатываемой части + MPI_Comm_rank(MPI_COMM_WORLD, &proc_rank); + + if (proc_rank == 0) { + std::string s = GetInput(); + + len = s.size() / procNum_; + remainder = s.size() % procNum_; + MPI_Bcast(&len, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD); + MPI_Bcast(&remainder, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD); + + unsigned int begin_0 = (0 * len) + std::min(static_cast(0), remainder); + unsigned int end_0 = ((0 + 1) * len) + std::min(static_cast(0 + 1), remainder); + true_len = end_0 - begin_0; + part_of_string = (true_len > 0) ? s.substr(begin_0, true_len) : ""; + + for (int i = 1; i < procNum_; i++) { + unsigned int begin = (i * len) + std::min(static_cast(i), remainder); + unsigned int end = ((i + 1) * len) + std::min(static_cast(i + 1), remainder); + unsigned int pre_true_len = end - begin; // предварительная длина обрабатываемой части + + MPI_Send(&pre_true_len, 1, MPI_UNSIGNED, i, 0, MPI_COMM_WORLD); + if (end - begin != 0) { + MPI_Send(s.substr(begin, pre_true_len).data(), static_cast(pre_true_len), MPI_CHAR, i, 1, MPI_COMM_WORLD); + } else { + MPI_Send("", 0, MPI_CHAR, i, 1, MPI_COMM_WORLD); + } + } + } else { + MPI_Bcast(&len, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD); + MPI_Bcast(&remainder, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD); + MPI_Recv(&true_len, 1, MPI_UNSIGNED, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + if (true_len > 0) { + part_of_string.resize(true_len); + } + MPI_Recv(part_of_string.data(), static_cast(true_len), MPI_CHAR, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + } + int local_result = CountOfLetters(part_of_string.data(), static_cast(part_of_string.size())); + MPI_Reduce(&local_result, &result, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); + MPI_Bcast(&result, 1, MPI_INT, 0, MPI_COMM_WORLD); + GetOutput() = result; + MPI_Barrier(MPI_COMM_WORLD); + return true; +} + +bool PapulinaYCountOfLettersMPI::PostProcessingImpl() { + return GetOutput() >= 0; +} + +} // namespace papulina_y_count_of_letters diff --git a/tasks/papulina_y_count_of_letters/report.md b/tasks/papulina_y_count_of_letters/report.md new file mode 100644 index 0000000000..677be1d2b5 --- /dev/null +++ b/tasks/papulina_y_count_of_letters/report.md @@ -0,0 +1,188 @@ +# Подсчет числа буквенных символов в строке + +- Student: Папулина Юлия Андреевна, group 3823Б1ФИ3 +- Technology: SEQ | MPI +- Variant: 22 + +## 1. Введение +Задача подсчета буквенных символов в строке является одной из базовых операций в обработке текстовых данных и представляет собой идеальный пример для освоения принципов параллельного программирования. Сейчас, когда объемы обрабатываемой текстовой информации постоянно растут, эффективная реализация таких операций становится особенно важной. В рамках данной работы реализован MPI-алгоритм, демонстрирующий ключевые аспекты параллельного программирования: декомпозицию задачи, балансировку нагрузки и коллективные операции. + +## 2. Постановка задачи +**Формальная постановка:** для заданной строки S длиной N подсчитать количество символов, являющихся буквами латинского алфавита. + +**Входные данные:** строка S произвольной длины + +**Выходные данные:** целое число - количество буквенных символов + +**Ограничения:** +- Решение должно быть масштабируемым для различного числа процессов + +## 3. Последовательная версия(Baseline) +Алгоритм последовательно проверяет каждый символ строки, определяя принадлежность к латинскому алфавиту с помощью функции int isalpha( int ch ) +```cpp +int result = 0; + if (n <= 0) { + return 0; + } + for (int i = 0; i < n; i++) { + unsigned char c = s[i]; + if (isalpha(c) != 0) { + result++; + } + } + return result; +``` + +## 4. Параллельная версия + +### 4.1. Разделение данных + Используется блочное распределение данных с равномерным распределением остатка: + - базовый размер блока: len = length / num_processes + - остаток: remainder = length % num_processes + - процесс i получает: len + (i < remainder ? 1 : 0) символов (таким образом, все ramainder процессов получат + дополнительный символ к обработке) + +### 4.2. Взаимодействие процессов +#### Процесс 0 (Координатор) + - читает входную строку + - рассылает базовый размер блока(len) и остаток(reminder) остальным потокам(MPI_Bcast) + - инициализирует свою часть обработки строки + - отправка данных(часть строки) для обработки другим процессам через for (MPI_Send) + - cобирает результаты (MPI_Reduce) + +#### Процессы 1..N-1 (Рабочие процессы) +- получают параметры: размер блока, остаток(MPI_Bcast) +- получают свою часть строки для обработки(MPI_Recv) +- выполняют подсчет на своей части +- отправляют результат (MPI_Reduce) + +### 4.3. Псевдокод алгоритма +```pseudocode +FUNCTION: + │ + ├─ INITIALIZATION + │ • Get process rank + │ • Initialize variables + │ + ├─ DATA DISTRIBUTION PHASE + │ │ + │ ├─ IF rank = 0 (MASTER): + │ │ • Read input string + │ │ • Calculate base_len = length / procNum + │ │ • Calculate remainder = length % procNum + │ │ • Broadcast base_len, remainder + │ │ • Counting the processed part for master + │ │ • For each worker i: + │ │ - Calculate chunk boundaries + │ │ - Send chunk_size + │ │ - Send chunk_data + │ │ + │ └─ ELSE (WORKER): + │ • Receive broadcast base_len, remainder + │ • Receive chunk_size + │ • Receive chunk_data + │ + ├─ COMPUTATION PHASE + │ • Each process: Count letters in local_data + │ + ├─ RESULT COLLECTION PHASE + │ • MPI_Reduce: SUM all local_count → process 0 + │ • Broadcast result + │ • Set result + │ + └─ RETURN success +``` +## 5. Детали реализации + +### 5.1. Файловая структура проекта +papulina_y_count_of_letters/ +├── common/include/common.hpp +├── seq/include/ops_seq.hpp +├── seq/src/ops_seq.cpp +├── mpi/include/ops_mpi.hpp +├── mpi/src/ops_mpi.cpp +├── tests/functional/main.cpp +├── tests/performance/main.cpp +└── data/ + +### 5.2. Ключевые классы и функции + +- `InType = std::string` - тип входных данных (строка) +- `OutType = int` - тип выходных данных (количество букв) +- `CountOfLetters(const char* s, const int& n)` - функция подсчета символов +- `RunImpl()` - основная логика последовательного выполнения +- `ValidationImpl()` - проверка валидности входных данных +- `PreProcessingImpl()` - подготовительные операции +- `PostProcessingImpl()` - завершающие операции +- `class PapulinaYRunFuncTestsProcesses` - параметрические функциональные тесты +- `class PapulinaYRunPerfTestsProcesses` - параметрические тесты производительности + +### 5.3. Использование памяти + +**SEQ версия:** +- хранит всю входную строку в памяти +- O(N) память, где N - длина строки +- минимальные накладные расходы(отсутствуют затраты на синхронизацию между потоками/процессами) + +**MPI версия:** +- процесс 0: хранит всю строку + буферы для коммуникации +- рабочие процессы: хранят только свою часть строки +- дополнительная память для MPI буферов сообщений +- эффективное распределение памяти при больших N + +## 6. Экспериментальное окружение + +**Hardware/OS:** +- **CPU:** Intel Core i5-11400H (6 cores, 12 threads, 2.70 GHz base frequency) +- **RAM:** 16.0 GB DDR4 +- **Storage:** SSD 512 GB +- **OS:** Windows 10 + +**Toolchain:** +- **Compiler:** Microsoft Visual C++ 2019 (MSVC 19.29.30153) +- **MPI Implementation:** Microsoft MPI Version10.1.12498.52 +- **Build System:** CMake 3.30.3 +- **Build Type:** Release + +**Environment:** +- **PPC_NUM_PROC:** 1, 2, 4, 6 + +**Data:** строка из 40 000 000 латинских символов + +## 7. Результаты + +### 7.1 Корректность +Корректность реализации была проверена через комплексную систему тестирования, включающую: +- 20 функциональных тестов(пустая строка, строка из одного символа, строка с генерированными символами) +- тест на производительность на стабильных данных + +**Структура параметров теста:** +- строка (generate - если тест на генерацию) +- ожидаемый результат +- название теста(его номер) + +### 7.2 Производительность +Время выполнения для строки длиной 40 000 000 символов: + +| Mode | Count | Time, s | Speedup | Efficiency | +|-------------|-------|---------|---------|------------| +| seq | 1 | 0.0951 | 1.00 | N/A | +| mpi | 2 | 0.0937 | 1.01 | 50.5% | +| mpi | 3 | 0.0718 | 1.32 | 44.0% | +| mpi | 4 | 0.0737 | 1.29 | 32.3% | +| mpi | 6 | 0.0778 | 1.22 | 20.3% | + +**Анализ результатов:** +- минимальное ускорение: наблюдается незначительное ускорение (1.01-1.32x) даже при использовании нескольких процессов +- низкая эффективность: эффективность варьируется от 20.3% до 50.5%, что указывает на значительные накладные расходы +- оптимальная конфигурация: максимальное ускорение достигается при 3 процессах (1.32x) + +**Анализ узких мест:** +- коммуникационные затраты: время передачи данных между процессами превышает время вычислений для данного объема данных +- неидеальное распределение: алгоритм распределения данных создает дополнительную нагрузку + +## 8. Заключение +В результате работы в учебных целях разработаны последовательная (SEQ) и параллельная (MPI) версии программы, подсчитывающей число латинских символов в строке. Несмотря на ограниченную практическую эффективность для конкретной задачи подсчета символов, реализация успешно демонстрирует принципы распределенных вычислений и может служить основой для более сложных алгоритмов обработки текста. + +## 9. Источники +1. Microsoft MPI : документация [Электронный ресурс] // Microsoft Learn. – URL: https://learn.microsoft.com/ru-ru/message-passing-interface/microsoft-mpi (дата обращения: 03.11.2025). +2. Сысоев А. В. Курс лекций по параллельному программированию diff --git a/tasks/papulina_y_count_of_letters/seq/include/ops_seq.hpp b/tasks/papulina_y_count_of_letters/seq/include/ops_seq.hpp new file mode 100644 index 0000000000..84e8eb8a8e --- /dev/null +++ b/tasks/papulina_y_count_of_letters/seq/include/ops_seq.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "papulina_y_count_of_letters/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace papulina_y_count_of_letters { + +class PapulinaYCountOfLettersSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + explicit PapulinaYCountOfLettersSEQ(const InType &in); + + private: + static int CountOfLetters(const char *s, const int &n); + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} // namespace papulina_y_count_of_letters diff --git a/tasks/papulina_y_count_of_letters/seq/src/ops_seq.cpp b/tasks/papulina_y_count_of_letters/seq/src/ops_seq.cpp new file mode 100644 index 0000000000..9897c68b35 --- /dev/null +++ b/tasks/papulina_y_count_of_letters/seq/src/ops_seq.cpp @@ -0,0 +1,45 @@ +#include "papulina_y_count_of_letters/seq/include/ops_seq.hpp" + +#include + +#include "papulina_y_count_of_letters/common/include/common.hpp" + +namespace papulina_y_count_of_letters { + +PapulinaYCountOfLettersSEQ::PapulinaYCountOfLettersSEQ(const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = 0; +} +int PapulinaYCountOfLettersSEQ::CountOfLetters(const char *s, const int &n) { + int k = 0; + if (n <= 0) { + return 0; + } + for (int i = 0; i < n; i++) { + unsigned char c = s[i]; + if (isalpha(c) != 0) { + k++; + } + } + return k; +} +bool PapulinaYCountOfLettersSEQ::ValidationImpl() { + return true; +} + +bool PapulinaYCountOfLettersSEQ::PreProcessingImpl() { + GetOutput() = 0; + return GetOutput() == 0; +} + +bool PapulinaYCountOfLettersSEQ::RunImpl() { + GetOutput() = CountOfLetters(GetInput().data(), static_cast(GetInput().size())); + return true; +} + +bool PapulinaYCountOfLettersSEQ::PostProcessingImpl() { + return true; +} + +} // namespace papulina_y_count_of_letters diff --git a/tasks/papulina_y_count_of_letters/settings.json b/tasks/papulina_y_count_of_letters/settings.json new file mode 100644 index 0000000000..b1a0d52574 --- /dev/null +++ b/tasks/papulina_y_count_of_letters/settings.json @@ -0,0 +1,7 @@ +{ + "tasks_type": "processes", + "tasks": { + "mpi": "enabled", + "seq": "enabled" + } +} diff --git a/tasks/papulina_y_count_of_letters/tests/.clang-tidy b/tasks/papulina_y_count_of_letters/tests/.clang-tidy new file mode 100644 index 0000000000..ef43b7aa8a --- /dev/null +++ b/tasks/papulina_y_count_of_letters/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/papulina_y_count_of_letters/tests/functional/main.cpp b/tasks/papulina_y_count_of_letters/tests/functional/main.cpp new file mode 100644 index 0000000000..38b4b68cfb --- /dev/null +++ b/tasks/papulina_y_count_of_letters/tests/functional/main.cpp @@ -0,0 +1,120 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "papulina_y_count_of_letters/common/include/common.hpp" +#include "papulina_y_count_of_letters/mpi/include/ops_mpi.hpp" +#include "papulina_y_count_of_letters/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" + +namespace papulina_y_count_of_letters { + +class PapulinaYRunFuncTestsProcesses : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + return std::get<1>(test_param); + } + + protected: + void SetUp() override { + TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + std::string s = std::string(std::get<0>(std::get<0>(params))); + if (s != "generate") { + input_data_ = std::string(std::get<0>(std::get<0>(params))); + expectedResult_ = std::get<1>(std::get<0>(params)); + } else { + std::string data = GenerateData(100); // будет генерироваться строка, в которой буквенных символов ровно 100 + input_data_ = data; + expectedResult_ = 100; + } + } + + bool CheckTestOutputData(OutType &output_data) final { + return (expectedResult_ == output_data); + } + + InType GetTestInputData() final { + return input_data_; + } + + private: + InType input_data_; + OutType expectedResult_ = 0; + static std::string GenerateData(size_t count) { + std::mt19937 gen(count); // константный, чтобы у всех потоков была одна и та же строка при генерации + std::uniform_int_distribution length_dist(100, 500); + std::uniform_int_distribution char_dist(32, 126); + + size_t length = length_dist(gen); + std::string generated_string; + generated_string.reserve(length); + + std::string all_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + std::uniform_int_distribution letter_dist(0, all_letters.size() - 1); + // добавляем все буквы + for (size_t i = 0; i < count; i++) { + char c = all_letters[letter_dist(gen)]; + generated_string += c; + } + std::uniform_int_distribution<> non_letter_dist(48, 57); // цифры 0-9 + for (size_t i = count; i < length; ++i) { + char c = static_cast(non_letter_dist(gen)); + generated_string += c; + } + std::shuffle(generated_string.begin(), generated_string.end(), gen); + return generated_string; + } +}; + +namespace { + +TEST_P(PapulinaYRunFuncTestsProcesses, CountOfLetters) { + ExecuteTest(GetParam()); +} + +const std::array kTestParam = { + std::make_tuple(std::make_tuple("", 0), "test1"), + std::make_tuple(std::make_tuple("abcd", 4), "test2"), + std::make_tuple(std::make_tuple("aabcd123abcd123abcd", 13), "test3"), + std::make_tuple(std::make_tuple("abcd_____________123abcd", 8), "test4"), + std::make_tuple(std::make_tuple("a", 1), "test5"), + std::make_tuple(std::make_tuple("1243356", 0), "test6"), + std::make_tuple(std::make_tuple("a1a1a1a1a1a1a1a1a1a1a1a1", 12), "test7"), + std::make_tuple(std::make_tuple("!@345678&*()", 0), "test8"), + std::make_tuple(std::make_tuple("aaaaaaaaaaaaaaaaaaaa", 20), "test9"), + std::make_tuple(std::make_tuple("tatatatatatatatatatatatatatatatatatatatata", 42), "test10"), + std::make_tuple(std::make_tuple("er11er11er11er11", 8), "test11"), + std::make_tuple(std::make_tuple("eee___eee__", 6), "test12"), + std::make_tuple(std::make_tuple("eee___eee__EEE", 9), "test13"), + std::make_tuple(std::make_tuple("EEEE___EEEE", 8), "test14"), + std::make_tuple( + std::make_tuple( + "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE", + 100), + "test15"), + std::make_tuple(std::make_tuple("фбсдуащуо", 0), "test16"), + std::make_tuple(std::make_tuple("aa", 2), "test17"), + std::make_tuple(std::make_tuple("aaa", 3), "test18"), + std::make_tuple(std::make_tuple("aabb0123456789", 4), "test19"), + std::make_tuple(std::make_tuple("generate", 4), "test20")}; + +const auto kTestTasksList = std::tuple_cat( + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_papulina_y_count_of_letters), + ppc::util::AddFuncTask(kTestParam, PPC_SETTINGS_papulina_y_count_of_letters)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); + +const auto kPerfTestName = PapulinaYRunFuncTestsProcesses::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(PicMatrixTests, PapulinaYRunFuncTestsProcesses, kGtestValues, kPerfTestName); + +} // namespace + +} // namespace papulina_y_count_of_letters diff --git a/tasks/papulina_y_count_of_letters/tests/performance/main.cpp b/tasks/papulina_y_count_of_letters/tests/performance/main.cpp new file mode 100644 index 0000000000..b0dd93a9ca --- /dev/null +++ b/tasks/papulina_y_count_of_letters/tests/performance/main.cpp @@ -0,0 +1,47 @@ +#include + +#include + +#include "papulina_y_count_of_letters/common/include/common.hpp" +#include "papulina_y_count_of_letters/mpi/include/ops_mpi.hpp" +#include "papulina_y_count_of_letters/seq/include/ops_seq.hpp" +#include "util/include/perf_test_util.hpp" + +namespace papulina_y_count_of_letters { + +class PapulinaYRunPerfTestProcesses : public ppc::util::BaseRunPerfTests { + const int kCount_ = 10000000; + const std::string s_ = "abcdabcd"; + InType input_data_; + OutType expectedResult_ = 0; + + void SetUp() override { + for (int i = 0; i < kCount_; i++) { + input_data_ += s_; + } + expectedResult_ = static_cast(kCount_ * s_.size()); + } + + bool CheckTestOutputData(OutType &output_data) final { + return expectedResult_ == output_data; + } + + InType GetTestInputData() final { + return input_data_; + } +}; + +TEST_P(PapulinaYRunPerfTestProcesses, RunPerfModes) { + ExecuteTest(GetParam()); +} + +const auto kAllPerfTasks = ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_papulina_y_count_of_letters); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +const auto kPerfTestName = PapulinaYRunPerfTestProcesses::CustomPerfTestName; + +INSTANTIATE_TEST_SUITE_P(RunModeTests, PapulinaYRunPerfTestProcesses, kGtestValues, kPerfTestName); + +} // namespace papulina_y_count_of_letters