-
Notifications
You must be signed in to change notification settings - Fork 80
Савва Дария. Технология SEQ|MPI. Минимальное значение элементов вектора. Вариант 4 #34
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
aobolensk
merged 8 commits into
learning-process:master
from
DariyaSavva:savva_d_min_element_vector
Jan 3, 2026
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
458d4d5
add task and tests and report
DariyaSavva ae822a9
fix clang-format
DariyaSavva ab5c331
Fix code formatting and line endings
DariyaSavva b422fa7
fix include
DariyaSavva 14a2964
modifix report
DariyaSavva 3cd2ef7
fix mpi_version
DariyaSavva 94b51a0
fix remember
DariyaSavva 377460a
fix clangformat
DariyaSavva 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,17 @@ | ||
| #pragma once | ||
|
|
||
| #include <string> | ||
| #include <tuple> | ||
| #include <vector> | ||
|
|
||
| #include "task/include/task.hpp" | ||
|
|
||
| namespace savva_d_min_elem_vec { | ||
|
|
||
| using InType = std::vector<int>; | ||
| using OutType = int; | ||
| using TestType = std::tuple<std::vector<int>, std::string>; // нужен как вспомогательный тип, чтобы было удобно | ||
| // проводить тесты (например хранит путь к файлу) | ||
| using BaseTask = ppc::task::Task<InType, OutType>; | ||
|
|
||
| } // namespace savva_d_min_elem_vec |
Large diffs are not rendered by default.
Oops, something went wrong.
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ФИ1", | ||
| "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,22 @@ | ||
| #pragma once | ||
|
|
||
| #include "savva_d_min_elem_vec/common/include/common.hpp" | ||
| #include "task/include/task.hpp" | ||
|
|
||
| namespace savva_d_min_elem_vec { | ||
|
|
||
| class SavvaDMinElemVecMPI : public BaseTask { | ||
| public: | ||
| static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { | ||
| return ppc::task::TypeOfTask::kMPI; | ||
| } | ||
| explicit SavvaDMinElemVecMPI(const InType &in); | ||
|
|
||
| private: | ||
| bool ValidationImpl() override; | ||
| bool PreProcessingImpl() override; | ||
| bool RunImpl() override; | ||
| bool PostProcessingImpl() override; | ||
| }; | ||
|
|
||
| } // namespace savva_d_min_elem_vec |
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,89 @@ | ||
| #include "savva_d_min_elem_vec/mpi/include/ops_mpi.hpp" | ||
|
|
||
| #include <mpi.h> | ||
|
|
||
| #include <algorithm> | ||
| #include <limits> | ||
| #include <vector> | ||
|
|
||
| #include "savva_d_min_elem_vec/common/include/common.hpp" | ||
|
|
||
| namespace savva_d_min_elem_vec { | ||
|
|
||
| SavvaDMinElemVecMPI::SavvaDMinElemVecMPI(const InType &in) { // эта функция не изменяется в задачах | ||
| SetTypeOfTask(GetStaticTypeOfTask()); // конструктор правильная постановка задачи | ||
| GetInput() = in; // GetInput() нужен чтобы больше не использовать сами данные in | ||
| GetOutput() = 0; | ||
| } | ||
|
|
||
| bool SavvaDMinElemVecMPI::ValidationImpl() { | ||
| return (!GetInput().empty()) && (GetOutput() == 0); | ||
| } | ||
|
|
||
| bool SavvaDMinElemVecMPI::PreProcessingImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| bool SavvaDMinElemVecMPI::RunImpl() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no data scatter from rank 0 to other ranks |
||
| int rank = 0; | ||
| int size = 0; | ||
| MPI_Comm_rank(MPI_COMM_WORLD, &rank); | ||
| MPI_Comm_size(MPI_COMM_WORLD, &size); | ||
| int local_n = 0; | ||
| int global_n = 0; | ||
| int *local_data = nullptr; | ||
| const int *global_data = nullptr; | ||
| int *counts = new int[size](); | ||
| int *displacements = new int[size](); | ||
|
|
||
| // если вектор - пустой, то false | ||
| if (rank == 0) { | ||
| global_data = GetInput().data(); | ||
| global_n = static_cast<int>(GetInput().size()); | ||
| int elements_per_proc = global_n / size; | ||
| int remainder = global_n % size; | ||
| int offset = 0; | ||
|
|
||
| for (int i = 0; i < size; ++i) { | ||
| counts[i] = elements_per_proc + (i < remainder ? 1 : 0); | ||
| displacements[i] = offset; | ||
| offset += counts[i]; | ||
| } | ||
| } | ||
|
|
||
| MPI_Bcast(&global_n, 1, MPI_INT, 0, MPI_COMM_WORLD); | ||
| if (global_n == 0) { | ||
| delete[] counts; | ||
| delete[] displacements; | ||
| return false; | ||
| } | ||
| MPI_Bcast(counts, size, MPI_INT, 0, MPI_COMM_WORLD); | ||
| local_data = new int[counts[rank]]; | ||
| local_n = counts[rank]; | ||
| MPI_Scatterv(global_data, counts, displacements, MPI_INT, local_data, local_n, MPI_INT, 0, MPI_COMM_WORLD); | ||
|
|
||
| int local_min = std::numeric_limits<int>::max(); | ||
| for (int i = 0; i < local_n; ++i) { | ||
| local_min = std::min(local_data[i], local_min); | ||
| } | ||
|
|
||
| int global_min = 0; | ||
| MPI_Allreduce(&local_min, &global_min, 1, MPI_INT, MPI_MIN, MPI_COMM_WORLD); | ||
|
|
||
| GetOutput() = global_min; | ||
|
|
||
| delete[] counts; | ||
| delete[] displacements; | ||
| delete[] local_data; | ||
|
|
||
| // Синхронизация | ||
| MPI_Barrier(MPI_COMM_WORLD); | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| bool SavvaDMinElemVecMPI::PostProcessingImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| } // namespace savva_d_min_elem_vec | ||
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,108 @@ | ||
| # Минимальный элемент вектора | ||
|
|
||
| - Студент: Савва Дария Александровна, 3823Б1ФИ1 | ||
| - Технологии: SEQ | MPI | ||
| - Вариант: 4 | ||
|
|
||
| ## 1. Введение | ||
| Целью данной работы является реализация алгоритма нахождения минимального элемента вектора. Алгоритм должен иметь последовательную и параллельную версии. | ||
|
|
||
| ## 2. Постановка задачи | ||
| Дан вектор составленный из N элементов, элементами являются числа. Среди данных элементов необходимо найти элемент, имеющий минимальное значение. | ||
|
|
||
| ## 3. Описание линейного алгоритма | ||
|
|
||
| Последовательная версия: | ||
| осуществляется последовательный проход по всем элементам вектора, на каждом шаге сравнивается значение текущего элемента с элементом, который является минимальным на данный момент. | ||
|
|
||
|
|
||
| ## 4. Описание схемы параллельного алгоритма | ||
| Пусть имеется K процессов и вектор размера N. Если N кратно K, вектор делится на K равных частей. Каждая часть обратывается соответсвующим процессом. | ||
| Локальная обработка части вектора - это последовательный поиск минимума в данной части вектора. Если N не кратно K, каждый процесс получает S элементов, | ||
| где S - результат целочисленного деления N на K, и первые M процессов получают на один элемент больше, где M - остаток от деления N на K. | ||
| Таким образом, вектор делится процессами на примерно равные части, каждая из которых локально обрабатывается своим процессом, что обеспечивает максимальную эффективность алгоритма. | ||
| Когда локальная обработка процессами завершена, результат пересылается на нулевой процесс, на котором вычисляется минимум из локальных минимумов. Затем осуществляется рассылка | ||
| результата на другие процессы. | ||
|
|
||
|
|
||
| ## Описание программной реализации параллельного алгоритма | ||
| Реализация выполнена на языке C++ с использованием библиотеки MPI. | ||
|
|
||
| Основные этапы: | ||
| - Инициализация и валидация входных данных; | ||
| - Определение диапазона элементов, обрабатываемых каждым процессом; | ||
| - Локальное вычисление минимума; | ||
| - Сбор частичных результатов между всеми процессами, нахождение и пересылка результата на каждый процесс при помощи MPI-функции `MPI_Allreduce`; | ||
| - Возврат итогового значения каждым процессом. | ||
| ### Ключевые функции: | ||
| - `MPI_Comm_rank`, `MPI_Comm_size` — определяют номер процесса и общее количество процессов; | ||
| - `MPI_Allreduce` — собирает результаты со всех процессов и осуществляет над ними итоговую операцию поиска минимума, рассылая итоговый результат на все процессы. | ||
| ### Валидация данных | ||
| Не допускается пустой вектор в качестве входных данных, поскольку в нём невозможно опеределить минимальный элемент. | ||
|
|
||
|
|
||
| ## Результаты экспериментов | ||
| ### Условия экспериментов | ||
| - Размеры векторов: \(10^7\) , \(5*10^7\) , \(10^9\) элементов. | ||
| - Среда выполнения: Windows, MPI (4 процесса). | ||
| - Измерение времени проводилось встроенными средствами тестового фреймворка GoogleTest. | ||
| --- | ||
| ### Результаты при размере вектора \(10^7\) | ||
| | Режим выполнения | Число процессов | Время (сек) | Ускорение | Эффективность, % | | ||
| |:-----------------|-------------:|-----------------:|:-------------|-------------| | ||
| | SEQ | 1 | 9.15 | 1.00 | | | ||
| | MPI | 2 | 9.1 | 1.01 | 25,2 | | ||
| | MPI | 4 | 12.5 | 0.99 | 24,7 | | ||
| | MPI | 8 | 24.9 | 0.99 | 12,3 | | ||
| **Вывод:** наибольшее ускорение достигается при 2 процессах, что не ожидалось, поскольку процессор имеет 4 ядра, возможно это связано с тем что при 2 процессах меньше накладные расходы на коммуникацию | ||
| --- | ||
| ### Результаты при размере вектора \(5*10^7\) | ||
| | Режим выполнения | Число процессов | Время (сек) | Ускорение | Эффективность, % | | ||
| |:-----------------|-------------:|-----------------:|:-------------|-------------| | ||
| | SEQ | 1 | 44.5 | 1.00 | | | ||
| | MPI | 2 | 44.8 | 0.99 | 12,3 | | ||
| | MPI | 4 | 60.6 | 1.01 | 25,2 | | ||
| | MPI | 8 | 24.9 | 0.99 | 12,3 | | ||
| **Вывод:** как ожидалось, наибольшее ускорение достигается на 4 процессах для 4-ядерного процессора, ускорение малое | ||
| --- | ||
| ### Результаты при размере вектора \(10^9\) | ||
| | Режим выполнения | Число процессов | Время (сек) | Ускорение | Эффективность, % | | ||
| |:-----------------|-------------:|-----------------:|:-------------|-------------| | ||
| | SEQ | 1 | 91 | 1.00 | | | ||
| | MPI | 2 | 98 | 0.92 | 11,6 | | ||
| | MPI | 4 | 128 | 0.99 | 12,3 | | ||
| **Вывод:** на очень больших данных происходит замедление при использовании параллельной версии, что не оправдало ожидания (ожидалось, что при больших данных распараллеливание будет эффективнее). Возможно, это связано с ограниченностью кэшированной памяти, что усложняет распараллеливание на больших данных. | ||
| ## Подтверждение корректности | ||
| Были выбраны функциональные тесты на следующих входных данных, предполагающие различные сценарии работы алгоритмов: | ||
|
|
||
| 1. Малый вектор {3, 1, 4, 1, 5} | ||
| 2. Вектор с единстенным минимальным элементом в середине {9, 2, 6, 1, 8, 3, 7} | ||
| 3. Вектор со смешанными числами {5, 4, 3, 2, 1, 0, -1, -2} | ||
| 4. Вектор с повторяющимися отрицательными значениями {-5, -55, -5, -3, -100000, -111111, -9, -111111} | ||
| 5. Вектор из одного элемента {7} | ||
|
|
||
| Результаты последовательной и параллельной версий совпали со значением, возвращаемым стандартной функцией std::min_element, следовательно, оба алгоритма работают корректно. | ||
|
|
||
| --- | ||
| ## Выводы | ||
| 1. Реализованы последовательная (SEQ) и параллельная (MPI) версии алгоритма поиска минимального элемента в векторе. | ||
| 2. Тестовая инфраструктура обеспечивает комплексную проверку корректности обеих реализаций алгоритма с точки зрения функциональности и производительности при различных размерах тестовых данных. | ||
| 3. Предполагалось, что параллельная MPI-реализация эффективно распределяет вычисления между процессами, используя стратегию блочного распределения данных с учетом остатка для балансировки нагрузки. | ||
| Ожидания не оправдались, так как ускорение удалось получить небольшое и лишь при определённом размере входных данных (больше млн и меньше млр элементов). Вероятно, это связано с | ||
| накладными расходами на параллельные вычисленения и некоторыми техническими особенностями реализации параллельного алгоритма. Алгоритм может быть модернизирован для получения большего ускорения, так как в данный момент | ||
| использование параллельных вычислений не оправдывает затрат на его реализацию. | ||
| --- | ||
| ## Заключение. | ||
| В ходе лабораторной работы был реализован и протестирован алгоритм нахождения минимума вектора с использованием технологии MPI. Проведён сравнительный анализ с последовательной версией, подтверждена корректность вычислений и измерено ускорение. Было так же показано, что MPI версия при достаточно больших данных имеет ускорение по сравнению с версией SEQ. | ||
| --- | ||
| ## Список литературы | ||
| 1. Документация по OpenMPI — https://www.open-mpi.org/doc/ | ||
| 2. cppreference.com - https://en.cppreference.com/ | ||
| 3. Лекции по параллельному программированию ННГУ | ||
| --- | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
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,22 @@ | ||
| #pragma once | ||
|
|
||
| #include "savva_d_min_elem_vec/common/include/common.hpp" | ||
| #include "task/include/task.hpp" | ||
|
|
||
| namespace savva_d_min_elem_vec { | ||
|
|
||
| class SavvaDMinElemVecSEQ : public BaseTask { | ||
| public: | ||
| static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { | ||
| return ppc::task::TypeOfTask::kSEQ; | ||
| } | ||
| explicit SavvaDMinElemVecSEQ(const InType &in); | ||
|
|
||
| private: | ||
| bool ValidationImpl() override; | ||
| bool PreProcessingImpl() override; | ||
| bool RunImpl() override; | ||
| bool PostProcessingImpl() override; | ||
| }; | ||
|
|
||
| } // namespace savva_d_min_elem_vec |
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,43 @@ | ||
| #include "savva_d_min_elem_vec/seq/include/ops_seq.hpp" | ||
|
|
||
| #include <algorithm> | ||
| #include <cstddef> | ||
| #include <vector> | ||
|
|
||
| #include "savva_d_min_elem_vec/common/include/common.hpp" | ||
|
|
||
| namespace savva_d_min_elem_vec { | ||
|
|
||
| SavvaDMinElemVecSEQ::SavvaDMinElemVecSEQ(const InType &in) { | ||
| SetTypeOfTask(GetStaticTypeOfTask()); | ||
| GetInput() = in; | ||
| GetOutput() = 0; | ||
| } | ||
|
|
||
| bool SavvaDMinElemVecSEQ::ValidationImpl() { | ||
| return (!GetInput().empty()) && (GetOutput() == 0); | ||
| } | ||
|
|
||
| bool SavvaDMinElemVecSEQ::PreProcessingImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| bool SavvaDMinElemVecSEQ::RunImpl() { | ||
| if (GetInput().empty()) { | ||
| return false; | ||
| } | ||
|
|
||
| int min_val = GetInput()[0]; | ||
| for (size_t i = 1; i < GetInput().size(); ++i) { | ||
| min_val = std::min(GetInput()[i], min_val); | ||
| } | ||
| GetOutput() = min_val; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| bool SavvaDMinElemVecSEQ::PostProcessingImpl() { | ||
| return true; | ||
| } | ||
|
|
||
| } // namespace savva_d_min_elem_vec |
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.