Сравнить производительность NCCL ring и tree алгоритмов на разном масштабе GPU
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Сравнить производительность NCCL ring и tree алгоритмов на разном масштабе GPU
1. Цель задачи
Провести количественное сравнение алгоритмов коллективных коммуникаций NCCL (ring и tree) на бенчмарке allreduce для разного числа GPU (2–64) и размеров сообщений (256 Б – 256 МБ). Определить точку перехода, когда tree-алгоритм начинает превосходить ring по пропускной способности, и объяснить причину (топология, число узлов, латентность). Полученные знания позволят выбирать оптимальный алгоритм при конфигурации распределённого обучения на масштабе >32 GPU.
Ключевой результат Набор графиков и таблица с критическими значениями числа GPU и размера сообщения, при которых tree быстрее ring.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Кластер с GPU (минимум 2 GPU, желательно 4+ на узел, несколько узлов) | Собственный, арендованный (AWS p4d/p5, Lambda Cloud) или доступ к суперкомпьютеру |
| NVIDIA NCCL (установлен, версия ≥ 2.14) | apt install nvidia-nccl или из контейнера nvidia/cuda |
| nccl-tests (набор бенчмарков) | Git-репозиторий: https://github.com/NVIDIA/[nccl-tests](/wiki/nccl-tests) |
| MPI (mpiexec) для запуска на нескольких процессах | OpenMPI / MPICH, устанавливается системно |
| Python с matplotlib, numpy, pandas | окружение conda/pip |
| Документация NCCL | https://docs.nvidia.com/deeplearning/[nccl](/wiki/NCCL)/user-guide/ |
Если нет реального кластера с >8 GPU — симулируем:
- Запустить nccl-tests на доступном числе GPU (например, 2, 4, 8) на одной или двух нодах.
- Для масштабов 16, 32, 64 использовать открытые данные из бенчмарков NVIDIA (например, графики из NCCL user guide) или эмпирические формулы:
- Для ring:
bw = B * N_GPU / (2 * (N_GPU-1))(ограничение топологией узлов) - Для tree: bw = B * log(N_GPU) (бинарное дерево)
- Для ring:
- Сравнить измеренные и теоретические кривые, сделать вывод о точке пересечения.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Бенчмаркинг allreduce | nccl-tests (allreduce_perf) | Замер пропускной способности и латентности |
| Оркестрация процессов | OpenMPI (mpiexec) | Запуск нескольких рангов на разных GPU/узлах |
| Выбор алгоритма NCCL | Переменные окружения NCCL_ALGO=RING / TREE | Принудительная установка алгоритма |
| Сбор и анализ данных | Python (subprocess, re, pandas, matplotlib) | Парсинг вывода, построение графиков |
| Визуализация | Jupyter Notebook или Python-скрипт | Графики bandwidth vs #GPU, latency vs size |
| Опционально: профилирование | NVIDIA Nsight Systems (nsys) | Подробный трейс вызовов NCCL |
4. Этапы выполнения
Этап 1: Подготовка окружения и сборка nccl-tests (30 минут)
Действия
-
Установить зависимости (если не установлены):
sudo apt update && sudo apt install openmpi-bin openmpi-common libopenmpi-devПроверить наличие CUDA Toolkit и NCCL:
nvcc --version ldconfig -p | grep nccl -
Клонировать и собрать nccl-tests
git clone https://github.com/NVIDIA/nccl-tests.git cd nccl-tests makeБинарник
build/allreduce_perfбудет использоваться. -
Проверить топологию GPU (важно для понимания ограничений):
nvidia-smi topo -mЗаписать количество узлов и связи (NVLink, PCIe, межузловая сеть).
-
Подготовить скрипт для запуска (шаблон):
# examples/run_bench.sh #!/bin/bash ALGO=$1 # RING или TREE NGPU=$2 # общее число GPU NNODES=$3 # число узлов (для межузловых тестов) mpirun -np $NGPU -N 8 --host node1:8,node2:8 \ -x NCCL_ALGO=$ALGO \ -x NCCL_DEBUG=WARN \ build/allreduce_perf -b 256 -e 256M -f 2 -g 1 -n 100
Ожидаемый результат этапа Рабочий скрипт запуска, подтверждение, что allreduce_perf выполняется на 2 GPU без ошибок.
Этап 2: Проведение бенчмарков (1–1.5 часа)
Действия
-
Составить список конфигураций
-
Команда запуска (пример для 4 GPU на одном узле):
NCCL_ALGO=RING mpiexec -np 4 ./build/allreduce_perf -b 256 -e 256M -f 2 -n 100 -g 1Ключевые опции:
-b 256– начальный размер (Б)-e 256M– конечный размер (256 MБ)-f 2– множитель (каждый шаг ×2)-n 100– число итераций для прогрева/усреднения-g 1– одно сообщение на вызов
-
Собрать выводы в файлы
mkdir -p results for N in 2 4 8; do for algo in RING TREE; do NCCL_ALGO=$algo mpiexec -np $N ./build/allreduce_perf -b 256 -e 256M -f 2 -n 100 -g 1 \ | tee results/${algo}_${N}gpu.log done done -
Симуляция для 16, 32, 64 GPU (если нет реального доступа):
Ожидаемый результат этапа Директория results/ с лог-файлами для всех доступных конфигураций.
Этап 3: Парсинг результатов и анализ (45 минут)
Действия
-
Структура лога (фрагмент):
# out-of-place in-place # size count type redop time algbw busbw error time algbw busbw error # (B) (count) (us) (GB/s) (GB/s) (us) (GB/s) (GB/s) 256 64 float sum 100.0 8.00 0.03 0.03 0 7.00 0.03 0.03 0Нужные поля:
size, time (us), algbw (GB/s), busbw (GB/s). Используем busbw как метрику пропускной способности шины. -
Написать парсер на Python
import re, pandas as pd def parse_log(filepath): data = [] with open(filepath) as f: for line in f: if line.startswith('#'): continue parts = re.split(r'\s+', line.strip()) if len(parts) >= 8: size = int(parts[0]) time_us = float(parts[4]) busbw = float(parts[6]) if parts[6] != '-' else 0 data.append({'size': size, 'time_us': time_us, 'busbw': busbw}) return pd.DataFrame(data) -
Для симуляции на >8 GPU дополнить DataFrame расчётными данными:
-
Агрегировать данные Для каждого размера и алгоритма усреднить по трём запускам, построить таблицу.
Ожидаемый результат этапа Pandas DataFrame со столбцами: algo, ngpu, size, busbw_avg, time_avg.
Этап 4: Визуализация и выявление точки перехода (45 минут)
Действия
-
Построить график "bandwidth vs #GPU" для фиксированного размера сообщения (например, 1 МБ и 256 МБ):
import matplotlib.pyplot as plt # Пример для 1MB sizes_fixed = [1*1024*1024] for sz in sizes_fixed: df_sub = df_all[df_all['size'] == sz] fig, ax = plt.subplots(figsize=(10,6)) for algo in ['RING','TREE']: data = df_sub[df_sub['algo']==algo].sort_values('ngpu') ax.plot(data['ngpu'], data['busbw_avg'], marker='o', label=algo) ax.set_xlabel('Number of GPUs') ax.set_ylabel('Bus bandwidth (GB/s)') ax.legend() plt.title(f'Allreduce bandwidth vs #GPUs (size={sz} B)') plt.savefig(f'bw_vs_gpu_{sz}.png') -
Для каждого размера сообщения определить точку пересечения (когда tree впервые ≥ ring):
- Найти минимальное
ngpu, при которомtree_busbw > ring_busbw. - Свести в таблицу:
Size (B) N_threshold Примечание 256 32 латентность доминирует 1M 16 шина выравнивается
- Найти минимальное
-
Построить контурную карту "алгоритм против размера и числа GPU" (тепловая карта разницы
tree_busbw - ring_busbw). -
Сформулировать вывод
- Для мелких сообщений (< 256 КБ) ring чаще быстрее из-за меньшей латентности.
- Для крупных сообщений (> 4 МБ) tree выигрывает, начиная с 16–32 GPU, особенно при межузловой связке.
- Tree даёт преимущество, когда число GPU превышает ширину одного узла (например, 8 на DGX-1) и возникает необходимость в древовидной редукции по кольцу узлов.
Ожидаемый результат этапа 3–4 графика (bandwidth vs #GPU для 2–3 размеров; тепловая карта) и итоговая таблица с пороговыми значениями.
Этап 5: Оформление отчёта (20 минут)
Действия
- Подготовить Jupyter Notebook с кодом всех этапов, встроенными графиками и текстовыми выводами.
- Сохранить финальную таблицу результатов в CSV:
ncc_algorithm_crossover.csv. - Написать краткое заключение (1–2 абзаца): при каком масштабе какой алгоритм рекомендуется, с оговорками.
Ожидаемый результат этапа Завершённый notebook, CSV с данными.
5. Критерии приемки (Definition of Done)
- Все бенчмарки запущены минимум для 2, 4 и 8 GPU (или симулированы).
- Для каждого запуска собраны данные по размерам от 256 Б до 256 МБ.
- Парсер корректно извлекает
busbwиtime_usиз логов. - Построены минимум два графика:
bandwidth vs #GPUдля двух размеров сообщений. - Выявлена точка перехода (число GPU) для каждого размера сообщения.
- Таблица с порогами записана в CSV.
- Сформулирован вывод с объяснением (влияние топологии, размера сообщения).
- Код воспроизводим: указаны exact-команды и версии зависимостей в notebook.
6. Ожидаемый результат
Артефакты
analysis.ipynb— Jupyter Notebook с кодом, графиками и выводами.results/— папка с сырыми логами (если реальные запуски).ncc_algorithm_crossover.csv— таблица пороговых значений (size, N_threshold, preferred_algo).- (Опционально) PDF-отчёт.
Содержимое notebook
- Импорт библиотек, функции парсера.
- Построение графиков для всех доступных данных (с метками RING/TREE).
- Сравнение с теоретической моделью (если симулировали).
- Итоговая таблица точки перехода.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Нет доступа к кластеру с >8 GPU | Использовать измерения на 2–8 GPU + теоретические кривые из документации NCCL; загрузить публичные данные из NVIDIA Developer Blog. |
| Ошибки при запуске mpiexec (память, драйвер) | Убедиться, что все GPU видны (nvidia-smi), проверить CUDA_VISIBLE_DEVICES, использовать -x CUDA_VISIBLE_DEVICES=0,1,.... |
| Разброс результатов между запусками >10% | Увеличить число итераций (-n 1000), проверить загрузку системы (нет фоновых процессов). |
| Несовместимость MPI и NCCL | Использовать mpich вместо OpenMPI, или запускать без MPI через NCCL_ALGO с CUDA_VISIBLE_DEVICES и несколькими процессами на одной ноде. |
| Значения busbw равны 0 (ошибка в парсинге) | Проверить формат лога: иногда выводится - вместо чисел; использовать try/except, искать столбец Gbps. |
8. Бюджет времени (оценка)
| Этап | Время (часы) |
|---|---|
| Подготовка окружения и сборка nccl-tests | 0.5 |
| Проведение бенчмарков (2–8 GPU, 2 алгоритма) | 1.0 |
| Симуляция для >8 GPU (Python модель + сбор данных) | 1.0 |
| Парсинг, визуализация, анализ | 1.0 |
| Оформление отчёта | 0.5 |
| Итого | 3.5 – 4.0 |
Примечание: для первого выполнения (включая изучение документации) выделите 4 часа. Если кластер и окружение уже готовы, время сокращается до 2.5 часов.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 101 | Принципы работы коллективных операций (allreduce, allgather) |
| 205 | Топология GPU (NVLink, PCIe, межсоединения) |
| 307 | Профилирование NCCL с помощью Nsight Systems |
| 412 | Влияние размера сообщения на выбор алгоритма (ring vs tree vs other) |
| 528 | Многопоточная обработка allreduce с MPI+OpenMP |
| 634 | Пропускная способность InfiniBand и её влияние на tree |
| 711 | Переменные окружения NCCL: NCCL_ALGO, NCCL_PROTO, NCCL_IB_HCA |
| 825 | Сравнение производительности allreduce на одном узле (NVLink) и между узлами |
| 901 | Масштабирование распределённого обучения (DDP, FSDP) и роль коллективных коммуникаций |
10. Чек-лист самопроверки
- Я клонировал и собрал nccl-tests без ошибок.
- Я запустил тесты минимум для 2, 4, 8 GPU с обоими алгоритмами.
- Логи сохранены и парсятся корректно (busbw извлекается).
- Для масштабов >8 GPU я использовал симуляцию или публичные данные.
- Я построил график
bandwidth vs #GPUдля хотя бы одного размера сообщения. - Я определил точку перехода (количество GPU) для каждого размера.
- В выводе явно указано: при каком числе GPU и размере сообщения tree быстрее ring.
- Я сохранил notebook и CSV с результатами.
- Воспроизводимость обеспечена: указаны версии инструментов и команды запуска.