Компиляция и запуск последовательных и параллельных задач на ЦИВК ОИЯИ

Э.Б.ДушановТ.Ф.Сапожникова ЛИТ, ОИЯИ, 2010.


В настоящее время в ЛИТ введена в эксплуатацию вычислительная ферма, состоящая из 168 двухпроцессорных 2-х и 4-х ядерных машин, соединенных коммуникационной средой 1Gb Ethernet. В это число входит ферма для параллельных вычислений, состоящая из двадцати машин, соединенных дополнительно 2xInfiniband. Так как 2-х и 4-х ядерные процессоры являются в действительности двумя и четырьмя независимыми процессорами на одном кристалле, то фактически пользователям ОИЯИ и Grid доступны 1104 64-х битных ЦПУ.

Доступ к ферме производится через интерактивные машины lxpub01-lxpub05, на которых задачи можно редактировать, компилировать, отлаживать и запускать на счет, если при этом запускаемые пользователем процессы требуют не более 15 минут счетного времени. Задания, требующие большего времени для обработки, запускаются на счетных машинах в пакетном режиме (batch).

Программное обеспечение

На всех счетных машинах ЦИВК установлена ОС Scientific Linux release 5.4 (SL54) с архитектурой x86_64. Для ускорения перехода на ОС SL54 установлена дополнительная интерактивная машина lxpub05 с ОС SL54 и 64-битной архитектурой. Поэтому пользователи могут готовить исполняемые файлы и на lxpub05, пропуская этап компиляции на счетных машинах.

На ферме установлены компиляторы:
g77/gcc/g++ - GNU Fortran 77, C and C++ compilers version 3.4.6;
gfortran/gcc4/g++4 - GNU Fortran 95, C and C++ compilers version 4.1.2;
ifort/icc/icpc - Intel Fortran, C, C++ compilers version 11.1.

GCC (GNU Compiler Collection) - набор свободно распространяемых компиляторов для различных языков программирования (С/C++/Fortran и др.). Они используются как стандартные компиляторы для Unix-подобных операционных систем.

Intel С/C++/Fortran Compilers - компиляторы нового поколения, позволяющие обеспечить высокую производительность на процессорах Intel. Компиляторы Intel дополнены эффективными средствами разработки многопоточного кода, поддерживающими стандарт OpenMP. Библиотека Intel Math Kernel Library (Intel MKL) предоставляет набор оптимизированных математических функций, позволяющих создавать быстродействующие приложения для процессоров Intel. Библиотеки включают линейные алгебраические функции (LAPACK и BLAS), быстрые преобразования Фурье (FFT), пакет векторной математики VML. Подробнее - см. документацию на lxpub05 в директории: /opt/intel/Compiler/11.1/056/Documentation/en_US

Для разработки параллельных программ с использованием пакета MPI (Message Passing Interface) установлены библиотеки MPI для языков программирования C, C++ и Фортран. Для компиляции и сборки параллельных программ с использованием пакета MPI используются следующие команды:

mpicc - для программ, написанных на языке C;
mpiCC - для программ, написанных на C++;
mpif77 и mpif90 - для программ, написанных на Фортране;
mpiexec - запуск программы на исполнение на всех ЦПУ.

Более подробно о командах и компиляторах можно узнать, выполнив команду man.

Запуск задач в пакетном режиме. Команды PBS

PBS (Portable Batch System) - система пакетной обработки заданий, предназначенная для управления ресурсами высокопроизводительных вычислительных кластеров. Команды PBS используются для постановки задания в очередь на выполнение, запуска на счет, мониторинга, модификации и снятия заданий, выдачи результатов.

Для большинства заданий пользователей вычислительной фермы используется 3 очереди: ib - очередь для параллельной фермы с Infiniband, а также очереди defq и common. В настоящее время для постановки заданий в очередь имя очереди в задании указывать необязательно. Все задачи запускаются в очередь defq, из которой они перераспределяются по очередям common и ib. Критерий распределения:

- если заказано от 2 до 80 ЦПУ, то задание пойдет в очередь ib и будет работать на Infiniband;
- если заказан 1 ЦПУ или больше 80, то задание пойдет в очередь common и будет работать на 1Gb Ethernet'е.

