Пример запуска HPL-NVIDIA

В этом примере мы запустим модифицированный тест Linpack от NVIDIA для оценки производительности графических ускорителей.

Установка HPL-NVIDIA

Один из самых простых способов запустить HPL-NVIDIA – воспользоваться готовым контейнером hpc-benchmarks с сайта NVIDIA. На кластере для работы с контейнерами используется пакет Singularity, он доступен в системе загрузки модулей. Для загрузки контейнера hpc-benchmarks нужно зарегистрироваться на сайте NVIDIA NGC и получить API key.

# загружаем модуль singularity
module load singularity
# скачиваем образ Docker-контейнера и конвертируем в образ Singularity
singularity pull --docker-login hpc-benchmarks:21.4-hpl.sif \
    docker://nvcr.io/nvidia/hpc-benchmarks:21.4-hpl
# для скачивания потребуется API key

Образ hpc-benchmarks будет сохранён в текущей директории в файле hpc-benchmarks:21.4-hpl.sif.

Запуск HPL-NVIDIA

Запустим расчёт с использованием 4 графических ускорителей Nvidia Tesla V100S. Подготовим файл конфигурации HPL-4xV100.dat и скрипт для очереди задач hpl-nvidia-4-v100.sh.

HPL-4xV100.dat
 1HPLinpack benchmark input file
 2Innovative Computing Laboratory, University of Tennessee
 3HPL.out      output file name (if any)
 46            device out (6=stdout,7=stderr,file)
 51            # of problems sizes (N)
 6130560       Ns
 71            # of NBs
 8384          NBs
 90            PMAP process mapping (0=Row-,1=Column-major)
101            # of process grids (P x Q)
112            Ps
122            Qs
1316.0         threshold
141            # of panel fact
151            PFACTs (0=left, 1=Crout, 2=Right)
161            # of recursive stopping criterium
174            NBMINs (>= 1)
181            # of panels in recursion
192            NDIVs
201            # of recursive panel fact.
211            RFACTs (0=left, 1=Crout, 2=Right)
221            # of broadcast
233            BCASTs (0=1rg,1=1rM,2=2rg,3=2rM,4=Lng,5=LnM)
241            # of lookahead depth
251            DEPTHs (>=0)
261            SWAP (0=bin-exch,1=long,2=mix)
27192          swapping threshold
281            L1 in (0=transposed,1=no-transposed) form
290            U  in (0=transposed,1=no-transposed) form
300            Equilibration (0=no,1=yes)
318            memory alignment in double (> 0)

В этом примере файла HPL.dat мы указываем размер системы в строке 6. Размер N=130560 подобран из соображений максимального использования GPU памяти. 4 карты по 32 Гб памяти в сумме дают 128 Гб памяти, что позволяет хранить плотную матрицу 131072×131072 чисел с плавающей точкой с двойной точностью. Мы немного уменьшим значение N, чтобы оно стало кратным параметру NB=384. Разбиение системы на блоки указывается в строках 11-12. Произведение P×Q должно совпадать с количеством используемых графических ускорителей.

hpl-nvidia-4-v100.sh
 1#!/bin/bash
 2#SBATCH --job-name=hpl-nvidia-4-v100    # название задачи
 3#SBATCH --partition=gpu                 # очередь gpu
 4#SBATCH --gpus=v100:4                   # 4 ускорителя v100
 5#SBATCH --nodes=1                       # 1 вычислительный узел
 6#SBATCH --ntasks-per-node=4             # 4 процесса на один узел
 7#SBATCH --cpus-per-task=6               # 6 ядер на один процесс
 8#SBATCH --time=0:10:00                  # оценка времени 10 минут
 9
10# загружаем модуль singularity для контейнера
11module load singularity
12# предполагается, что контейнер hpc-benchmarks:21.4-hpl.sif
13# находится в текущей директории
14srun --mpi=pmi2  singularity run --nv \
15    ./hpc-benchmarks:21.4-hpl.sif hpl.sh \
16    --cpu-affinity all:all:all:all \
17    --cpu-cores-per-rank $SLURM_CPUS_PER_TASK \
18    --gpu-affinity 0:1:2:3 \
19    --dat HPL-4xV100.dat

В скрипте указываются параметры задачи: в строке 2 – название задачи, в строке 3 – название очереди gpu для серверов с графическими ускорителями, в строке 4 – необходимое количество и тип графических ускорителей, в строке 5 – количество GPU-узлов (в данном случае этот параметр можно опустить), в строке 6 – количество процессов на одном сервере (можно также просто указать --ntasks=4), в строке 7 – количество CPU ядер на один процесс, в строке 8 – максимальное время выполнения задачи. В строке 11 загружается модуль singularity для работы с контейнерами Singularity. В строках 14-19 запускается параллельный расчёт задачи: в строке 14 программа srun запускает 4 процесса singularity, параметр --nv у singularity предоставляет контейнеру доступ к графическим ускорителям, в строке 15 указано название контейнера ./hpc-benchmarks:21.4-hpl.sif и запускаемый скрипт внутри контейнера hpl.sh, в строке 16 указывается привязка процессов к ядрам CPU, мы указываем ключевое слово all, чтобы использовать привязку Slurm, в строке 17 указывается количество ядер на один процесс, мы указываем значение $SLURM_CPUS_PER_TASK, которое совпадает с параметром --cpus-per-task, в строке 18 указывается привязка GPU-карт к процессам, в строке 19 указывается имя файла с параметрами HPL.dat.

Для запуска задачи в системе очередей используется команда sbatch:

sbatch hpl-nvidia-4-v100.sh

Результаты расчёта будут сохранены в файле slurm-XXX.out, где XXX – номер задачи. Время расчёта с указанными параметрами обычно составляет несколько минут. Сводную таблицу с временем работы и оценкой скорости вычислений можно получить с помощью следующей команды:

# вместо XXX нужно указать номер задачи, или использовать *
grep -B2 WR slurm-XXX.out
# пример вывода:
# T/V                N    NB     P     Q               Time                 Gflops
# --------------------------------------------------------------------------------
# WR03C2C4      130560   384     2     2              61.55              2.411e+04

В результате получена производительность R_max = 24110 Gflops.

В примере выше мы использовали не все доступные ядра на узле g01. Наш выбор обусловлен особенностями подключения GPU-карт к материнской плате. На узле g01 установлены 4 карты Nvidia Tesla V100S, и все они подключены к PCI-шине первого процессора. Такое подключение позволяет ускорить обмены между GPU-картами через общую PCI-шину. С другой стороны, обмены между вторым процессором и GPU-картами происходят медленнее. При использовании 6 ядер на одну GPU-карту нам достаточно 24 ядер, и они все могут быть размещены на первом процессоре.

Попытка добавить больше ядер приведёт лишь к снижению производительности из-за дополнительных накладных расходов при обменах между вторым процессором и GPU-картами:

# увеличиваем количество ядер на процесс в два раза
sbatch --cpus-per-task=12 hpl-nvidia-4-v100.sh
grep -B2 WR slurm-XXX.out
# пример вывода:
# T/V                N    NB     P     Q               Time                 Gflops
# --------------------------------------------------------------------------------
# WR03C2C4      130560   384     2     2              87.42              1.697e+04

В результате подключения к работе второго процессора производительность уменьшилась до R = 16970 Gflops.

Система очередей Slurm автоматически выбирает свободные ядра первого процессора при запросе графических ускорителей V100 на узле g01.