Планировщик задач Altair PBS Pro

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

Программы, выполняемые на комплексе, не запускаются пользователями сразу на выполнение - вместо этого они помещаются в очередь ожидающих задач. Для этого используется команда qsub из пакета PBS, которой в качестве параметра передается скрипт на языке bash, содержащий всю необходимую информацию - какую программу надо запустить и какие ресурсы ей потребуются (количество процессов, оперативной памяти, максимальное время работы, …).

Проверив скрипт и поместив его в очередь, qsub выводит на экран строку вида «XXXXX.hpc-suvir.hpc», где XXXXX - некое число, являющееся уникальным идентификатором задачи.

Посмотреть статус задачи в очереди можно при помощи команды qstat, в качестве параметра которой опционально можно указать идентификатор интересующей задачи. Удалить свою задачу из очереди можно командой qdel с идентификатором в качестве параметра.

Работающий на сервере планировщик задач контролирует текущее состояние комплекса и при наличии необходимых свободных ресурсов запускает очередной скрипт из очереди. Скрипт запускается только на одном из узлов (называемом 'Mother Superior'), задача распараллеливания возлагается на пользователя и его программу. (В свою очередь, использование в программе стандартов MPI или OpenMP позволяет данную задачу облегчить). Имена узлов, выделенных задаче, и ряд других дополнительных параметров передаются скрипту через переменные окружения.

После завершения скрипта его стандартные потоки вывода и ошибок (stdout и stderr) сохраняются в той же директории в файлы с названиями вида «НазваниеСкрипта.oXXXXX» и «НазваниеСкрипта.еXXXXX» соответственно. Подробнее описано на этой странице. Следует отметить, что при одновременном выводе (например, в stdout) несколькими потоками MPI/OpenMP порядок сообщений в файле будет неопределённым - никакого упорядочивания не производится.

С момента постановки задачи в очередь и до её завершения нельзя изменять файлы, относящиеся к данной задаче - ни скрипт для qsub, ни запускаемое приложение, ни исходные данные. Именно эти самые самие файлы, а не их копии, будут использоваться при работе задачи - поэтому их модификация с большой вероятностью прервёт работу либо приведёт к некорректным результатам.

  • cpu (central processing unit, процессор) - микросхема, выполняющая код работающих на компьютере программ. Слово 'процессор' часто некорректно используется вместо термина 'ядро процессора', описанного ниже.
  • cpu core (ядро процессора) - часть процессора, способная выполнять свой собственный набор команд. Процессор, содержащий только одно ядро, вынужден постоянно делить его между всеми запущенными программами, выделяя каждой из них своё время. Но в любой момент времени он выполняет только какую-то одну программу. Процессор, содержащий несколько ядер, в каждый момент времени выполняет пропорционально большее количество программ. Для простоты можно представить четырёхядерный процессор как четыре одноядерных, находящихся в корпусе одной микросхемы.
  • host - любой компьютер, т.е. физический сервер.
  • node (узел) - компьютер, предназначенный для выполнения на нём пользовательских задач с использованием PBS.
  • resource (ресурс) - одно из основных понятий, используемых PBS. Ресурсы узла состоят как минимум из его ядер и оперативной памяти. Ресурсы, необходимые задаче пользователя, включают как количество ядер/памяти, так и время, необходимое задаче для работы. Также в виде ресурсов могут выступать, например, лицензии на коммерческое программное обеспечение. Более подробное описание находится ниже.
  • vnode (virtual node, виртуальный узел) - часть аппаратных ресурсов узла, для удобства логически объединенная в абстрактный объект. Например, узлы, содержащие по три графические карты, могут быть представлены как три виртуальных узла, каждый из которых содержит по одной карте и равному количеству процессорных ядер и оперативной памяти. Слово 'виртуальный' в данном случае не имеет никакого отношения к использованию на сервере виртуализации.
  • job (задача) - набор директив, передаваемых пользователем планировщику PBS, с помощью которых указывается, какие ресурсы необходимы и какую программу запускать. Удобно оформлять задачу как скрипт на языке 'bash', хотя возможна и передача всех данных через параметры команды 'qsub'.
  • сhunk (блок) - набор ресурсов, выделяемых задаче как целая часть, гарантированно находящаяся на одном узле.
  • queue ([kju:], очередь) - имеющий собственное имя контейнер для задач, обрабатываемых PBS. Очередь содержит как уже выполняющиеся, так и ожидающие запуска задачи. Завершившиеся задачи очередь покидают. Планировщик использует несколько очередей, например, для запуска задач на узлах разных типов. Каждая задача может находиться только в одной очереди. Буква 'q' в начале названий многих утилит PBS происходит как раз от слова 'queue'. Подробное описание имеющихся у нас очередей находится на этой станице.