В процессе пакетной обработки автоматически инициализируются ряд переменных окружения, которые можно использовать в задании.

Значения некоторых переменных:
$PBS_O_WORKDIR - абсолютный путь к текущему каталогу пользователя, из которого производился запуск пакетного задания;
(пример: /afs/jinr.ru/user/t/tsap/tmp/)
$PBS_NODEFILE - список выделенных ЦПУ, на которых будет запущена задача (пример элемента списка: wni005.jinr.ru);
$TMPDIR - имя директории на счетных машинах, создаваемой на время выполнения задания (пример: /scr/u/2971008.lxbsrv01.jinr.ru).

Задания запускаются в пакетную обработку командой qsub. При вызове этой команды пользователь указывает требуемое количество ресурсов, а также ряд дополнительных параметров. Параметры, необходимые для выполнения задания, записывается в файл (script-file), после чего задание можно отправить в очередь на выполнение командой:


     qsub script-file

Пример script-файла для последовательной задачи с компиляцией и запуском на счет:

     #!bin/sh
     #PBS -q defq
     #PBS -l walltime=01:00:00
     #PBS -l cput=01:00:00
     #PBS -m abe 
     #PBS -M username@jinr.ru
     cd $PBS_O_WORKDIR
     cc -o myprog myprog.c
     ./myprog

Некоторые параметры команды qsub:


-q - имя очереди (defq);
-m - события, о которых следует извещать email'ом:
b - оповещение о запуске,
e - о завершении,
a - о прекращении работы по ошибке;

-M - e-mail адрес, на который направляются все служебные сообщения о состоянии задачи;
-l - требуемые ресурсы:
walltime - астрономическое время счета задачи;
cput - счетное (процессорное) время;
nodes - количество процессоров (ЦПУ).

Полное описание ресурсов задачи можно получить по команде man pbs_resources, а описание атрибутов задачи - по команде man pbs_job_attributes.

После того, как задача была отправлена в очередь, ее состояние можно контролировать с помощью команды


     qstat -u username  ,

после ввода которой на экране появляется таблица:

lxbsrv01.jinr.ru: 
                                                                     Req'd  Req'd   Elap
Job ID            Username Queue  Jobname           SessID  NDS  TSK Memory Time  S Time
----------------  --------------  ----------------  ------  ---  --- ------ ----- - ----
3859978.lxbsrv01  tsap     ib     test-job-para-nA    --     10   1    --   00:05 Q  --
3860035.lxbsrv01  tsap     ib     test-job-para-nA  17293     3   1    --   00:05 R  --

Значения столбцов таблицы:

Job ID - уникальный идентификатор задачи;
Username - имя владельца задачи;
Queue - название очереди, в которой находится задание;
Jobname - имя задания;
SessID - идентификатор сессии (если задание в состоянии выполнения)
NDS - число используемых ЦПУ;
TSK - количество задач;
Req'd Time - планируемое время счета задачи;
Elap Time - общее процессорное время, использованное задачей на данный момент;
S - состояние задачи: Q - находится в очереди, R - вычисляется, E - произошла ошибка при выполнении.

Результаты выполнения задания появляются в рабочей директории ($PBS_O_WORKDIR) в виде 2 файлов:

Имя_задачи.oИдентификатор - стандартный вывод (stdout)
Имя_задачи.eИдентификатор - сообщение об ошибках (stderr)

Удаление задания из очереди:


     qdel <Job_ID>

Запуск параллельных задач

Для подготовки и счета параллельных задач под управлением MPI на ферме доступны компиляторы mpicc, mpif77, mpic++ и mpif90.

При запуске задач нужно сначала определиться, откуда их запускать. Если файлы небольшие, тогда удобней работать в пределах домашней директории, которая находится в AFS (распределенной высоко защищенной файловой системе), и там же хранить все файлы. Если есть или могут появиться большие файлы (а место в home-директории ограничено 50 мб), или есть общие для нескольких пользователей файлы, тогда лучше хранить их, например, на scratch (что не в AFS), а для счета - копировать на счетные машины во временную директорию, адрес которой находится в переменной $TMPDIR.

