Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions tasks/egashin_k_radix_simple_merge/all/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Поразрядная сортировка double с простым слиянием - ALL

- Student: Егашин Кирилл Олегович, group 3823Б1ФИ2
- Technology: ALL
- Variant: 19

## 1. Введение

ALL-версия использует гибридную схему: MPI делит данные между рангами, а внутри каждого ранга блок
сортируется потоками OpenMP.

## 2. Постановка задачи

Нужно отсортировать общий входной `std::vector<double>` по возрастанию. После выполнения результат должен быть
одинаковым на всех рангах, чтобы общий тест мог проверить выход каждой задачи.

## 3. Базовый алгоритм

Внутри каждого локального блока применяется тот же radix sort по 64-битным ключам. После локальной сортировки
блоки собираются на ранге 0 и сливаются простым merge.

## 4. Межпроцессная схема

Каждый ранг получает свой диапазон индексов. В текущей тестовой инфраструктуре вход доступен каждому рангу,
поэтому ранг локально берет свой срез входного массива.

После локальной сортировки используется `MPI_Gatherv`, чтобы собрать отсортированные блоки на ранге 0. Ранг 0
выполняет простое слияние всех частей. Затем итоговый массив рассылается всем рангам через `MPI_Bcast`.

## 5. Внутрипроцессная схема

Внутри ранга локальный блок дополнительно делится на подблоки по `PPC_NUM_THREADS`. Подблоки сортируются
через `#pragma omp parallel for`, затем сливаются уровнями.

## 6. Детали реализации

Основные файлы:

- `common/include/radix_utils.hpp`
- `all/include/ops_all.hpp`
- `all/src/ops_all.cpp`

`ValidationImpl` проверяет, что размер входа помещается в `int`, потому что MPI counts и displacements
передаются как `int`.

## 7. Проверка корректности

ALL подключена к общим functional и performance tests. При обычном запуске без MPI functional runner
пропускает ALL-тесты. При запуске через `mpirun` результат проверяется на каждом ранге после `MPI_Bcast`.

## 8. Экспериментальная среда

Окружение замеров:

- OS: Ubuntu 24.04
- Compiler: `g++-14`
- Build type: `Release`
- Processes: `PPC_NUM_PROC=2`
- Threads per process: `PPC_NUM_THREADS=2`
- Metric: `task_run`

Команды:

```bash
cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Release
cmake --build build --parallel
PPC_NUM_THREADS=2 scripts/run_tests.py --running-type=processes --counts 1 2 4 --build-dir build
PPC_NUM_THREADS=2 PPC_NUM_PROC=2 scripts/run_tests.py --running-type=performance --build-dir build
```

## 9. Результаты

| Ранги | Потоки на ранг | Total workers | Time, s | Speedup vs seq | Efficiency |
| ----- | -------------- | ------------- | ------- | -------------- | ---------- |
| 2 | 2 | 4 | 0.030749 | 1.16 | 0.29 |

## 10. Вывод

Гибридная версия полезна для проверки процессного и потокового уровней параллелизма. Для малых размеров
ожидаются заметные накладные расходы на `MPI_Gatherv`, `MPI_Bcast` и финальное слияние на ранге 0.
78 changes: 78 additions & 0 deletions tasks/egashin_k_radix_simple_merge/omp/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Поразрядная сортировка double с простым слиянием - OMP

- Student: Егашин Кирилл Олегович, group 3823Б1ФИ2
- Technology: OMP
- Variant: 19

## 1. Введение

OMP-версия распараллеливает сортировку за счет разбиения входного массива на независимые блоки. Каждый блок
сортируется поразрядной сортировкой, затем блоки попарно сливаются.

## 2. Постановка задачи

Вход и выход совпадают с SEQ-версией: нужно получить отсортированный `std::vector<double>`. Корректность
проверяется сравнением с результатом `std::ranges::sort`.

## 3. Базовый алгоритм

Внутри каждого блока используется тот же radix sort, что и в последовательной версии: 8 проходов counting sort
по байтам 64-битного ключа.

## 4. Схема распараллеливания

Количество рабочих потоков берется из `PPC_NUM_THREADS`. Если элементов меньше, чем потоков, число потоков
уменьшается до размера массива.

Массив делится на почти равные диапазоны. Для сортировки блоков используется `#pragma omp parallel for` с
`schedule(static)`. Запись в `result_` безопасна, потому что каждый поток работает только со своим диапазоном.

