-
Notifications
You must be signed in to change notification settings - Fork 80
Никитина Валерия. Технология SEQ-MPI. Максимальное значение элементов матрицы. Вариант 13. #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
b3ffcd5
ver_1.0
Leraniki b3adbdd
change matrix size
Leraniki ec8b626
change matrix size and report
Leraniki 35b6160
change matrix size
Leraniki 778d8c7
edit tests
Leraniki e60940b
edit tests_3
Leraniki 60f0d79
edit tests_4
Leraniki 16f7c7b
edit tests_5
Leraniki 7336df4
edit tests_6
Leraniki 3fb210f
add report
Leraniki b32d9f0
try solve clang-tidy
Leraniki 72dded5
try to solve clang_tidy_2
Leraniki 9afd9ad
try to solve clang_tidy_3
Leraniki 321b704
try to solve clang_tidy_4
Leraniki f3f485b
try to solve clang_tidy_5
Leraniki 0f76a25
Merge pull request #1 from Leraniki/nikitina_v_max_elem_matr
Leraniki 6214f2a
change bcast
Leraniki b7f820d
Merge pull request #2 from Leraniki/nikitina_v_max_elem_matr
Leraniki File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #pragma once | ||
|
|
||
| #include <vector> | ||
|
|
||
| #include "task/include/task.hpp" | ||
|
|
||
| namespace nikitina_v_max_elem_matr { | ||
|
|
||
| using InType = std::vector<int>; | ||
| using OutType = int; | ||
|
|
||
| using BaseTask = ppc::task::Task<InType, OutType>; | ||
|
|
||
| } // namespace nikitina_v_max_elem_matr |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "student": { | ||
| "first_name": "Валерия", | ||
| "last_name": "Никитина", | ||
| "middle_name": "Владимировна", | ||
| "group_number": "3823Б1ФИ2", | ||
| "task_number": "1" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #pragma once | ||
|
|
||
| #include <vector> | ||
|
|
||
| #include "nikitina_v_max_elem_matr/common/include/common.hpp" | ||
| #include "task/include/task.hpp" | ||
|
|
||
| namespace nikitina_v_max_elem_matr { | ||
|
|
||
| class MaxElementMatrMPI : public BaseTask { | ||
| public: | ||
| static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { | ||
| return ppc::task::TypeOfTask::kMPI; | ||
| } | ||
| explicit MaxElementMatrMPI(const InType &in); | ||
|
|
||
| private: | ||
| bool ValidationImpl() override; | ||
| bool PreProcessingImpl() override; | ||
| bool RunImpl() override; | ||
| bool PostProcessingImpl() override; | ||
|
|
||
| static void CalculateScatterParams(int total_elements, int world_size, std::vector<int> &sendcounts, | ||
| std::vector<int> &displs); | ||
| static int FindLocalMax(const std::vector<int> &data); | ||
|
|
||
| int rows_{}; | ||
| int cols_{}; | ||
| int global_max_{}; | ||
| std::vector<int> matrix_; | ||
| }; | ||
|
|
||
| } // namespace nikitina_v_max_elem_matr |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| #include "nikitina_v_max_elem_matr/mpi/include/ops_mpi.hpp" | ||
|
|
||
| #include <mpi.h> | ||
|
|
||
| #include <algorithm> | ||
| #include <cstddef> | ||
| #include <iterator> | ||
| #include <limits> | ||
| #include <vector> | ||
|
|
||
| #include "nikitina_v_max_elem_matr/common/include/common.hpp" | ||
|
|
||
| namespace nikitina_v_max_elem_matr { | ||
|
|
||
| MaxElementMatrMPI::MaxElementMatrMPI(const InType &in) : BaseTask() { | ||
| SetTypeOfTask(GetStaticTypeOfTask()); | ||
| GetInput() = in; | ||
| } | ||
|
|
||
| bool MaxElementMatrMPI::ValidationImpl() { | ||
| int rank = 0; | ||
| MPI_Comm_rank(MPI_COMM_WORLD, &rank); | ||
|
|
||
| if (rank == 0) { | ||
| const auto &in = GetInput(); | ||
| if (in.size() < 2) { | ||
| return false; | ||
| } | ||
| rows_ = in[0]; | ||
| cols_ = in[1]; | ||
| return rows_ >= 0 && cols_ >= 0 && static_cast<size_t>(rows_) * cols_ == in.size() - 2; | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| bool MaxElementMatrMPI::PreProcessingImpl() { | ||
| int rank = 0; | ||
| MPI_Comm_rank(MPI_COMM_WORLD, &rank); | ||
|
|
||
| if (rank == 0) { | ||
| const auto &in = GetInput(); | ||
| matrix_.clear(); | ||
| if (rows_ > 0 && cols_ > 0) { | ||
| matrix_.reserve(static_cast<size_t>(rows_) * cols_); | ||
| std::copy(in.begin() + 2, in.end(), std::back_inserter(matrix_)); | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| void MaxElementMatrMPI::CalculateScatterParams(int total_elements, int world_size, std::vector<int> &sendcounts, | ||
| std::vector<int> &displs) { | ||
| const int elements_per_proc = total_elements / world_size; | ||
| const int remainder_elements = total_elements % world_size; | ||
| int current_displ = 0; | ||
| for (int i = 0; i < world_size; ++i) { | ||
| sendcounts[i] = (i < remainder_elements) ? elements_per_proc + 1 : elements_per_proc; | ||
| displs[i] = current_displ; | ||
| current_displ += sendcounts[i]; | ||
| } | ||
| } | ||
|
|
||
| int MaxElementMatrMPI::FindLocalMax(const std::vector<int> &data) { | ||
| if (data.empty()) { | ||
| return std::numeric_limits<int>::min(); | ||
| } | ||
| int max_val = data[0]; | ||
| for (size_t i = 1; i < data.size(); ++i) { | ||
| max_val = std::max(max_val, data[i]); | ||
| } | ||
| return max_val; | ||
| } | ||
|
|
||
| bool MaxElementMatrMPI::RunImpl() { | ||
| int world_size = 0; | ||
| int rank = 0; | ||
| MPI_Comm_size(MPI_COMM_WORLD, &world_size); | ||
| MPI_Comm_rank(MPI_COMM_WORLD, &rank); | ||
|
|
||
| MPI_Bcast(&rows_, 1, MPI_INT, 0, MPI_COMM_WORLD); | ||
| MPI_Bcast(&cols_, 1, MPI_INT, 0, MPI_COMM_WORLD); | ||
|
|
||
| if (static_cast<size_t>(rows_) * cols_ == 0) { | ||
| global_max_ = std::numeric_limits<int>::min(); | ||
| } else { | ||
| const int total_elements = rows_ * cols_; | ||
| std::vector<int> sendcounts(world_size); | ||
| std::vector<int> displs(world_size); | ||
|
|
||
| if (rank == 0) { | ||
| CalculateScatterParams(total_elements, world_size, sendcounts, displs); | ||
| } | ||
|
|
||
| MPI_Bcast(sendcounts.data(), world_size, MPI_INT, 0, MPI_COMM_WORLD); | ||
| MPI_Bcast(displs.data(), world_size, MPI_INT, 0, MPI_COMM_WORLD); | ||
|
|
||
| std::vector<int> recv_buf(sendcounts[rank]); | ||
| const int *send_buf = (rank == 0) ? matrix_.data() : nullptr; | ||
|
|
||
| MPI_Scatterv(send_buf, sendcounts.data(), displs.data(), MPI_INT, recv_buf.data(), sendcounts[rank], MPI_INT, 0, | ||
| MPI_COMM_WORLD); | ||
|
|
||
| int local_max = FindLocalMax(recv_buf); | ||
| MPI_Reduce(&local_max, &global_max_, 1, MPI_INT, MPI_MAX, 0, MPI_COMM_WORLD); | ||
| } | ||
|
|
||
| MPI_Bcast(&global_max_, 1, MPI_INT, 0, MPI_COMM_WORLD); | ||
| return true; | ||
| } | ||
|
|
||
| bool MaxElementMatrMPI::PostProcessingImpl() { | ||
| GetOutput() = global_max_; | ||
| return true; | ||
| } | ||
|
|
||
| } // namespace nikitina_v_max_elem_matr | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| # Поиск максимального элемента в целочисленной матрице | ||
|
|
||
| - **Студент:** `<Никитина Валерия Владимировна>`, группа `<3823Б1ФИ2>` | ||
| - **Технология:** SEQ, MPI | ||
| - **Вариант:** `<13>` | ||
|
|
||
| ## 1. Введение | ||
|
|
||
| Поиск экстремальных значений является одной из фундаментальных операций в анализе данных. При работе с большими матрицами последовательное выполнение этой задачи может занимать значительное время. Распараллеливание алгоритма с использованием технологии Message Passing Interface (MPI) позволяет сократить время вычислений за счет одновременной обработки разных частей данных на нескольких вычислительных узлах. | ||
|
|
||
| Целью данной работы является реализация и сравнение производительности последовательного и параллельного (MPI) алгоритмов для поиска максимального элемента в целочисленной матрице, а также обеспечение полной корректности и тестового покрытия реализованного решения. | ||
|
|
||
| ## 2. Постановка задачи | ||
|
|
||
| **Входные данные:** Целочисленная матрица, представленная в виде одномерного вектора `std::vector<int>`. Первые два элемента вектора задают размеры матрицы: количество строк `rows` и столбцов `cols`. Остальные `rows * cols` элементов представляют собой данные матрицы. | ||
|
|
||
| **Выходные данные:** Одно целое число — максимальное значение среди всех элементов матрицы. | ||
|
|
||
| **Ограничения:** | ||
| - Элементы матрицы — целые числа. | ||
| - Матрица с нулевыми размерами (например, `10x0` или `0x10`) является валидным входным данным. Для таких матриц результат равен `INT_MIN`. | ||
| - Входные данные с отрицательными размерами или некорректным количеством элементов считаются невалидными. | ||
|
|
||
| ## 3. Описание алгоритма (базового/последовательного) | ||
|
|
||
| Последовательный алгоритм представляет собой простой линейный обход всех элементов матрицы. | ||
|
|
||
| 1. Проводится валидация входных данных: проверяется, что размеры матрицы неотрицательные и соответствуют фактическому количеству переданных элементов. | ||
| 2. Инициализируется переменная `global_max` минимально возможным значением для типа `int` (`INT_MIN`). | ||
| 3. Если матрица не пуста, организуется цикл, который итерируется по каждому элементу. | ||
| 4. На каждой итерации текущий элемент матрицы сравнивается со значением `global_max`. Если текущий элемент больше, `global_max` обновляется. | ||
| 5. После завершения обхода переменная `global_max` содержит искомое максимальное значение. | ||
|
|
||
| Временная сложность данного алгоритма составляет O(N × M), где N и M — размеры матрицы. | ||
|
|
||
| ## 4. Схема распараллеливания | ||
|
|
||
| Для распараллеливания задачи с использованием технологии MPI была выбрана модель "Мастер-Рабочий" (Master-Worker). Декомпозиция данных выполняется путем разделения исходной матрицы на примерно равные непрерывные части. | ||
|
|
||
| - **Валидация:** Каждый MPI-процесс самостоятельно выполняет проверку входных данных для достижения 100% тестового покрытия ветвей кода. | ||
|
|
||
| - **Схема обменов данными:** | ||
| 1. **Процесс с рангом 0 (Мастер):** Хранит полную исходную матрицу. | ||
| 2. **`MPI_Scatterv`:** Мастер распределяет данные. Он вычисляет, сколько элементов будет обрабатывать каждый процесс, и рассылает соответствующие части матрицы всем процессам (включая себя). | ||
| 3. **Локальные вычисления:** Каждый процесс находит максимальный элемент в своей локальной части (`local_max`). | ||
| 4. **`MPI_Reduce`:** Все процессы участвуют в коллективной операции редукции, в результате которой на 0-м процессе вычисляется глобальный максимум (`global_max`). | ||
| 5. **`MPI_Bcast`:** Процесс 0 рассылает финальный `global_max` всем остальным процессам. Этот шаг критически важен, так как тестовый фреймворк проверяет корректность результата на каждом процессе. | ||
|
|
||
| Эта схема позволяет эффективно распределить вычислительную нагрузку, минимизируя коммуникации. | ||
|
|
||
| ## 5. Экспериментальная установка | ||
|
|
||
| - **Окружение:** Разработка и локальное тестирование проводились в контейнере Docker на базе Ubuntu. | ||
| - **CPU:** Предоставлено средой выполнения (2 виртуальных ядра). | ||
| - **Toolchain:** | ||
| - Компилятор: GCC 14.2.0 | ||
| - Система сборки: CMake | ||
| - Тип сборки: `Release` | ||
| - **Переменные окружения:** Эксперименты проводились при `PPC_NUM_PROC=2`. | ||
| - **Данные для тестов:** | ||
| - **Функциональные тесты:** Матрицы различных размеров, включая граничные и невалидные случаи. | ||
| - **Тесты производительности:** Матрица размером **12000x12000**, заполненная случайными целыми числами. | ||
|
|
||
| ## 6. Результаты и обсуждение | ||
|
|
||
| ### 6.1. Корректность и тестовое покрытие | ||
|
|
||
| Корректность работы алгоритмов проверялась с помощью исчерпывающего набора GTest'ов, включающего как тесты на валидных данных, так и тесты, проверяющие обработку некорректных входных данных. Благодаря этому было достигнуто **100% покрытие строк и ветвей кода**, что гарантирует надежность реализованных функций. | ||
|
|
||
| ### 6.2. Производительность | ||
|
|
||
| Измерения времени выполнения проводились на матрице 12000x12000. Ускорение (Speedup) вычислялось как S(p) = T(1) / T(p), а эффективность (Efficiency) как E(p) = S(p) / p. | ||
|
|
||
| | Режим | Кол-во процессов (p) | Время, с | Ускорение (S) | Эффективность (E) | | ||
| | :---- | :------------------: | :------- | :------------ | :---------------- | | ||
| | seq | 1 | **0.415**| 1.00 | 100% | | ||
| | mpi | 2 | **0.224**| 1.85 | 92.5% | | ||
|
|
||
| **Анализ результатов:** | ||
|
|
||
| Параллельная MPI-реализация на двух процессах показала значительное **ускорение в 1.85 раза** по сравнению с последовательной версией. Это близко к идеальному двукратному ускорению, что свидетельствует о высокой эффективности распараллеливания. | ||
|
|
||
| Эффективность в `92.5%` означает, что только 7.5% времени было потрачено на накладные расходы, связанные с работой MPI (раздача данных и сбор результатов). Такой высокий показатель подтверждает, что для данной задачи на двух процессах вычислительная нагрузка хорошо распределяется, а коммуникационные издержки минимальны. | ||
|
|
||
| ## 7. Выводы | ||
|
|
||
| В ходе выполнения работы были успешно реализованы, протестированы и отлажены последовательный и параллельный (MPI) алгоритмы для поиска максимального элемента в матрице. | ||
|
|
||
| Экспериментальные замеры показали, что MPI-реализация на двух процессах достигает ускорения `1.85x` при эффективности `92.5%`. Это подтверждает, что выбранная схема распараллеливания является высокоэффективной для данной задачи и позволяет значительно сократить время выполнения по сравнению с последовательным подходом. | ||
|
|
||
| ## 8. Источники | ||
|
|
||
| 1. Open MPI Documentation — [https://www.open-mpi.org/doc/](https://www.open-mpi.org/doc/) | ||
| 2. Peter S. Pacheco. Parallel Programming with MPI. Morgan Kaufmann, 1996. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| #pragma once | ||
|
|
||
| #include <vector> | ||
|
|
||
| #include "nikitina_v_max_elem_matr/common/include/common.hpp" | ||
| #include "task/include/task.hpp" | ||
|
|
||
| namespace nikitina_v_max_elem_matr { | ||
|
|
||
| class MaxElementMatrSEQ : public BaseTask { | ||
| public: | ||
| static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { | ||
| return ppc::task::TypeOfTask::kSEQ; | ||
| } | ||
| explicit MaxElementMatrSEQ(const InType &in); | ||
|
|
||
| private: | ||
| bool ValidationImpl() override; | ||
| bool PreProcessingImpl() override; | ||
| bool RunImpl() override; | ||
| bool PostProcessingImpl() override; | ||
|
|
||
| int rows_{}; | ||
| int cols_{}; | ||
| int max_val_{}; | ||
| std::vector<int> matrix_; | ||
| }; | ||
|
|
||
| } // namespace nikitina_v_max_elem_matr |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| #include "nikitina_v_max_elem_matr/seq/include/ops_seq.hpp" | ||
|
|
||
| #include <algorithm> | ||
| #include <cstddef> | ||
| #include <iterator> | ||
| #include <limits> | ||
| #include <vector> | ||
|
|
||
| #include "nikitina_v_max_elem_matr/common/include/common.hpp" | ||
|
|
||
| namespace nikitina_v_max_elem_matr { | ||
|
|
||
| MaxElementMatrSEQ::MaxElementMatrSEQ(const InType &in) : BaseTask() { | ||
| SetTypeOfTask(GetStaticTypeOfTask()); | ||
| GetInput() = in; | ||
| } | ||
|
|
||
| bool MaxElementMatrSEQ::ValidationImpl() { | ||
| const auto &in = GetInput(); | ||
| if (in.size() < 2) { | ||
| return false; | ||
| } | ||
| rows_ = in[0]; | ||
| cols_ = in[1]; | ||
| return rows_ >= 0 && cols_ >= 0 && static_cast<size_t>(rows_) * cols_ == in.size() - 2; | ||
| } | ||
|
|
||
| bool MaxElementMatrSEQ::PreProcessingImpl() { | ||
| const auto &in = GetInput(); | ||
| matrix_.clear(); | ||
| if (rows_ > 0 && cols_ > 0) { | ||
| matrix_.reserve(static_cast<size_t>(rows_) * cols_); | ||
| std::copy(in.begin() + 2, in.end(), std::back_inserter(matrix_)); | ||
| } | ||
| max_val_ = std::numeric_limits<int>::min(); | ||
| return true; | ||
| } | ||
|
|
||
| bool MaxElementMatrSEQ::RunImpl() { | ||
| if (matrix_.empty()) { | ||
| max_val_ = std::numeric_limits<int>::min(); | ||
| return true; | ||
| } | ||
| max_val_ = matrix_[0]; | ||
| for (size_t i = 1; i < matrix_.size(); ++i) { | ||
| max_val_ = std::max(max_val_, matrix_[i]); | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| bool MaxElementMatrSEQ::PostProcessingImpl() { | ||
| GetOutput() = max_val_; | ||
| return true; | ||
| } | ||
|
|
||
| } // namespace nikitina_v_max_elem_matr |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "tasks_type": "processes", | ||
| "tasks": { | ||
| "mpi": "enabled", | ||
| "seq": "enabled" | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.