Научные вычисления

High-Performance Computing

Прогноз погоды на завтра требует 10^15 операций с плавающей точкой. На одном ядре это заняло бы 3 года. Суперкомпьютер делает это за 4 часа. Секрет - четыре уровня параллелизма: SIMD внутри ядра, OpenMP между ядрами, MPI между узлами, GPU для массивных вычислений.

  • **Прогноз погоды (ECMWF):** 10 000 MPI-процессов на суперкомпьютере Atos Sequana, модель с разрешением 9 км по всему земному шару
  • **Deep Learning (NVIDIA A100):** 6912 CUDA-ядра + Tensor Cores, 312 TFLOPS для матричных умножений в нейросетях
  • **Молекулярная динамика (GROMACS):** гибридный MPI+OpenMP+CUDA - один из самых оптимизированных научных пакетов
  • **NumPy / PyTorch:** автоматически используют AVX-512 SIMD для операций над тензорами

MPI: Message Passing Interface

Суперкомпьютер из 10 000 узлов - это не один гигантский компьютер, а 10 000 отдельных машин, каждая со своей памятью. Передать данные между ними можно только через сеть. **MPI (Message Passing Interface)** - стандарт для такой коммуникации: каждый процесс имеет уникальный ранг (rank), а данные передаются явными вызовами send/receive.

Ключевая идея: каждый процесс работает со своей копией программы и своим куском данных. Нет общей памяти - нет гонок данных. Синхронизация происходит только при явной передаче сообщений.

**Основные операции MPI:** `MPI_Send`/`MPI_Recv` (точка-точка), `MPI_Bcast` (рассылка всем), `MPI_Scatter`/`MPI_Gather` (раздать/собрать массив), `MPI_Reduce` (агрегация с операцией), `MPI_Barrier` (барьерная синхронизация).

В MPI-программе с 8 процессами вызывается MPI_Reduce(MPI_SUM). Сколько локальных значений суммируется?

OpenMP: параллелизм с shared memory

На одном многоядерном сервере - другая история: все ядра видят одну и ту же оперативную память. Передавать сообщения не нужно - можно просто разделить работу между потоками. **OpenMP** делает это через pragma-аннотации: компилятор сам создаёт пул потоков и распределяет итерации цикла.

**Hybrid MPI+OpenMP:** лучший подход для кластеров - один MPI-процесс на узел, OpenMP-потоки внутри узла. Так избегаем MPI-overhead внутри одного сервера и получаем масштабирование между узлами.

Зачем в OpenMP-цикле нужна клауза `reduction(+:sum)` вместо простого `sum += ...`?

GPU Computing: CUDA основы

CPU имеет 8-128 сложных ядер (глубокие конвейеры, branch prediction, большие кеши). GPU - тысячи простых: RTX 4090 содержит 16 384 CUDA-ядра. Каждое GPU-ядро простое (без branch prediction, малый кеш), но их тысячи работают одновременно. Это идеально для задач с **одной операцией над тысячами элементов** - матричные операции, физические симуляции, нейронные сети.

**GPU подходит:** матричные умножения, FFT, Monte Carlo, сверточные нейросети, MD-симуляции. **GPU не подходит:** задачи с сильными зависимостями данных, сложными ветвлениями, малыми массивами (overhead на transfer > выигрыш).

CUDA kernel запущен с конфигурацией `<<<256, 512>>>`. Сколько всего потоков создаётся?

Vectorization: SIMD инструкции

Даже внутри одного CPU-ядра есть скрытый параллелизм. **SIMD (Single Instruction, Multiple Data)** - специальные инструкции, которые применяют одну операцию сразу к нескольким числам. AVX-512 обрабатывает **16 float** за одну инструкцию. Цикл из 1000 итераций превращается в 63 инструкции вместо 1000.

**NumPy использует SIMD:** `np.dot(a, b)` - это не Python-цикл, а оптимизированный BLAS/LAPACK с AVX инструкциями. Именно поэтому NumPy быстрее ручных циклов в сотни раз.

Почему компилятор не может автоматически векторизовать цикл `for(i) a[i] = a[i-1] * 2`?

Четыре уровня параллелизма

  • **MPI:** параллелизм между узлами кластера - явная передача сообщений, нет shared memory, масштабируется до миллионов процессов
  • **OpenMP:** параллелизм между ядрами одного узла - pragma-аннотации, shared memory, нужно следить за race conditions
  • **CUDA:** тысячи простых GPU-потоков для data-parallel задач - данные на GPU, минимизируй PCIe transfer
  • **SIMD/Vectorization:** 4-16 чисел за одну инструкцию внутри ядра - автоматически компилятором или явно через intrinsics

Связанные темы

HPC-параллелизм строится на понимании архитектуры памяти и численных методов.

  • Параллельные паттерны и масштабирование — Как применять MPI и OpenMP в реальных задачах
  • Monte Carlo методы — Embarrassingly parallel задачи - идеальны для GPU и MPI
  • Численные методы: дифференциальные уравнения — PDE-решатели - основной use case для HPC

Вопросы для размышления

  • Почему для задачи симуляции молекулярной динамики лучше подойдёт GPU, а не только MPI-кластер?
  • Как hybrid MPI+OpenMP подход использует память эффективнее чем чистый MPI с одним процессом на ядро?
  • В каком случае автовекторизация компилятора не сработает и придётся переписывать цикл вручную?

Связанные уроки

  • par-01
High-Performance Computing

0

1

Войти