После сортировки создаются отсортированные части. На каждом уровне merge пары частей сливаются параллельно.
Каждая пара записывает результат в отдельную ячейку `next`, поэтому `critical`, `atomic` и `reduction` не
нужны.

## 5. Детали реализации

Основные файлы:

- `common/include/radix_utils.hpp`
- `omp/include/ops_omp.hpp`
- `omp/src/ops_omp.cpp`

Общий helper содержит преобразование `double` в сортируемый ключ, counting pass, сортировку диапазона и
простое слияние двух отсортированных массивов.

## 6. Проверка корректности

Тесты подключают SEQ и OMP реализации к одному набору входов. Для OMP проверяются те же случаи, что и для SEQ:
пустой массив, один элемент, отрицательные числа, повторы и бесконечности.

## 7. Экспериментальная среда

Окружение замеров:

- OS: Ubuntu 24.04
- Compiler: `g++-14`
- Build type: `Release`
- Threads: `PPC_NUM_THREADS=2`
- Metric: `task_run`

Команды:

```bash
cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Release
cmake --build build --parallel
scripts/run_tests.py --running-type=threads --counts 1 2 4 --build-dir build
PPC_NUM_THREADS=2 PPC_NUM_PROC=2 scripts/run_tests.py --running-type=performance --build-dir build
```

## 8. Результаты

| Threads | Time, s | Speedup vs seq | Efficiency |
| ------- | ------- | -------------- | ---------- |
| 2 | 0.024104 | 1.48 | 0.74 |

## 9. Вывод

OMP-версия подходит для этой задачи, потому что сортировка блоков независима, а простое слияние можно
выполнять уровнями без общей записи в один результат.
117 changes: 117 additions & 0 deletions tasks/egashin_k_radix_simple_merge/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Поразрядная сортировка для вещественных чисел double с простым слиянием

- Student: Егашин Кирилл Олегович, group 3823Б1ФИ2
- Variant: 19
- Technology reports: `seq/report.md`, `omp/report.md`, `tbb/report.md`, `stl/report.md`, `all/report.md`

## 1. Введение

Работа сравнивает пять реализаций одной задачи: SEQ, OMP, TBB, STL и ALL. Задача хорошо подходит для сравнения
моделей параллелизма, потому что массив можно разделить на независимые части, отсортировать их отдельно и
затем объединить простым слиянием.

## 2. Постановка задачи

Вход: массив `std::vector<double>`.

Выход: отсортированный по возрастанию массив той же длины.

Критерий корректности: выход должен совпадать с результатом `std::ranges::sort` для тех же входных данных.

## 3. Единая методика

Для всех реализаций используется один базовый подход:

1. Преобразовать `double` в сортируемый 64-битный ключ.
2. Выполнить LSD radix sort по байтам ключа.
3. Для параллельных версий разделить вход на блоки.
4. Отсортировать блоки независимо.
5. Объединить отсортированные блоки простым merge.

SEQ сортирует весь массив одним блоком. OMP, TBB и STL сортируют блоки в потоках. ALL дополнительно делит
данные между MPI рангами и внутри каждого ранга использует OpenMP.

## 4. Сводка реализации

Основные файлы:

- `common/include/common.hpp`
- `common/include/radix_utils.hpp`
- `seq/src/ops_seq.cpp`
- `omp/src/ops_omp.cpp`
- `tbb/src/ops_tbb.cpp`
- `stl/src/ops_stl.cpp`
- `all/src/ops_all.cpp`
- `tests/functional/main.cpp`
- `tests/performance/main.cpp`

Общий helper `radix_utils.hpp` используется новыми параллельными версиями для сортировки диапазона и простого
слияния. SEQ оставлена без рефакторинга, чтобы не менять уже готовую базовую реализацию.

## 5. Корректность

Функциональные тесты покрывают:

- пустой массив
- один элемент
- уже отсортированный массив
- обратный порядок
- смешанные знаки
- повторы
- разные масштабы значений
- положительную и отрицательную бесконечность

Performance test проверяет, что результат отсортирован, через `std::ranges::is_sorted`.

## 6. Экспериментальная среда

Окружение замеров:

- OS: Ubuntu 24.04
- Compiler: `g++-14`
- Build type: `Release`
- Build system: CMake + Ninja
- Threads: `PPC_NUM_THREADS=2`
- Processes: `PPC_NUM_PROC=2`
- Metric: `task_run`

## 7. Команды воспроизведения