Запуск параллельных задач в AFS

Для работы из home-директории надо иметь там script-файл для запуска, там же - программу или исполняемый файл и все входные файлы. В этом script-файле должна быть команда:


     cd $PBS_O_WORKDIR

Пример script-файла для запуска задачи с параллельными вычислениями на нескольких процессорах (все файлы - в домашней директории):

     #  "defq" - очередь, из которой задания направляются в очереди common и ib 
     #PBS -q defq
     #  Запрашиваем 50 мин. астрономического времени на выполнение задания
     #PBS -l walltime=00:50:00
     #  и 5 мин. счетного времени на 1 процессоре
     #PBS -l cput=00:05:00
     #  Задание выполняется на 10 ЦПУ
     #PBS -l nodes=10 
     #  Переходим в домашнюю директорию, откуда запускалась команда qsub
     #  и где находятся файлы программы и данных
     cd $PBS_O_WORKDIR
     #  Готовим исполняемый файл
     mpicc -o test test.c
     #  Запуск программы на исполнение на всех ЦПУ
     mpiexec ./test

Запуск параллельных задач с файлами, находящимися вне AFS

Переменная $TMPDIR, устанавливаемая при выполнении задания, указывает на временную директорию на счетных машинах, куда могут быть записаны файлы задания. Соответственно в script-файле должны быть команды копирования нужных файлов с директорий, которые не входят в AFS и которые доступны непосредственно только на интерактивных машинах lxpub01-lxpub05, а на счетных машинах - доступны только по абсолютному пути.

Для работы с использованием /scrc/ надо иметь в домашней директории script-файл для запуска задачи с использованием MPI, а на /scrc/u/username - нужные файлы (тексты программы или исполняемый файл и/или входные файлы).

Пример script-файла для запуска параллельных задач с файлами вне AFS:

     #PBS -l walltime=00:20:00
     #PBS -l cput=00:05:00
     #PBS -l nodes=4
     #  Переходим во временную директорию на счетном компьютере:
     ret=0
     cd $TMPDIR
     if test $? -ne 0 ; then
        echo "ERROR 1: can not cd $TMPDIR"
        ret=1
     fi
     #  Копирование исполняемых и входных файлов:
     #  (заменить директорию /scrc/u/username/ и имена файлов - на свои)
     scp -p2 lxpub01:/scrc/u/tsap/test .
     scp -p2 lxpub01:/scrc/u/tsap/in.dat .   
     #  - здесь копируем файлы только на одну машину, 
     #
     #  а ниже - на остальные:
     for h in `cat $PBS_NODEFILE | sort | uniq` ; do
        test X"`hostname -f`" = X"$h" && continue
        ssh -1x $h "mkdir -p $TMPDIR"
        scp -p2 test $h:$TMPDIR
        scp -p2 in.dat $h:$TMPDIR
     done
     #  Проверка, все ли получилось.
     #  (имена файлов - тоже заменить на свои)
     if test ! -e $TMPDIR/test ; then
        echo "ERROR 2: no $TMPDIR/test"
        ret=1
     fi
     if test ! -e $TMPDIR/in.dat ; then
        echo "ERROR 3: no $TMPDIR/in.dat"
        ret=1
     fi
     test $ret -ne 0 && exit 1
     #  Запуск на счет:
     mpiexec ./test
     #  Копирование выходного файла out.dat
     #  (также заменить имя файла и адрес на /scrc/ на свои)
     if [ -f out.dat ]; then
        scp -p2 out.dat lxpub01:/scrc/u/tsap/.
     fi

Команда


     qstat -Qf ib

показывает параметры очереди ib. Вот некоторые из них:

lxpub01:~ > qstat -Qf ib
Queue: ib
     resources_max.cput = 16000:00:00
     resources_max.nodect = 80
     resources_max.walltime = 101:00:00
     resources_min.nodect = 2
     resources_available.nodect = 80

max.nodect - максимальное число ЦПУ для параллельной задачи (для очереди ib);
max.walltime - максимальное астрономическое время счета задачи;
max.cput - максимальное счетное время задачи.

