diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp new file mode 100644 index 0000000000..73db841da3 --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +#include "task/include/task.hpp" + +namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector { + +using InType = std::pair; // rows, cols +using OutType = std::vector; +using TestType = std::tuple, std::string>; +using BaseTask = ppc::task::Task; + +} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/info.json b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/info.json new file mode 100644 index 0000000000..bff316b642 --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/info.json @@ -0,0 +1,9 @@ +{ + "student": { + "first_name": "Елизавета", + "last_name": "Попова", + "middle_name": "Сергеевна", + "group_number": "3823Б1ПР1", + "task_number": "2" + } +} diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/include/ops_mpi.hpp b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/include/ops_mpi.hpp new file mode 100644 index 0000000000..635cb24351 --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/include/ops_mpi.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector { + +class PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kMPI; + } + explicit PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + + static std::pair GetLocalColumnsCounts(int cols, int rank, int size); + static void CountSeq(int rows, int cols, std::vector &result); + static void CountMpi(int rows, int cols, int rank, int size, std::vector &result); + + int rows_ = 0; + int cols_ = 0; +}; + +} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/src/ops_mpi.cpp b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/src/ops_mpi.cpp new file mode 100644 index 0000000000..6393ee806d --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/src/ops_mpi.cpp @@ -0,0 +1,112 @@ +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/include/ops_mpi.hpp" + +#include + +#include +#include + +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp" + +namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector { + +std::pair PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::GetLocalColumnsCounts(int cols, + int rank, + int size) { + int base_cols = cols / size; + int remainder = cols % size; + + int local_cols = base_cols; + if (rank < remainder) { + local_cols = local_cols + 1; + } + + int start_col = 0; + for (int i = 0; i < rank; ++i) { + int cols_for_i = base_cols; + if (i < remainder) { + cols_for_i = cols_for_i + 1; + } + start_col = start_col + cols_for_i; + } + + return {local_cols, start_col}; +} + +void PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::CountSeq(int rows, int cols, + std::vector &result) { + for (int i = 0; i < rows; ++i) { + double sum = 0.0; + for (int j = 0; j < cols; ++j) { + double matrix_value = (i + j) * 1.5; + double vector_value = j * 2.0; + sum += matrix_value * vector_value; + } + result[i] = sum; + } +} + +void PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::CountMpi(int rows, int cols, int rank, int size, + std::vector &result) { + auto [local_cols, start_col] = GetLocalColumnsCounts(cols, rank, size); + + std::vector local_result(rows, 0.0); + + for (int i = 0; i < rows; ++i) { + double sum = 0.0; + for (int j = 0; j < local_cols; ++j) { + int global_col = start_col + j; + double matrix_value = (i + global_col) * 1.5; + double vector_value = global_col * 2.0; + sum += matrix_value * vector_value; + } + local_result[i] = sum; + } + + MPI_Allreduce(local_result.data(), result.data(), rows, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +} + +PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI( + const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = std::vector(); +} + +bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::ValidationImpl() { + int rows = GetInput().first; + int cols = GetInput().second; + return (rows > 0 && cols > 0); +} + +bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::PreProcessingImpl() { + rows_ = GetInput().first; + cols_ = GetInput().second; + + GetOutput().resize(rows_, 0.0); + return true; +} + +bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::RunImpl() { + int rank = 0; + int size = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + if (cols_ < size) { + if (rank == 0) { + CountSeq(rows_, cols_, GetOutput()); + } + MPI_Bcast(GetOutput().data(), rows_, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } else { + CountMpi(rows_, cols_, rank, size, GetOutput()); + } + + MPI_Barrier(MPI_COMM_WORLD); + return true; +} + +bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::PostProcessingImpl() { + return true; +} + +} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/report.md b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/report.md new file mode 100644 index 0000000000..d4866abe05 --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/report.md @@ -0,0 +1,208 @@ +# Ленточная вертикальная схема - умножение матрицы на вектор + +- **Студент**: Попова Елизавета Сергеевна, группа 3823Б1ПР1 +- **Технология**: SEQ | MPI +- **Вариант**: 12 + +## 1. Введение + +Умножение матрицы на вектор — фундаментальная операция линейной алгебры, которая широко применима в научных вычислениях, машинном обучении, компьютерной графике и других областях. При умножении матрицы размером `m × n` на вектор размером `n` получается вектор размером `m`. + +Цель работы — реализовать алгоритм умножения матрицы на вектор с использованием вертикальной ленточной схемы, распараллелить его с помощью технологии MPI. + +## 2. Постановка задачи +Задача: реализовать последовательную (SEQ) и параллельную (MPI) версию умножения матрицы на вектор с использованием вертикальной ленточной схемы. + +Входные данные представлены в виде пары целых чисел (rows, cols): +```cpp +using InType = std::pair; +``` +- rows — количество строк матрицы (тип `int`, положительное число) +- cols — количество столбцов матрицы (тип `int`, положительное число) + +Выходные данные (результат вычислений) представлены в виде вектора размером `rows`: +```cpp +using OutType = std::vector; +``` + +Тестовые данные (содержание матрицы и вектора) генерируются по следующей схеме: +- Матрица А: `A[i][j] = (i + j) * 1.5` +- Вектор v: `v[j] = j * 2.0` + +Результат вычисляется как `result[i] = SUMMA (A[i][j] * v[j])` + + + +## 3. Базовый алгоритм (последовательная версия) +Последовательная версия алгоритма состоит из 4-х этапов: +1. `ValidationImpl()`: проверяем, что поступившие входные данные соответствуют органичениям (`rows > 0`, `cols > 0`). +2. `PreProcessingImpl()`: инициализация размеров задачи и выделение памяти для результата; +3. `RunImpl()`: основной этап вычислений: +- Для каждой строки матрицы выполняется суммирование произведений элементов строки на соответствующие элементы векторы; +- Результат сохраняется в выходной вектор. +```cpp +for (int i = 0; i < rows; ++i) { + double sum = 0.0; + for (int j = 0; j < cols; ++j) { + double matrix_value = (i + j) * 1.5; + double vector_value = j * 2.0; + sum += matrix_value * vector_value; + } + result[i] = sum; +} +``` +4. `PostProcessingImpl()`: завершающий этап. + + +## 4. Схема распараллеливания +При распараллеливании используется вертикальная ленточная схема (Vertical Ribbon Scheme): +- Матрица делится на части между процессами по столбцам; +- Каждый процесс получает блок столбцов матрицы и соответствующие элементы вектора; +- Каждый процесс вычисляет частичную сумму для каждой строки на своей части столбцов; +- Частичные суммы собираются воедино с помощью MPI_Allreduce. + +Особенности реализации: +- Если число столбцов меньше числа процессов, вычисления выполняются на процессе rank = 0, а результат рассылается через MPI_Bcast; +- При неравномерном делении столбцов первые процессы получают на один столбец больше; +- Для распределения столбцов используется вспомогательный метод `GetLocalColumnsCounts()`. + +## 5. Детали реализации + +Структура проекта +| Файл | Суть | +| ---------------------- | ------------------------------ | +| `common.hpp` | Общее определение типов данных | +| `ops_seq.hpp/.cpp` | Последовательная реализация | +| `ops_mpi.hpp/.cpp` | MPI-реализация | +| `functional/main.cpp` | Функциональные тесты | +| `performance/main.cpp` | Тесты на производительность | + +### 5.1. Метод распределения столбцов +Обеспечивается равномерное распределение нагрузки между процессами при вертикальном разделении матрицы. Кратко об алгоритме: +- Вычисляем базовое количество столбцов (минимальное на процесс); +- Считаем количество "лишних" столбцов, которые нужно распределить напервые процессы; +- Вычисляем начальный столбец (индекс) +```cpp +static std::pair GetLocalColumnsCounts(int cols, int rank, int size) { + int base_cols = cols / size; + int remainder = cols % size; + + int local_cols = base_cols; + if (rank < remainder) { + local_cols = local_cols + 1; + } + + int start_col = 0; + for (int i = 0; i < rank; ++i) { + int cols_for_i = base_cols; + if (i < remainder) { + cols_for_i = cols_for_i + 1; + } + start_col = start_col + cols_for_i; + } + + return {local_cols, start_col}; +} +``` + +### 5.2. Метод для параллельного вычисления +Реализуется параллельное вычисление. Кратко об алгоритме: +- Через `GetLocalColumnsCounts` получаем границы обрабатываемых столбцов; +- Каждый процесс вычисляет частичные суммы для своей части столбца; +- Суммируем частичные суммы всех процессов. + ```cpp +static void CountMpi(int rows, int cols, int rank, int size, + std::vector &result) { + auto [local_cols, start_col] = GetLocalColumnsCounts(cols, rank, size); + + std::vector local_result(rows, 0.0); + + for (int i = 0; i < rows; ++i) { + double sum = 0.0; + for (int j = 0; j < local_cols; ++j) { + int global_col = start_col + j; + double matrix_value = (i + global_col) * 1.5; + double vector_value = global_col * 2.0; + sum += matrix_value * vector_value; + } + local_result[i] = sum; +} + + MPI_Allreduce(local_result.data(), result.data(), + rows, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +} +``` + +### 5.3. Основная логика `RumImpl()` +Интеграция логики выполнения вычислений. Кратко: +- Получаем ранг и размер; +- Используем необходимый алгоритм в зависимости от соотношения процессов и столбцов. +```cpp +bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorMPI::RunImpl() { + int rank = 0, size = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + if (cols_ < size) { + if (rank == 0) { + CountSeq(rows_, cols_, GetOutput()); + } + MPI_Bcast(GetOutput().data(), rows_, MPI_DOUBLE, 0, MPI_COMM_WORLD); + } else { + CountMpi(rows_, cols_, rank, size, GetOutput()); + } + + MPI_Barrier(MPI_COMM_WORLD); + return true; +} +``` + + +## 6. Экспериментальная среда +| Параметр | Значение | +| ---------- | ------------------------------------------------ | +| CPU | Intel Core i3-6006U (2 ядра / 4 потока, 2.0 ГГц) | +| RAM | 8 GB | +| ОС | Windows 10 64-bit | +| Компилятор | MSVC (Visual Studio Build Tools) | +| MPI | Microsoft MPI 10.1 (mpiexec 10.1.12498.52) | + + +## 7. Результаты и обсуждение + + +### 7.1 Корректность +Функциональные тесты проверяют корректность вычислений для различных размеров матриц: +- Квадратные матрицы: (1×1), (2×2), (3×3), (4×4), (5×5), (10×10), (16×16), (17×17); +- Прямоугольные матрицы: (3×5), (5×3), (15×3), (3×15), (84×11), (11×84). + +Ожидаемый результат результат (с учетом одновременного заполнения матрицы) вычисляется по аналитической формуле: +- `expected[i] = SUMMA((i + j) * 1.5 * (j * 2.0))`, +- с точностью проверки `ε = 10^-10`. + +Обе реализации (`SEQ`, `MPI`) прошли все тесты успешно. + +### 7.2 Производительность +Результаты измерений на матрице размером 5000 х 5000 + +| Mode | Count | Time, s | Speedup | Efficiency | +| ---- | ----- | ------- | ------- | ---------- | +| SEQ | 1 | 0.0524 | 1 | N/A | +| MPI | 2 | 0.0343 | 1.53 | 76.5% | +| MPI | 4 | 0.0291 | 1.80 | 45.0% | + + + +## 8. Заключение +В ходе работы: +- Реализована последовательная версия умножения матрицы на вектор с использованием аналитических вормул без явного хранения матрицы; +- Разработана параллельная реализация с использованием вертикальной ленточной схемы распределения данных через MPI; +- Проведено тестирование корректность для разноразмерных матриц; +- Рассчитаны характеристики ускорения и эффективности для распараллеленого алгоритма. + + + +## 9. Источники +1. Сысоев А. В., Лекции по курсу «Параллельное программирование для кластерных систем». +2. Документация по курсу «Параллельное программирование», URL: https://learning-process.github.io/parallel_programming_course/ru/index.html +3. Репозиторий курса «Параллельное программирование», URL: https://github.com/learning-process/ppc-2025-processes-engineers \ No newline at end of file diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/seq/include/ops_seq.hpp b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/seq/include/ops_seq.hpp new file mode 100644 index 0000000000..6efbdc86c4 --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/seq/include/ops_seq.hpp @@ -0,0 +1,28 @@ +#pragma once +#include + +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp" +#include "task/include/task.hpp" + +namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector { + +class PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + explicit PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorSEQ(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; + + std::vector> matrix_; + std::vector vector_; + int rows_ = 0; + int cols_ = 0; +}; + +} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/seq/src/ops_seq.cpp b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/seq/src/ops_seq.cpp new file mode 100644 index 0000000000..1bab3dfe64 --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/seq/src/ops_seq.cpp @@ -0,0 +1,54 @@ +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/seq/include/ops_seq.hpp" + +#include + +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp" +// #include "util/include/util.hpp" + +namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector { + +PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorSEQ::PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorSEQ( + const InType &in) { + SetTypeOfTask(GetStaticTypeOfTask()); + GetInput() = in; + GetOutput() = std::vector(); +} + +bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorSEQ::ValidationImpl() { + int rows = GetInput().first; + int cols = GetInput().second; + return (rows > 0 && cols > 0) && GetOutput().empty(); +} + +bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorSEQ::PreProcessingImpl() { + rows_ = GetInput().first; + cols_ = GetInput().second; + + GetOutput().resize(rows_, 0.0); + + return true; +} + +bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorSEQ::RunImpl() { + int rows = rows_; + int cols = cols_; + auto &result = GetOutput(); + + for (int i = 0; i < rows; ++i) { + double sum = 0.0; + for (int j = 0; j < cols; ++j) { + double matrix_value = (i + j) * 1.5; + double vector_value = j * 2.0; + sum += matrix_value * vector_value; + } + result[i] = sum; + } + + return true; +} + +bool PopovaEVerticalRibbonSchemeMatrixMultiplicationByVectorSEQ::PostProcessingImpl() { + return true; +} + +} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/settings.json b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/settings.json new file mode 100644 index 0000000000..b1a0d52574 --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/settings.json @@ -0,0 +1,7 @@ +{ + "tasks_type": "processes", + "tasks": { + "mpi": "enabled", + "seq": "enabled" + } +} diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/tests/.clang-tidy b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/tests/.clang-tidy new file mode 100644 index 0000000000..ef43b7aa8a --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/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/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/tests/functional/main.cpp b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/tests/functional/main.cpp new file mode 100644 index 0000000000..1a2322d26e --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/tests/functional/main.cpp @@ -0,0 +1,116 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp" +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/include/ops_mpi.hpp" +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" + +namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector { + +static std::vector CalculateExpectedResult(const InType &input); + +class PopovaEMatrixVectorRunFuncTestsProcesses : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + auto input = std::get<0>(test_param); + std::string description = std::get<1>(test_param); + return std::to_string(input.first) + "x" + std::to_string(input.second) + "_" + description; + } + + 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 { + int rows = input_data_.first; + + if (output_data.size() != static_cast(rows)) { + return false; + } + + auto expected = CalculateExpectedResult(input_data_); + + double epsilon = 1e-10; + for (size_t i = 0; i < expected.size(); ++i) { + if (std::abs(output_data[i] - expected[i]) > epsilon) { + return false; + } + } + + return true; + } + + InType GetTestInputData() final { + return input_data_; + } + + private: + InType input_data_; +}; + +std::vector CalculateExpectedResult(const InType &input) { + int rows = input.first; + int cols = input.second; + std::vector expected(rows, 0.0); + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + double matrix_value = (i + j) * 1.5; + double vector_value = j * 2.0; + expected[i] += matrix_value * vector_value; + } + } + + return expected; +} + +namespace { + +TEST_P(PopovaEMatrixVectorRunFuncTestsProcesses, MatmulFromPic) { + ExecuteTest(GetParam()); +} + +const std::array kTestParam = {std::make_tuple(std::make_pair(1, 1), "square_matrix_1x1"), + std::make_tuple(std::make_pair(2, 2), "square_matrix_2x2"), + std::make_tuple(std::make_pair(3, 3), "square_matrix_3x3"), + std::make_tuple(std::make_pair(4, 4), "square_matrix_4x4"), + std::make_tuple(std::make_pair(5, 5), "square_matrix_5x5"), + std::make_tuple(std::make_pair(10, 10), "square_matrix_10x10"), + std::make_tuple(std::make_pair(16, 16), "square_matrix_16x16"), + std::make_tuple(std::make_pair(17, 17), "square_matrix_17x17"), + std::make_tuple(std::make_pair(3, 5), "rectangular_matrix_3x5"), + std::make_tuple(std::make_pair(5, 3), "rectangular_matrix_5x3"), + std::make_tuple(std::make_pair(15, 3), "rectangular_matrix_15x3"), + std::make_tuple(std::make_pair(3, 15), "rectangular_matrix_3x15"), + std::make_tuple(std::make_pair(84, 11), "rectangular_matrix_84x11"), + std::make_tuple(std::make_pair(11, 84), "rectangular_matrix_11x84")}; + +const auto kTestTasksList = + std::tuple_cat(ppc::util::AddFuncTask( + kTestParam, PPC_SETTINGS_popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector), + ppc::util::AddFuncTask( + kTestParam, PPC_SETTINGS_popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTestTasksList); + +const auto kPerfTestName = + PopovaEMatrixVectorRunFuncTestsProcesses::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(MatrixMultiplicationTests, PopovaEMatrixVectorRunFuncTestsProcesses, kGtestValues, + kPerfTestName); + +} // namespace + +} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector diff --git a/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/tests/performance/main.cpp b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/tests/performance/main.cpp new file mode 100644 index 0000000000..8246ada6ca --- /dev/null +++ b/tasks/popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/tests/performance/main.cpp @@ -0,0 +1,78 @@ +#include + +#include +#include +#include +#include + +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/common/include/common.hpp" +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/mpi/include/ops_mpi.hpp" +#include "popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector/seq/include/ops_seq.hpp" +#include "util/include/perf_test_util.hpp" + +namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector { + +static std::vector CalculateExpectedResult(const InType &input) { + int rows = input.first; + int cols = input.second; + std::vector expected(rows, 0.0); + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + double matrix_value = (i + j) * 1.5; + double vector_value = j * 2.0; + expected[i] += matrix_value * vector_value; + } + } + + return expected; +} + +class PopovaEMatrixMultiplicationByVectorRunPerfTestProcesses : public ppc::util::BaseRunPerfTests { + InType input_data_; + + void SetUp() override { + input_data_ = std::make_pair(5000, 5000); + } + + bool CheckTestOutputData(OutType &output_data) final { + int rows = input_data_.first; + + if (output_data.size() != static_cast(rows)) { + return false; + } + + auto expected = CalculateExpectedResult(input_data_); + + double epsilon = 1e-5; + for (size_t i = 0; i < expected.size(); i++) { + if (std::abs(output_data[i] - expected[i]) > epsilon) { + return false; + } + } + + return true; + } + + InType GetTestInputData() final { + return input_data_; + } +}; + +TEST_P(PopovaEMatrixMultiplicationByVectorRunPerfTestProcesses, RunPerfModes) { + ExecuteTest(GetParam()); +} + +const auto kAllPerfTasks = + ppc::util::MakeAllPerfTasks( + PPC_SETTINGS_popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector); + +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +const auto kPerfTestName = PopovaEMatrixMultiplicationByVectorRunPerfTestProcesses::CustomPerfTestName; + +INSTANTIATE_TEST_SUITE_P(RunModeTests, PopovaEMatrixMultiplicationByVectorRunPerfTestProcesses, kGtestValues, + kPerfTestName); + +} // namespace popova_e_vertical_ribbon_scheme_matrix_multiplication_by_vector