```bash
cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Release
cmake --build build --parallel
scripts/run_tests.py --running-type=threads --counts 1 2 4 --build-dir build
PPC_NUM_THREADS=2 scripts/run_tests.py --running-type=processes --counts 1 2 4 --build-dir build
PPC_NUM_THREADS=2 PPC_NUM_PROC=2 scripts/run_tests.py --running-type=performance --build-dir build
```

## 8. Агрегированные результаты

| Backend | Configuration | Time, s | Speedup vs seq | Efficiency |
| ------- | ------------------- | ------- | -------------- | ---------- |
| seq | 1 worker | 0.035714 | 1.00 | N/A |
| omp | 2 threads | 0.024104 | 1.48 | 0.74 |
| tbb | 2 workers | 0.023022 | 1.55 | 0.78 |
| stl | 2 threads | 0.024620 | 1.45 | 0.73 |
| all | 2 ранга, 2 потока | 0.030749 | 1.16 | 0.29 |

## 9. Интерпретация

SEQ задает baseline и проверочный результат.

OMP ожидаемо должен давать выигрыш на больших массивах, потому что сортировка блоков независима.

TBB использует ту же блочную схему, но планирование выполняет runtime TBB.

STL дает ручной контроль над потоками, но платит за создание и синхронизацию `std::thread`.

ALL добавляет процессный уровень. На больших входах это может помочь, но на малых входах коммуникации и
финальное слияние на ранге 0 могут перекрыть выигрыш.

## 10. Источники

1. Документация курса: `docs/common_information/report.rst`
2. Документация курса: `docs/common_information/threading_tasks.rst`
3. OpenMP specification: <https://www.openmp.org/specifications/>
4. oneTBB documentation: <https://uxlfoundation.github.io/oneTBB/>
5. MPI standard: <https://www.mpi-forum.org/docs/>
77 changes: 77 additions & 0 deletions tasks/egashin_k_radix_simple_merge/seq/report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Поразрядная сортировка double с простым слиянием - SEQ

- Student: Егашин Кирилл Олегович, group 3823Б1ФИ2
- Technology: SEQ
- Variant: 19

## 1. Введение

Задача состоит в сортировке массива чисел типа `double` по возрастанию. Последовательная версия используется
как эталон корректности для всех остальных реализаций.

## 2. Постановка задачи

Входные данные: `std::vector<double>`.

Выходные данные: отсортированный `std::vector<double>` той же длины.

Пустой массив и массив из одного элемента считаются корректными входами. В функциональных тестах проверяются
пустой массив, один элемент, уже отсортированные данные, обратный порядок, отрицательные числа, повторы,
разные масштабы и бесконечности.

## 3. Алгоритм

Каждое значение `double` преобразуется в 64-битный ключ. Для положительных чисел инвертируется знаковый бит,
для отрицательных инвертируются все биты. После такого преобразования обычный порядок ключей соответствует
порядку исходных чисел.

Далее выполняются 8 устойчивых проходов counting sort по одному байту. После последнего прохода ключи
преобразуются обратно в `double`.

Сложность по времени: `O(8 * (n + 256))`, то есть `O(n)`.

Сложность по памяти: `O(n)`.

## 4. Детали реализации

Основные файлы:

- `seq/include/ops_seq.hpp`
- `seq/src/ops_seq.cpp`

`PreProcessingImpl` копирует входные данные во внутренний буфер. `RunImpl` запускает radix sort.
`PostProcessingImpl` записывает результат в выход задачи.

## 5. Проверка корректности

Функциональные тесты строят ожидаемый результат через `std::ranges::sort` и сравнивают его с выходом задачи.
Тест производительности дополнительно проверяет инвариант `std::ranges::is_sorted`.

## 6. Экспериментальная среда

Окружение замеров:

- OS: Ubuntu 24.04
- Compiler: `g++-14`
- Build type: `Release`
- Threads: `PPC_NUM_THREADS=2`
- Metric: `task_run`

Команды:

```bash
cmake -S . -B build -G Ninja -D CMAKE_BUILD_TYPE=Release
cmake --build build --parallel
scripts/run_tests.py --running-type=threads --counts 1 2 4 --build-dir build
PPC_NUM_THREADS=2 PPC_NUM_PROC=2 scripts/run_tests.py --running-type=performance --build-dir build
```

## 7. Результаты

| Backend | Workers | Time, s |
| ------- | ------- | ------- |
| seq | 1 | 0.035714 |

## 8. Вывод

SEQ-версия задает базовый корректный результат и baseline для расчета ускорения в OMP, TBB, STL и ALL.
Loading
Loading