Эти параметры очереди устанавливаются администратором системы и могут быть изменены. Для сбалансированного задания параметров очереди нужно учитывать, что для walltime, cput и nodect примерно выполняется следующее соотношение:

астрономическое время (walltime) * число процессов (nodect) ≈     
≈ процессорное время (cput)     

(В приведенном примере параметров очереди ib максимальное счетное время задачи задано больше с учетом планируемого увеличения числа процессоров).

Требуемые значения этих параметров задаются в script-файле и в соответствии с запрашиваемыми ресурсами определяется приоритет и время ожидания в очереди. Задание не ставится в очередь, если превышены максимально допустимые значения параметров очереди. Запрашивать значения счетного и астрономического времени значительно больше требуемого не имеет смысла, т.к. задание с большей вероятностью дольше простоит в очереди.

Дополнительную информацию можно найти на сайте ЛИТ в разделе ЦИВК и в информационном бюллетене ЛИТ. Ниже приведены ссылки на script-файлы (автор - В.В.Мицын), которые можно использовать как тест или диагностическую задачу для случаев:

- test-job - когда у пользователя что-то в batch-системе не работает;
- test-job-para-AFS - тест для параллельных вычислений на нескольких процессорах для случая, когда все файлы лежат в AFS;
- test-job-para-nAFS - тест для параллельных вычислений на нескольких процессорах, когда файлы надо копировать из /scr или другого произвольного места, находящегося вне AFS.

Компиляция и запуск параллельных задач в среде Grid

В EGEE предусмотрена возможность работы с параллельными программами с помощью MPI-1 (LAM и MPICH) и MPI-2 (OpenMPI и MPICH2).
Задача на счет в среде Grid отправляется с помощью mpi-start скриптов, разработанных в рамках проекта Interactive European Grid рабочей группой MPI:
http://dissemination.interactive-grid.eu/

Эти скрипты доступны на сайте информационной группы EGEE:
http://egee-intranet.web.cern.ch/egee-intranet/NA1/TCG/wgs/mpi.htm
http://egee-uig.web.cern.ch/egee-uig/production_pages/MPIJobs.html

При расчетах в среде Grid для любой задачи требуется скрипт-файл с расширением jdl. При использовании mpi-start системы от пользователя дополнительно требуется создание запускающего и завершающего скриптов. Таким образом, для расчета параллельной задачи в Grid требуется следующее:

1. Действительный сертификат пользователя, подписанный одним из удостоверяющих центров, признаваемый grid-сайтами (usercert.pem) и соответствующий этому сертификату закрытый ключ (userkey.pem);
2. JDL-файл для запуска задачи в Grid с указанием в этом файле требований к программному обеспечению (ПО), если при запуске задачи явно не указывается вычислительный элемент;
3. Если запуск задачи происходит с явным указанием вычислительного элемента, то предварительно необходимо запросить информационную систему Grid с целью убедиться, что он (элемент) имеет всё необходимое для задачи ПО (MPICH, OpenMPI, MPI-START);
4. mpi-start-wrapper.sh - файл, определяющий переменные среды;
5. mpi-hooks.sh - файл, который подготавливает задачу к запуску, компилирует и после завершения выводит сообщение.

Начнем со второго пункта. Обычно существующее программное обеспечение публикуется в информационных службах самих grid-сайтов. Это может быть MPICH или OPENMPI. Именно эти значения должны указываться в JDL-файле в атрибуте Arguments и в атрибуте Requirements, если при запуске задачи явно не указывается вычислительный элемент. Приводим вариант такого файла:

     #  myprog.jdl
     #
     Type          = "Job"
     #  JobType принимает значения:
     #  MpiCh | Normal | Partitionable | Parametric | Checkpointable
     JobType       = "Normal";
     #  Число процессоров:
     CPUNumber     = 4;
     #  Исполняемый скрипт-файл:
     Executable    = "mpi-start-wrapper.sh";
     #  Аргументы - исполняемый файл и среда (ПО):
     Arguments     = "myprog MPICH";
     #  Файл для вывода данных на стандартный вывод:
     StdOutput     = "myprog.out";
     #  Файл для ошибок:
     StdError      = "myprog.err";
     #  Поток файлов, отправляемых на узел для выполнения:
     InputSandbox  = {"mpi-start-wrapper.sh","mpi-hooks.sh","myprog.c"};
     #  Поток результирующих файлов:
     OutputSandbox = {"myprog.err","myprog.out"};
     Requirements  = 
     Member("MPI-START",other.GlueHostApplicationSoftwareRunTimeEnvironment)&& 
     Member("OPENMPI-1.3.2",other.GlueHostApplicationSoftwareRunTimeEnvironment);
     #
     #  the end