Ресурсы могут относиться к серверу PBS, к очередям или к узлам (виртуальным узлам). Задача запрашивает необходимые ей ресурсы. Ресурсы выделяются, при этом некоторые из них (например, процессорные ядра или оперативная память узла) при выполнении задачи потребляются и освобождаются только после её завершения. Виртуальные узлы, находящиеся на одном сервере, могут разделять свои ресурсы друг с другом.


Ресурсы, относящиеся к серверу PBS или к очереди, используются всей задачей и в запросе указываются в следующем виде: '-l Ресурс=Значение'. Пример такого ресурса - 'walltime', время, необходимое задаче для работы. Если по истечении этого времени задача не завершится сама, то будет прервана принудительно. Указывается в виде 'часы:минуты:секунды'. Например, следующий запрос означает, что задаче достаточно полторы минуты работы:

-l walltime=00:01:30


Ресурсы, относящиеся к узлам (или виртуальным узлам), запрашиваются и выделяются в виде блоков (chunk). Запрос в большинстве случаев можно представить в следующем виде: '-l select=N:chunk', где строка 'chunk' имеет вид 'Ресурс1=Значение1[:Ресурс2=Значение2 …]', а число 'N' - сколько таких блоков требуется. Если нужны блоки разных типов, можно использовать следующую форму запроса: '-l select=N1:chunk1[+N2:chunk2 …]'.

В частности, именно так запрашивается необходимое количество ядер (параметр 'ncpus', хотя логичнее было бы 'ncores') и оперативной памяти ('mem'). При использовании MPI или OpenMP также надо указать, сколько потоков должно быть запущено в этом блоке, для этого используются параметры 'mpiprocs' и 'ompthreads' соответственно. Например, следующий запрос означает, что задаче необходимы два блока, каждый из которых содержит 4 ядра и 8000 МБ памяти, и на каждом из этих блоков будут запущены 4 MPI процесса:

-l select=2:ncpus=4:mpiprocs=4:mem=8000m


Для указания нужного расположения выделяемых блоков на узлах используется запрос '-l place=[arrangement][:sharing]'

  1. 'Arrangement' имеет смысл только при запросе более одного блока. Может иметь одно из значений:
    • 'pack' - все выделенные блоки должны быть на одном узле.
    • 'scatter' - все блоки должны быть на разных серверах.
    • 'free' - произвольным образом.
  2. 'Sharing' может иметь одно из значений:
    • 'exclhost' - только эта задача может использовать выделенный узел. Неиспользуемые на узле ресурсы будут недоступны другим задачам.
    • 'excl' - только эта задача может использовать выделенный виртуальный узел.
    • 'shared' - значение по умолчанию. Задача может разделять ресурсы узла (или виртуального узла) с другими задачами.


Важно понимать, что в общем случае запрошенное количество ядер и ОЗУ не приводит автоматически к ограничению запускаемого приложения именно этим количеством ядер и памяти. Интеграция PBS с OpenMP и MPI позволяет передавать запрошенное количество ядер приложению, чтобы оно знало, сколько потоков запустить, но в случае использования каких-то других механизмов распараллеливания это надо отслеживать самостоятельно. Запрашиваемое количество ОЗУ как правило никак не передаётся приложению, для того чтобы оно самостоятельно ограничивало свои потребности, и также не ограничивает память, выделяемую приложению операционной системой. Вместо этого пользователь должен самостоятельно оценивать, сколько памяти потребуется его приложению при работе и сообщать это PBS, чтобы тот учитывал это при планировании.

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

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

Примеры

Два MPI процесса, каждому требуется по 100 МБ ОЗУ:

  • на одном и том же узле:
    #PBS -l select=2:ncpus=1:mpiprocs=1:mem=100m,place=pack

    или

    #PBS -l select=1:ncpus=2:mpiprocs=2:mem=200m
  • на разных узлах:
    #PBS -l select=2:ncpus=1:mpiprocs=1:mem=100m,place=scatter
  • произвольно:
    #PBS -l select=2:ncpus=1:mpiprocs=1:mem=100m,place=free


Процесс с 4 потоками под управлением OpenMP, где каждому из четырех потоков требуется по 2000 МБ ОЗУ:

#PBS -l select=1:ncpus=4:ompthreads=4:mem=8000m

Создадим скрипт «submit.sh» следующего вида:

#!/bin/bash

#PBS -l select=2:ncpus=1:mem=2000m,place=scatter
#PBS -l walltime=00:01:00
#PBS -m n

cd $PBS_O_WORKDIR
echo "I run on node: `uname -n`"
echo "My working directory is: $PBS_O_WORKDIR"
echo "Assigned to me nodes are:"
cat $PBS_NODEFILE
sleep 15


Строки, начинающиеся с '#PBS', содержат директивы, используемые планировщиком. В частности, запросы ресурсов. Заметим, что для языка 'bash' все строки, начинающиеся с символа '#', являются комментариями и не влияют на работу самого скрипта.


Поставим в очередь:

