Запуск массива заданий с использованием GridWay.
- Предварительные действия
- Постановка задачи
- Программная часть
- Описание задания
- Запуск задания
- Получение и обработка результатов
- Дополнительная информация
Этот практикум демонстрирует возможность запуска массива заданий, используя метапланировщик GridWay.
В качестве примера рассматривается известный алгоритм по вычислению числа π
.
Предварительные действия
Прежде чем выполнять какие-либо действия необходимо получить прокси-сертификат для того чтобы получить доступ к грид-ресурсам.
$ voms-proxy-init -voms gilda Enter GRID pass phrase: Your identity: /DC=es/DC=irisgrid/O=ucm/CN=joseluis.vazquez Cannot find file or dir: /home/jlvazquez/.glite/vomses Creating temporary proxy ................................................. Done Contacting voms.ct.infn.it:15001 [/C=IT/O=INFN/OU=Host/L=Catania/CN=voms.ct.infn.it] "gilda" Done Creating proxy ...................................... Done Your proxy is valid until Tue Jun 3 08:22:47 2008
Постановка задачи
Для иллюстрации возможности запуска массива заданий будем использовать хорошо известный пример по вычислению числа π
.
Для этого необходимо вычислить интеграл следующей функции:
Интегрируемая функция: f(x) = 4/(1+x2)
. То есть искомое число π
будет равно
значению интеграла f(x) на интервале [0,1].
Для того чтобы вычислить этот интеграл, разобьём интервал интегрирования на несколько частей и вычислим их по отдельности.
Ясно, что чем больше частей, тем точнее будет вычисленное значение.
Итак, у нас есть доступ в Грид с несколькими вычислительными узлами, есть GridWay для запуска заданий.... Почему бы не использовать их
для вычисления числа π
, распределив вычисление каждой из частей между отдельными узлами и выполнить это одной командой.
Программная часть
Для реализации этого алгоритма выберем язык программирования С. Создайте текстовый файл с именем pi.c и скопируйте в него следующий текст:
#include <stdio.h> #include <string.h> int main (int argc, char** args) { int task_id; int total_tasks; long long int n; long long int i; double l_sum, x, h; task_id = atoi(args[1]); total_tasks = atoi(args[2]); n = atoll(args[3]); fprintf(stderr, "task_id=%d total_tasks=%d n=%lld\n", task_id, total_tasks, n); h = 1.0/n; l_sum = 0.0; for (i = task_id; i < n; i += total_tasks) { x = (i + 0.5)*h; l_sum += 4.0/(1.0 + x*x); } l_sum *= h; printf("%0.12g\n", l_sum); return 0; }
Затем скомпилируйте его при помощи команды
$ gcc -O3 pi.c -o pi
Важное замечание: в зависимости от архитектуры удалённых узлов (32 или 64 разрядная) необходимо добавить соответствующий флаг -m32 или -m64.
После компиляции вы получите исполняемый файл pi. Эта программа принимает три параметра:
- Идентификатор(номер) текущего задания в массиве заданий. Нумерация внутри массива начинается с 0
- Общее количество заданий, на которое будет разделено вычисление
- Количество интервалов для вычисления интеграла
Описание задания
Для того чтобы использовать GridWay для выполнения задания, необходимо подготовить файл описания задания. В нашем случае он будет называться pi.jt. Создайте файл с таким именем и скопируйте в него следующий текст:
EXECUTABLE = pi ARGUMENTS = ${TASK_ID} ${TOTAL_TASKS} 100000 STDOUT_FILE = stdout_file.${TASK_ID} STDERR_FILE = stderr_file.${TASK_ID} RANK = CPU_MHZ
Важное замечание: если исполняемый файл скомпилирован для определённой архитектуры (скажем для определённости для 32-разрядной), а есть вероятность того что в Грид присутствуют узлы с 64-разрядной архитектурой, то в файл описания задания необходимо добавить ограничение для использования только 32-разрядных узлов.
REQUIREMENTS = ARCH="x86"
Запуск задания
Теперь необходимо запустить задание. Это выполняется командой:
$ gwsubmit -v -t pi.jt -n 4 ARRAY ID: 1 TASK JOB 0 15 1 16 2 17 3 18
- Использованные опции команды:
-t
- путь к файлу описания задания относительно текущей директории-v
- вывод на экран всех идентификаторов заданий-n
- количество заданий, на которое будет разделено вычисление
- На экран выводятся:
ARRAY ID
- идентификатор (номер), присвоенный всему массиву заданийTASK
- идентификатор (номер) задания внутри массива заданийJOB
- уникальный идентификатор (номер) отдельного задания, присвоенный системой
Для того чтобы ожидать завершения всех заданий используется команда gwwait. Аргумент, передаваемый этой команде - это идентификатор,
присвоенный всему массиву заданий. Он выдаётся в качестве выходных данных команды gwsubmit, если при запуске указана опция -v
.
Это значение можно также получить при помощи команды gwps.
Команда gwwait блокирует консоль и возвращает упраление только когда завершатся все задания из массива.
$ gwwait -v -A 1 0 : 0 1 : 0 2 : 0 3 : 0
Если команда была вызвана с опцией -v
, то для каждого задания массива выводится код завершения
(обычно код=0 означает успешное завершение).
Получение и обработка результатов
При завершении каждое из заданий создаёт файл с выходными данными. В нашем случае в текущей директории будут созданы файлы:
stdout_file.0 stdout_file.1 stdout_file.2 stdout_file.3
Всё что нам остаётся сделать - просуммировать результаты из каждого файла. Проще всего это выполнить, используя скрипт для awk.
$ awk 'BEGIN {sum=0} {sum+=$1} END {printf "Pi is %0.12g\n", sum}' stdout_file.* Pi is 3.1415926536
Не очень высокая точность, не правда ли? Вы можете запустить задание ещё раз, увеличив интервал разбиения, скажем до 10 000 000 000. Как вы думаете, надо ли увеличивать количество заданий? На что это повлияет? Какой компромиссный вариант следует выбрать ?
Достаточно просто написать скрипт, который будет будет выполнять все действия, избежав интерактивной работы:
#!/bin/sh AID=`gwsubmit -v -t pi.jt -n 4 | head -1 | awk '{print $3}'` if [ $? -ne 0 ] then echo "Submission failed!" exit 1 fi gwwait -v -A $AID if [ $? -eq 0 ] then awk 'BEGIN {sum=0} {sum+=$1} END {printf "Pi is %0.12g\n", sum}' stdout_file.* else echo "Some tasks failed!" fi
Дополнительная информация
Для получения дополнительной информации посетите сайт документации по GridWay .