Если среда реализована в OpenMPI, то в значении атрибута Arguments надо заменить MPICH на OPENMPI.

Команда


     glite-wms-job-list-match -a myprog.jdl 

выводит список доступных именно для этой задачи вычислительных элементов в соответствии с информацией в файле описания задачи и правами пользователя, вытекающими из его сертификата. Например, на lxpub04.jinr.ru можно получить:

     Connecting to the service 
            https://lcg16.sinp.msu.ru:7443/glite_wms_wmproxy_server
     ====================================================================
                          COMPUTING ELEMENT IDs LIST
      The following CE(s) matching your job requirements have been found:
            *CEId*
      - cms-eth0-1.kipt.kharkov.ua:2119/jobmanager-lcgpbs-rgstest
      - grid129.sinp.msu.ru:2119/jobmanager-lcgpbs-rgstest
      - lcgce01.jinr.ru:2119/jobmanager-lcgpbs-rgstest
      - lcgce02.jinr.ru:2119/jobmanager-lcgpbs-rgstest
      - lcgce21.jinr.ru:8443/cream-pbs-rgstest
      - grid-ce.icp.ac.ru:2119/jobmanager-lcgpbs-rgstest
      - grid-ce.icp.ac.ru:2119/jobmanager-lcgpbs-test1
     ====================================================================

Файл, определяющий переменные среды, имеет вид:

     #!/bin/bash
     #  mpi-start-wrapper.sh
     #  Присваиваем переменным имя исполняемого файла (myprog) и ПО (MPICH)
     #  из Arguments JDL-файла:
     MY_EXECUTABLE=`pwd`/$1
     MPI_FLAVOR=$2
     #  Перевод прописных букв в строчные в MPI_FLAVOR для отправки на mpi-start:
     MPI_FLAVOR_LOWER=`echo $MPI_FLAVOR | tr '[:upper:]' '[:lower:]'`
     #  Укажем правильный путь к ПО на основе данного параметра:
     eval MPI_PATH=`printenv MPI_${MPI_FLAVOR}_PATH`
     #  Присвоим переменной путь к grid-интерфейсу:
     eval I2G_${MPI_FLAVOR}_PREFIX=$MPI_PATH
     export I2G_${MPI_FLAVOR}_PREFIX
     #  Создание исполняемого файла с формальным именем (локализация):
     touch $MY_EXECUTABLE
     #  Формирование переменных для mpi-start:
     export I2G_MPI_APPLICATION=$MY_EXECUTABLE
     export I2G_MPI_APPLICATION_ARGS=
     export I2G_MPI_TYPE=$MPI_FLAVOR_LOWER
     export I2G_MPI_PRE_RUN_HOOK=mpi-hooks.sh
     export I2G_MPI_TYPE=$MPI_FLAVOR_LOWER
     export I2G_MPI_PRE_RUN_HOOK=mpi-hooks.sh
     export I2G_MPI_POST_RUN_HOOK=mpi-hooks.sh
     #  Для включения в протокол выполнения задачи отладочной информации 
     #  надо раскомментировать 3 строки, приведённые ниже:
     #export I2G_MPI_START_VERBOSE=1
     #export I2G_MPI_START_DEBUG=1
     #export I2G_MPI_START_TRACE=1
     echo "Start: $I2G_MPI_START"
     #  Вызов mpi-start:
     $I2G_MPI_START

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

     #!/bin/sh
     # mpi-hook.sh
     #  Следующая функция вызывается перед тем, как исполняемый MPI-файл стартует:
     pre_run_hook () {
     #  Выводим некоторые параметры компиляции:
     #echo "Compiling ${I2G_MPI_APPLICATION}"
     #echo "OPTS=${MPI_MPICC_OPTS}"
     #echo "PROG=${I2G_MPI_APPLICATION}.c"
     #  Компиляция программы и получение исполняемого файла:
        cmd=" mpicc -o myprog  myprog.c "
        echo $cmd
        $cmd
        if [ ! $? -eq 0 ]; then
           echo "Error compiling program.  Exiting..."
           exit 1
        fi
     #  Если компиляция прошла успешно:
        echo "Successfully compiled ${I2G_MPI_APPLICATION}"
        return 0
     }
     #  Следующая функция вызывается перед завершением исполняемого MPI-файла: 
     post_run_hook () {
        echo "Executing post hook."
        echo "Finished the post hook."
        return 0
     }

