Содержание
1 Введение
Данная страница является руководством по использованию кластера «Ангара-К1».
В руководстве приводится краткое описание поддерживаемых моделей программирования,
инфраструктуры запуска и отслеживания выполнения задач.
2 Быстрый старт
- Используя выданное вам при регистрации имя пользователя (user), вы можете подключиться к
управляющему узлу. Для доступа используйте адрес angara-k1.nicevt.ru
- Скомпилируйте свою программу
- Запустите задачу с помощью менеджера управления ресурсами Slurm
- Примеры команд:
Подключение к управляющему узлу (инструкция для подлючения пользователей Windows c помощью клиента PuTTY):
[localuser@localhost ~]$ ssh user@angara-k1.nicevt.ru
Компиляция программы (С++):
[user@head ~]$ mpicxx ./my_program.cpp -o my_program
Запуск задачи:
[user@head ~]$ srun -N 2 ./my_program
В данном случае задача запустится на двух узлах при наличии свободных.
3 Кластер «Ангара-К1»
3.1 Общее описание
Кластер состоит из 36 узлов, соединённых сетью Ангара с адаптерами на базе СБИС ЕС8430.
Топология сети — 4D-тор размерности
. Пары узлов по
направлению соединены одним
линком, по направлению
— двумя линками.
Головной узел — head, сборка и запуск программ должны осуществляться только с него.
Используются вычислительные узлы двух типов:
- А-узлы (24 шт.):
- сервер Supermicro X9DRW-3LN4F+/X9DRW-3TF+ (BIOS rev. 1.0);
- 2 процессора Intel Xeon CPU E5-2630 @ 2.30GHz по 6 ядер (всего 12 ядер);
- Операционная система: SLES 11 SP4 (kernel 3.0.101-63-default x86_64);
- Память 64 ГБ ;
- В-узлы (12 шт.):
- сервер Supermicro X9SRG-F (BIOS rev. 1.0);
- 1 процессор Intel Xeon CPU E5-2660 @ 2.20GHz (8 ядер);
- Операционная система SLES 11 SP4 (kernel 3.0.101-63-default x86_64);
- Память 64 ГБ.
На данный момент на всех процессорах кластера включен режим Hyper-Threading, режим Turbo Boost
выключен.
Для системы запуска SLURM на кластере «Ангара-К1» доступны следующие разделы: A (только
A-узлы), B (только B-узлы), all (все узлы кластера).
На кластере установлены:
- Intel C++ Composer XE 2013 (compiler 13.0), в состав которого входят компиляторы языков
C/C++ и Fortran, библиотека MKL;
- MPICH 3.0.4 (используется по умолчанию);
- MPICH 3.0.4 оптимизированный, бета версия.
4 Поддерживаемые модели программирования
Можно использовать следующие средства параллельного программирования:
- MPI — библиотека MPI, поддерживается версия стандарта 3.0;
- SHMEM — библиотека SHMEM, поддерживается версия стандарта OpenShmem 1.0;
- OpenMP — технология OpenMP, поддерживается версия стандарта 3.1.
4.1 Особенности реализации библиотеки MPI
Библиотека MPI для сети Ангара базируется на MPICH 3.0.4 (реализация стандарта MPI-3).
4.2 MPI+SHMEM
Необходимо явно вызывать как функции MPI_Init с MPI_Finalize, так и shmem_init с shmem_finalize,
причём функция MPI_Init должна предшествовать функции shmem_init, а функция MPI_Finalize
должна вызываться после функции shmem_finalize.
Пример правильного порядка вызова MPI и SHMEM функций при инициализации MPI и SHMEM в
одном процессе:
#include <mpi.h>
#include <shmem.h>
int main() {
/* ... */
MPI_Init(...);
/* ... */
shmem_init();
/* ... */
shmem_finalize();
/* ... */
MPI_Finalize();
/* ... */
}
4.3 Потоки в SHMEM
Базовое понятие SHMEM — PE (processing element). В нашем случае PE — это процесс вместе с
выделенным регионом памяти (GA-память), доступным для удалённой записи/чтения.
Все потоки одного PE выполняют SHMEM-операции от имени этого PE. Синхронизация и
логика работы потоков одного PE определяются целиком и полностью лишь пользователем
SHMEM.
Все вызовы SHMEM по отношению к thread safety делятся на 3 категории:
- Доступ к ресурсам SHMEM только на чтение (RO-shmem): информационные вызовы вроде
my_pe(), num_pes(); операции записи и чтения с локальной частью GA-памяти.
- Доступ к ресурсам SHMEM для чтения и записи (RW-shmem): операции с удалёнными
частями GA-памяти (put, get, add, bcast,...).
- Специальные функции SHMEM с синхронизацией между PE (Sync-shmem): init, finalize;
barrier; reduce; shmalloc; quiet, fence.
Вызов Sync-shmem функций любым из потоков процесса является вызовом от имени PE, никакой
неявной синхронизации между потоками в SHMEM нет, никакого различия при посылке пакетов между
разными потоками одного процесса (PE) не делается. Порядок SHMEM-операций выдаваемых разными
потоками без явной синхронизации недетерминирован.
PE выходит на барьер, как только любой из его потоков вызывает shmem_barrier; последующий
вызов shmem_barrier другим потоком будет означать выход на следующий барьер (после чего будут
ожидаться симметричные вызовы на других PE).
Библиотека SHMEM предполагает возможность поддержки одного/нескольких из следующих
режимов работы с потоками:
- SHMEM_THREAD_SINGLE — будет выполняться только один поток;
- SHMEM_THREAD_FUNNELED — процесс может быть многопоточным, однако программа
должна гарантировать, что только основной поток будет выполнять RW-, Sync-shmem
вызовы;
- SHMEM_THREAD_SERIALIZED — процесс может быть многопоточным, однако программа
должна гарантировать, что только один поток будет выполнять RW-, Sync-shmem вызовы в
каждый момент времени (т.е. все RW-, Sync-shmem вызовы должны быть сериализованы);
- SHMEM_THREAD_MULTIPLE — процесс может быть многопоточным, все потоки могут
выполнять RW-, Sync-shmem вызовы без ограничений (при этом Sync-shmem вызовы от
каждого потока будут выполняться от имени PE).
Для организации работы с потоками в SHMEM добавлены следующие функции:
- shmem_init_thread — вызов для инициализации SHMEM (вместо shmem_init) с
возможностью указать режим работы с потоками;
- shmem_thread_started, shmem_thread_exited
— вызовы для начала и завершения работы потока с RW-, Sync-shmem (могут быть вызваны
только после shmem_init/shmem_init_thread);
- shmem_get_max_nthreads — возвращает максимальное поддерживаемое число потоков.
4.3.1 SHMEM+pthreads
Основная модель программирования при использовании pthreads вместе с SHMEM: в основном потоке
вызвать shmem_init() либо shmem_init_thread() в начале и shmem_finalize() в конце, затем в остальных
потоках, которые будут выполнять RW-, Sync-shmem вызовы, вызвать в начале shmem_thread_started()
и shmem_thread_exited() в конце.
Пример правильного порядка вызова SHMEM функций при использовании pthreads:
void* thread_func(void *argv) {
shmem_thread_started();
/* ... */
shmem_thread_exited();
}
int main() {
shmem_init();
/* ... */
for (i = 0; i < ...) {
pthread_create(..., thread_func, ...);
}
/* ... */
shmem_finalize();
}
4.3.2 SHMEM+OpenMP
Основная модель программирования при использовании OpenMP вместе с SHMEM: в головном потоке
вызвать shmem_init() либо shmem_init_thread() в начале и shmem_finalize() в конце, в остальных
потоках не вызывать специальных функций.
Функция shmem_is_omp_supported() используется для проверки, что текущая версия SHMEM
поддерживает OpenMP.
int main() {
shmem_init();
/* ... */
if (!shmem_is_omp_supported()) {
printf("This version of SHMEM doesn’t support OpenMP!\n");
abort();
}
# pragma omp parallel
{
/* SHMEM here */
}
/* ... */
shmem_finalize();
}
4.4 Потоки в MPI
Для безопасной работы с потоками в MPI есть специальный вызов MPI_Init_thread, заменяющий
MPI_Init и инициализирующий среду для работы с потоками:
int MPI_Init_thread(int *argc, char ***argv, int required, int *provided);
Аргумент required используется для задания требуемого уровеня поддержки потоков. Допустимы
следующие значения:
- MPI_THREAD_SINGLE — будет выполняться только один поток;
- MPI_THREAD_FUNNELED — процесс может быть многопоточным, однако программа
должна гарантировать, что только основной поток будет выполнять MPI-вызовы;
- MPI_THREAD_SERIALIZED — процесс может быть многопоточным, однако программа
должна гарантировать, что только один поток будет выполнять MPI-вызовы в каждый
момент времени (т.е. все MPI-вызовы должны быть сериализованы);
- MPI_THREAD_MULTIPLE — процесс может быть многопоточным, все потоки могут
выполнять MPI-вызовы без ограничений.
Различные процессы задачи могут требовать различных уровней поддержки потоков.
Вызвращаемое значение provided содержит информацию об уровне поддержки потоков, который будет
фактически обеспечен MPI (одно из четырёх перечисленных выше значений). Это значение может
зависеть от особенностей реализации (конфигурации) MPI, а также от переменных окуржения,
выставленных перед запуском задачи.
В случае успеха, будет возвращено значение provided
required, иначе — максимальный доступный уровень поддержки потоков.
Более подробную информацию см. в спецификации MPI.
Функции MPI_Init (MPI_Init_thread) и MPI_Finalize должны вызываться в одном и том же
потоке.
5 Компиляция программ
- MPI Для компиляции программ на MPI (без SHMEM) используются стандартные
компиляторы mpicc, mpicxx, mpif77, mpif90. Следует подключить заголовочный файл mpi.h.
mpicc -O3 -o myprog mpiprog.c
- SHMEM Программы на SHMEM (без MPI) компилируются с помощью acc, acxx. Следует
подключить заголовочный файл shmem.h.
acc -O3 -o myprog shmemprog.c
acxx -o /opt/angara/bin/myprog shmemprog.cpp
- MPI+SHMEM Программы, в которых совместно используются функции MPI и SHMEM,
компилируются с использованием shmemcc, shmemcxx. Следует подключить заголовочные файлы
mpi.h и shmem.h.
shmemcc -O3 -o myprog shmemmpiprog.c
5.1 Опции для MPI
Переменные окружения, которые могут пригодиться при использовании MPI для сети Ангара
(AMFCH):
- Выбор сети:
- MPICH_NEMESIS_NETMOD=angara (сеть Ангара, по умолчанию);
- MPICH_NEMESIS_NETMOD=tcp (сеть Ethernet).
- Вывод информации о параметрах сборки и переменных окружения для AMFCH:
AMFCH_PRINT_PARAMS=1.
- Выключить передачу больших сообщений по протоколу Rendezvous (если MPICH собран с
поддержкой этого протокола, в противном случае выдается warning):
AMFCH_LMT_IS_ENABLED=0.
- Задать размер пакета, начиная с которого будет использоваться протокол Rendezvous:
MPICH_CH3_EAGER_MAX_MSG_SIZE=N,
где N — это размер пакета в байтах (значение по умолчанию — 131072). Также есть внутренняя
переменная AMFCH_EAGER_LIMIT=N, которая используется при отладке.
- Использовать сеть для коммуникаций между процессами одного узла:
MPICH_NO_LOCAL=1.
5.1.1 Сбор статистики
Данный раздел посвящён средствам сбора статистики для сети Ангара при выполнении MPI-пересылок.
Собственные средства MPI здесь не рассматриваются.
Общая информация
На текущий момент поддерживается сбор следующих статистических данных:
- количество осуществлённых данным MPI-процессом передач (для больших сообщений один
MPI-вызов может соответствовать нескольким передачам);
- суммарное количество переданных данным MPI-процессом 64-битных слов, включая
MPI-заголовок, собственно полезные данные и накладные расходы на выравнивание данных
по границе 64-битных слов.
Собранные статистические данные могут быть отображены в следующих формах:
- исходные данные для построения графа пересылок для пакета Graphviz: вершины
графа — MPI-процессы, толщина дуг указывает интенсивность пересылок; интенсивность
задаётся числом от 0 до 10, где 10 соотвествует максимальному числу слов, переданных между
какой-либо парой MPI-процессов за данный период сбора статистики;
- набор таблиц: по одной таблице для каждого MPI-процесса, в строках — данные для
каждого возможного адресата;
- матрица паттерна инжекции: элементы матрицы — количество переданных 64-битных
слов между источником и адресатам, строки — источники, столбцы — адресаты; числа
разделены пробелами, данную форму отображения удобно использовать для построения heat
map.
Пример вывода данных для построения графа пересылок:
digraph {
node [shape=circle,fixedsize=true,width=1];
overlap=false;
splines=true;
A0 [label="A0"];
A1 [label="A1"];
A0 -> A1 [penwidth=10.000];
A1 -> A0 [penwidth=0.468];
}
Пример вывода набора таблиц:
rank = 0
| dest | avg_msg,w | msg_cnt | data_total,w |
| 0 | 0.00 | 0 | 0 |
| 1 | 2009.74 | 1685 | 3386419 |
rank = 1
| dest | avg_msg,w | msg_cnt | data_total,w |
| 0 | 1570.75 | 101 | 158646 |
| 1 | 0.00 | 0 | 0 |
Пример вывода паттерна инжекции:
Injection pattern (rows - sources; columns - destinations; values - 64-bit words sent):
0 3386419
158646 0
Включение сбора статистики и управление выводом
Сбор статистики возможен, если при сборке AMFCH (администратором кластера) был определён
макрос AMFCH_ENABLE_STATISTICS=1. Пользователю доступна функция amfch_statistics_is_enabled,
которая возвращает 1, если сбор статистики поддерживается данной версией MPI, и 0 в противном
случае.
Форма отображения собранных данных задаётся переменной окружения AMFCH_STATISTICS_PRINT_MODE
путём выставления соответствующих битов маски: бит 0 — вывод данных для построения графа
пересылок, бит 1 — вывод набора таблиц, бит 2 — вывод паттерна инжекции. Например,
AMFCH_STATISTICS_PRINT_MODE=7 задаёт одновременный вывод всех трёх форм отображения. По
умолчанию происходит вывод только паттерна инжекции.
Функции для работы со статистикой
По умолчанию (при сборке с AMFCH_ENABLE_STATISTICS=1) статистика начинает собираться
автоматически сразу после вызова MPI_Init(), а результаты выводятся при вызове функции
MPI_Finalize().
Программисту также доступен набор функций для работы со статистикой:
- int amfch_statistics_is_enabled(void) — возвращает 1, если текущая сборка MPI
поддерживает сбор статистики;
- void amfch_statistics_start(void) — начало сбора статистики (после вызова MPI_Init()
статистика собирается автоматически);
- void amfch_statistics_stop(void) — конец сбора статистики (amfch автоматически
перестает вести сбор статистики при вызове функции MPI_Finalize());
- void amfch_statistics_reset(void) — обнуление текущих значений счетчиков;
- void amfch_statistics_output(void) — вывести на экран значения счетчиков в выбранном
формате (во время вызова функции MPI_Finalize() значения выводятся автоматически).
Прототипы данных функций находятся в amfch.h.
5.2 Запуск программ с использованием SLURM
Ниже приведена краткая справочная информация по основным командам SLURM; более подробная
информация доступна в man к соответствующей команде.
Для запуска задач в системе SLURM пользователю доступны следующие команды:
- srun — запуск задачи в интерактивном режиме;
- sbatch — запуск задачи в пакетном режиме;
- scancel — отмена запущенной задачи, удаление задачи из очереди;
- sinfo — вывод информации о состоянии задач, разделов и узлов, управляемых SLURM;
- squeue — просмотр информации о задачах, которые поставлены в очередь планирования
SLURM;
- smap — графический вывод информации о состоянии задач, разделов и узлов, управляемых
SLURM.
5.2.1 Команда srun
Команда srun позволяет запускать задачи в интерактивном режиме; формат команды: srun [OPTIONS]
PROG [ARGS].
Основные опции:
- -N, --nodes=<number> — количество узлов, на которых будет запущена задача;
- --ntasks-per-node=<number> требует, чтобы для данной задачи на каждом узле было
запущено number процессов;
- --threads-per-core=<number> — на каждом ядре будет использоваться number
аппаратных потоков;
- --cpu_bind=threads — каждый процесс будет привязан к одному аппаратному потоку;
- -w, --nodelist=<host1,host2,... or filename> позволяет задать узлы, которые должны
присутствовать в списке узлов, на которых будет запущена задача;
- -p, --partition=<partition names> позволяет задать раздел, в рамках которой задаче
будут выделены узлы.
Таким образом, при выполнении команды srun -N2 --ntasks-per-node=4 tt программа tt будет
запущена на двух узлах по четыре процесса на каждом.
5.2.2 Команда sbatch
Команда sbatch позволяет запускать задачи в пакетном режиме; формат команды: sbatch [OPTIONS]
SCRIPT [ARGS].
Основные опции:
- -N, --nodes=<number> — количество узлов, на которых будет запущена задача;
- --ntasks-per-node=<number> требует, чтобы для данной задачи на каждом узле было
запущено number процессов;
- --threads-per-core=<number> — на каждом ядре будет использоваться number
аппаратных потоков;
- -w, --nodelist=<host1,host2,... or filename> позволяет задать узлы, которые должны
присутствовать в списке узлов, на которых будет запущена задача;
- -p, --partition=<partition names> позволяет задать раздел, в рамках которой задаче
будут выделены узлы;
- --wrap=<command string> — sbatch сделает из command string shell скрипт и поставит его
в очередь (если используется данная опция, то в командной строке имя скрипта и аргументы
указывать не нужно);
- -o, --output=<filename pattern> — перенаправление стандартного вывода в файл с
именем filename pattern; по умолчанию поток стандартного вывода и поток ошибок
направлены в один файл; если имя файла не задано, то вывод будет сохраняться в файл
slurm-%j.out, где %j будет заменён на ID задачи.
Скрипт запускается на первом из выделенных узлов. Запуск нескольких процессов осуществляется
командой srun. При этом все опции, указанные в командной строке или самом скрипте в строках
#SBATCH, приписываются к каждой команде srun данного скрипта, если не переопределены в
ней.
$ cat myscript
#!/bin/sh
#SBATCH --ntasks-per-node=4
srun tt
$ sbatch -N2 myscript
При выполнении данной последовательности команд, программа tt будет запущена на двух узлах по
четыре процесса на каждом. Выполнение команды sbatch -N2 --ntasks-per-node=4 --wrap "srun tt"
приведет к аналогичным результатам.
5.2.3 Особенности, ограничения, рекомендации
Текущие ограничения:
- количество процессов на каждом узле в задаче должно быть одинаковым;
- при написании скрипта sbatch для запуска задачи необходимо использовать команду srun
и при этом только одну.
Текущие особенности выделения узлов:
- узлы выделяются задаче эксклюзивно (т. е. на каждом узле будут выполняться процессы
только одной задачи);
- узлы выделяются в соответствии с топологией сети, по возможности выбирается связное
множество с минимальным диаметром;
- узлы выделяются так, чтобы сетевой трафик одной задачи никак не пересекался с трафиком
других задач; при необходимости резервируются транзитные узлы (например, для тора
при выделении 32-х узлов будут зарезервированы дополнительно 4 узла, чтобы весь трафик
задачи был локализован внутри выделенного множества);
- при запуске задач из очереди обычно используется политика priority/basic — "first arrived
first served"(«первым пришёл, первым обслужен»). Текущие настройки можно посмотреть
с помощью команды ‘scontrol show config | grep PriorityType‘. В выводе комманды
squeue для каждой ожидающей запуска задачи указана причина (REASON), почему задача
ещё не запущена. Две наиболее частые причины: Resources — в данный момент нет
достаточного количества узлов требуемого типа; Priority — свободные узлы есть, однако
задача будет запущена только после того, как все ранее поставленные в очередь задачи (с
меньшими JobID) будут запущены.
6 Рекомендации для получения максимальной производительности
- Для увеличения производительности рекомендуется использовать опции SLURM для привязки
процессов к ядрам и распределения процессов по сокетам.
- Для А-узлов при запуске более 6 процессов на узле рекомендуется распределять
процессы равномерно по сокетам, а для ядер использовать только один аппаратный
поток из двух доступных в режиме Hyper Threading. Также необходимо привязывать
процессы к аппаратным потокам ядер. Для этого можно использовать опции SLURM
--ntasks-per-node, --threads-per-core, --cpu_bind.
srun -N 16 --ntasks-per-node=8 --ntasks-per-socket=4
--threads-per-core=1 --cpu_bind=threads tt
В данном примере будет использоваться рекомендуемое равномерное распределение процессов
по сокетам (в slurm задано по умолчанию).
- В режиме использования библиотеки MPI в сочетании с технологией OpenMP рекомендуется
дополнительно ко всем вышеупомянутым опциям SLURM использовать опцию
--cpus-per-task=<omp_num_threads> — на каждый MPI-процесс выделить omp_num_threads
виртуальных процессоров (в контексте предыдущих опций — ядер), где omp_num_threads —
необходимое количество OpenMP-потоков.
- Так как в кластере присутствуют узлы с разными характеристиками, при выполнении задачи
на всех вычислительных узлах рекомендуется использовать не больше 8 процессов на
узел.