qsub submit.sh
15434.hpc-suvir1.hpc

15434 - идентификатор получившейся задачи. Посмотрим её состояние:

qstat 15434
Job id            Name             User              Time Use S Queue
----------------  ---------------- ----------------  -------- - -----
15434.hpc-suvir1  submit.sh        admin                    0 Q workq

Спустя некоторое время в текущей директории появляются файлы «submit.e15434» и «submit.o15434». Первый из них содержит сообщения об ошибках и в случае корректной работы как правило должен быть пустым. Второй файл содержит вывод скрипта и должен выглядеть примерно так:

I run on node: cn15
My working directory is: /mnt/storage/home/admin/examples/pbs
Assigned to me nodes are:
cn15
cn16

В случае, если необходимо интерактивное взаимодействие с работающей программой, используется соответствующий режим запуска задач. В этом режиме после постановки задачи в очередь команда qsub не завершается, а ждёт, когда планировщик выделит запрошенные ресурсы, после чего предоставляет shell на выделенном узле. Если запрошено несколько узлов, доступ предоставляется к 'Mother Superior'.

Вторая важная особенность интерактивного режима заключается в том, что из скрипта, передаваемого qsub, используются только опции PBS (строки '#PBS …'), содержимое скрипта не выполняется. Поэтому после получения shell необходимую программу надо запустить самостоятельно, после чего с ней можно работать в интерактивном режиме.


Для запроса у планировщика интерактивного режима надо при вызове qsub дополнительно указать параметр '-I':

qsub -I submit.sh

Либо можно указать этот параметр внутри скрипта submit.sh:

#PBS -I


Может быть удобным отказаться от использования скрипта и все параметры передавать qsub через коммандную строку:

qsub -I -l select=1:ncpus=1:mem=2000m,walltime=1:0:0


В случае, если будет использоваться система X Window для запуска на узлах программ с графическим интерфейсом, необходимо добавить ключ '-X':

qsub -I -X -l select=1:ncpus=1:mem=2000m,walltime=1:0:0


Если Ваша программа отработала и завершилась до истечения walltime, то для завершения самой интерактивной задачи выполните команду 'exit'.

  1. Вычислительные узлы разных типов доступны при помощи разных очередей задач. Все имеющиеся очереди описаны на этой странице. Очередь можно не указывать, при этом будет использоваться очередь по умолчанию.
  2. Число свободных узлов каждого типа можно узнать с помощью команды 'qfree' или 'qfree -s'. Например:
    qfree -s
    Completely free 12-cores nodes: 5
    Partially  free 12-cores nodes: 7
    Completely free  8-cores nodes: 12
    Partially  free  8-cores nodes: 15
    Free CPU cores                : 88 + 172
  3. Наличие свободных ресурсов не означает, что Ваша задача запустится сразу после постановки в очередь. Причины могут быть разные. Например, имеется ограничение на количество ядер, которые пользователь может занять одновременно. Также возможна ситуация, когда в очереди находится задача, которой необходимо очень много ядер и для запуска которой PBS резервирует свободные ресурсы и не даёт использовать другим.
  4. Имеется возможность получать по электронной почте уведомления, что задача запустилась, завершилась или была принудительно прервана. Подробное описание есть в PBS User's Guide (ссылка находится в верху страницы) в разделе '3.13.5 Specifying Email Notification'. Например, для получения всех возможных уведомлений, в скрипт для PBS надо добавить строку:
    #PBS -m abe
  5. Возможно объединение потоков ошибок и стандартного вывода и сохранение их в общий файл, для этого в скрипт нужно добавить:
    #PBS -j oe
  6. В некоторых случаях можно использовать qsub без дополнительного скрипта, указав qsub не только необходимые ресурсы (как в примере использования интерактивного режима), но и какую команду выполнить. Команда указывается после параметра '--', без использования дополнительных кавычек. Например так:
    qsub -l select=1:ncpus=1:mem=100m,walltime=0:0:10 -- /bin/uname -a

    или, если необходимо выполнить несколько команд:

    qsub -l select=1:ncpus=1:mem=100m,walltime=0:0:10 -- /bin/bash -c "cd $PBS_O_WORKDIR;uname -a;date"
  7. Если необходимо выполнить большое количество однотипных вычислений (например, обработать 10000 файлов или получить результат какого-то вычисления при большом количестве разных исходных данных), то не надо усложнять и пытаться запускать из одной задачи PBS несколько программ одновременно. Вместо этого напишите скрипт, который создаст на интерфейсном сервере и поставит в очередь столько задач, сколько необходимо.
  8. Пользователям, ставящим в очередь много задач одновременно, иногда бывает нужно удалить их все (или часть) из очереди. Для этого можно использовать примерно такую команду (в данном случае первые 5 задач будут пропущены):
    qdel $( qstat -u ИмяВашейУчетнойЗаписи | awk -F. '{if (NR>5) print $1}' )