После формирования этих двух вспомогательных и одного JDL файлов задачу можно отправлять для счета командой:


     glite-wms-job-submit -a myprog.jdl ,

если требования к среде окружения были указаны в файле описания задачи;
либо командой:

     glite-wms-job-submit -a -r <ce> myprog.jdl ,

если указывается конкретный вычислительный элемент (<ce> - вычислительный элемент конкретного grid-узла).

Например:
(символ "\" означает, что следующие 2 строки составляют одну команду)

     lxpub04:~ > glite-wms-job-submit -a -r \
            grid-ce.icp.ac.ru:2119/jobmanager-lcgpbs-rgstest myprog.jdl
     
     Connecting to the service 
     https://lcg16.sinp.msu.ru:7443/glite_wms_wmproxy_server
     =================== glite-wms-job-submit Success ===================
     The job has been successfully submitted to the WMProxy
     Your job identifier is:
     https://lcg16.sinp.msu.ru:9000/OJhpNW-Z4xNvd7gIIQCCKA
     ====================================================================

Задаче присваивается идентификатор:

     https://lcg16.sinp.msu.ru:9000/OJhpNW-Z4xNvd7gIIQCCKA ,
по которому можно проверять статус задачи командой:
     lxpub04:~ > glite-wms-job-status \
            https://lcg16.sinp.msu.ru:9000/OJhpNW-Z4xNvd7gIIQCCKA
     *************************************************************
     BOOKKEEPING INFORMATION:
     Status info for the Job : 
            https://lcg16.sinp.msu.ru:9000/OJhpNW-Z4xNvd7gIIQCCKA
     Current Status:     Scheduled
     Status Reason:      Job successfully submitted to Globus
     Destination:        grid-ce.icp.ac.ru:2119/jobmanager-lcgpbs-rgstest
     Submitted:          Thu Jan 21 15:49:06 2010 MSK
     *************************************************************

Как видно из этой таблицы, выводятся четыре параметра:
 
- Current Status - текущий статус, принимает значения:
а) Scheduled - задача принята;
б) Running - задача запущена на счет;
в) Done - расчеты завершены.

- Status Reason - действие, происходящее при текущем статусе, принимает значения:
а) unavailable - неопределенность, возможно задача не будет приниматься;
б) Job successfully submitted to Globus - задача успешно отправлена на узел;
в) Job terminated successfully - расчеты завершены удачно.

- Destination - показывает grid-узел, куда отправляется/отправлена задача.
- Submitted - начало отправки.

После успешного завершения задачи можно забрать результаты её работы командой:

     lxpub04:~ > glite-wms-job-output --dir myprogout \
            https://lcg16.sinp.msu.ru:9000/OJhpNW-Z4xNvd7gIIQCCKA
     Connecting to the service 
     https://lcg16.sinp.msu.ru:7443/glite_wms_wmproxy_server

     ====================================================================
                             JOB GET OUTPUT OUTCOME
     Output sandbox files for the job: 
            https://lcg16.sinp.msu.ru:9000/OJhpNW-Z4xNvd7gIIQCCKA
     have been successfully retrieved and stored in the directory:
            /afs/jinr.ru/user/d/dushanov/myprogout
     ====================================================================

В этом случае полученные данные (myprog.out, myprog.err) скопируются в каталог myprogout.