удалённый доступ - Томский политехнический университет

advertisement
Федеральное агентство по образованию
Государственное образовательное учреждение высшего
профессионального образования
ТОМСКИЙ ПОЛИТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
Лаборатория мультифизического
моделирования на базе вычислительного
кластера «СКИФ-политех»
Программирование, компиляция и запуск программ с
использованием вычислительного кластера «СКИФ-политех»
Томск 2009
Содержание
Содержание ............................................................................................................ 2
Удалённый доступ ................................................................................................. 3
Введение в ОС UNIX ............................................................................................ 5
Документация ..................................................................................................... 7
Некоторые другие базовые команды ОС Unix ............................................. 10
Обмен данными с кластером .............................................................................. 12
Перекодировка файлов .................................................................................... 12
Передача файлов .............................................................................................. 12
Первая программа в Unix ................................................................................... 15
Создание и редактирование файлов .............................................................. 15
Компиляция и запуск программ ..................................................................... 19
Программирование с использованием MPI ...................................................... 22
Отправка сообщения другому процессу: MPI_Send() ............................. 23
Прием сообщения от другого процесса: MPI_Recv() .............................. 24
Первая программа MPI: скалярное произведение векторов ....................... 24
Запуск параллельных приложений на кластере ............................................... 29
Компиляция программ MPI ............................................................................ 29
Постановка задачи в очередь .......................................................................... 30
Пояснение к системе приоритетов ................................................................. 31
Просмотр результатов ..................................................................................... 31
Просмотр состояния очереди ......................................................................... 37
Удаление задачи ............................................................................................... 37
2
Удалённый доступ
Удаленный доступ к вычислительному кластеру осуществляется через
головную машину комплекса (master.hpc.cctpu.edu.ru, IP-адрес: 109.123.146.178) и
только с тех компьютеров, IP-адреса которых были указаны в заявке при
регистрации (при попытке зайти с неуказанного адреса программа будет долго
ждать и сообщит о потере связи по таймауту). Непосредственный терминальный
доступ на узлы кластера не допускается.
В настоящий момент удаленный терминальный доступ на кластер
осуществляется по протоколу SSH версии 2. На Unix-машинах этот протокол
поддерживается стандартной командой ssh.
Для Windows рекомендуется программа PuTTY. Другие клиентские
программы для Windows, поддерживающие протокол SSH 2 - это SSH Secure Shell
Client и Teraterm последних версий.
Рис. 1. Внешний вид окна настройки программы Putty.
После нажатия кнопки Open откроется окно удалённой командной
оболочки, с приглашением ввода логина и пароля.
3
Рис. 2. Окно приглашения удалённой командной строки.
Обратите внимание, что в Unix-системах вводимые пароли, в отличие от
Windows, не отображаются на экране даже в виде звездочек (клавиша Backspace,
тем не менее, работает), этого не следует пугаться, просто нажмите Enter по
завершению ввода, как обычно. Так сделано затем, чтобы нельзя было узнать хотя
бы длину пароля (даже стуком клавиш можно обмануть, стирая лишние символы).
Программа Putty работает как эмулятор терминала, и поэтому выступает как
комбинация клавиатуры и монитора для удаленной машины. Поэтому многие
привычные комбинации кнопок работать не будут – например, сочетание Ctrl-C
будет передано на удаленную сторону и скорее всего вызовет прерывание работы
текущей программы, а не копирование в буфер обмена, о котором удаленная
сторона ничего не знает, поскольку он находится исключительно на вашей
машине.
Если вы выделите мышью на экране Putty текст, он будет скопирован в
буфер обмена Windows сразу, автоматически, без дополнительных нажатий
клавиш (точно так же ведут себя и все графические программы в Unix). Если Вам
нужно скопировать прямоугольный блок, при выделении зажмите кнопку Alt,
если какая-либо программа захватила управление мышью и выделения не
происходит, зажмите кнопку Shift. Изменить область выделения можно
(например, расширить) можно щелчком средней кнопки мыши. Вставить текст из
буфера обмена Windows в окно Putty можно нажатием правой кнопки мыши (при
этом удаленная сторона по-прежнему ничего не знает о буфере обмена, и считает,
что текст был набран). Следует отметить, что в графических программах Unix
наоборот, правая кнопка мыши используется для расширения выделения, а
средняя – для вставки. Изменить данное поведение можно в категории Selection
настроек Putty.
4
ВВЕДЕНИЕ В ОС UNIX
Установленная на головной машине и всех узлах кластера ОС SUSE Linux
Enterprise Server относится к семейству Unix-подобных систем, берущих начало
от оригинальной версии Unix 1969 года. Предполагается знакомство читателя с
командной строкой DOS или Windows, поскольку основным интерфейсом
управления Unix-системами, достаточным для редактирования текста и запуска
программ, является командная строка. Графический интерфейс предъявляет
повышенные требования к пропускной способности сети для нормальной работы,
используется на нашем кластере только для сторонних пакетов типа Wolfram
Mathematica или Mathlab, и в данном руководстве не рассматривается.
Несмотря на общие корни, командная строка в Unix эволюционировала
более быстро, и кроме имён команд, отличается также в некоторых принципах.
Так, Unix имеет более чем одну консоль, т.е. комбинацию монитор+клавиатура
(устройство con из DOS/Windows), здесь они называются терминалами. Когда
Вы заходите на кластер через сеть, создается виртуальный псевдотерминал
(pseudo tty), поскольку программа PuTTY здесь эмулирует терминал (клавиатуру
и монитор) через сеть. После входа вы попадаете в командный интерпретатор, так
называемую оболочку (shell), которая является родителем всех своих дочерних
процессов, после выхода из него терминал уничтожаются, и все привязанным к
нему программам будет послан сигнал завершения, если они еще не успели
сделать это до того. Здесь более широко, чем в DOS/Windows, используются
понятия стандартных файлов ввода (stdin), вывода (stdout) и стандартного файла
ошибок (stderr), поскольку программы не имеют прямого доступа к монитору,
поэтому более широко используются перенаправления ввода-вывода, например
cmd > file.txt или cmd1 | cmd2, при этом, в силу многозадачности,
программы (процессы) работают одновременно.
В дальнейших примерах мы будем показывать вводимый пользователем
текст полужирным шрифтом. Аналогично выводу в DOS строки типа C:\>
перед каждой командой, оболочка Unix тоже показывает своё приглашение:
test@master:~/my_progs> ls
scalar
scalar.out-212 scalar.out-220 scalar.rep-208
scalar.c
scalar.out-213 scalar.out-274 scalar.rep-212
scalar.c~
scalar.out-214 scalar.out-276 scalar.rep-213
scalar.o
scalar.out-215 scalar.out-279 scalar.rep-214
scalar.out-205 scalar.out-216 scalar.out-287 scalar.rep-215
scalar.out-206 scalar.out-217 scalar.rep-205 scalar.rep-216
scalar.out-207 scalar.out-218 scalar.rep-206 scalar.rep-217
scalar.out-208 scalar.out-219 scalar.rep-207 scalar.rep-218
test@master:~/my_progs> pwd
/home/test/my_progs
test@master:~/my_progs> cd ..
test@master:~> pwd
/home/test
test@master:~> cd my_progs
test@master:~/my_progs> ls -l
total 212
-rwxr-xr-x 1 test users 13753 Mar 20 2007 scalar
-rw-r--r-- 1 test users 2257 Mar 20 2007 scalar.c
scalar.rep-219
scalar.rep-220
scalar.rep-274
scalar.rep-276
scalar.rep-279
scalar.rep-287
5
-rw-r--r--rw-r--r--rw-r--r--rw-r--r--
1
1
1
1
test
test
test
test
users
users
users
users
2260
5464
0
0
Mar
Mar
Mar
Mar
20
20
20
20
2007
2007
2007
2007
scalar.c~
scalar.o
Makefile
mAKEFILe
Из этого примера уже можно видеть несколько базовых команд Unix:
 ls – показать список файлов в текущем каталоге
 pwd – показать полный путь текущего каталога (print working directory),
полезно, если Вы забыли где находитесь (приглашение оболочки не
всегда бывает настроено так, чтобы отображать текущий каталог)
 cd или chdir – сменить текущий каталог (как и в DOS)
Кроме того, видны и особенности системы, например, что в приглашении
отображается имя пользователя (test) на головной машине (master), и текущий
путь относительно домашнего каталога пользователя, который в Unix по
соглашению часто обозначают одним символом тильды (~). Видно также то, что
в Unix опции команд указывают через минус: ls -l показывает список в
длинном (long) формате, включающем размеры файлов, даты модификации и т.д.
Еще можно заметить, что в Unix имеет значение регистр имени файла – в
Windows бы регистр имени файла Makefile бы сохранился, в отличие от DOS,
но создать файл mAKEFILe система бы уже не дала.
Однако наиболее важным видным здесь отличием является то, что в Unix
нет отдельных дисков и их букв (C:, D:, …), а есть единый корневой каталог,
обозначаемый просто /, и все пути отсчитываются от него, разделителем
каталогов является тоже прямой слэш (/) вместо обратного (\) из DOS и Windows.
Различные физические диски просто монтируются (mount) в произвольную
точку общего дерева каталогов, что заметно, например, в выводе команды
отображения свободного места на дисках (по умолчанию в килобайтах):
test@master:~/my_progs> df
Filesystem
1K-blocks
Used Available
/dev/sda2
165140368
91625316
65126312
udev
4089704
132
4089572
/dev/sda4
30211520
15328
30196192
panfs://192.168.10.252/data 4271186424 3269816068 1001370356
panfs://192.168.10.252/khav 488281248
3508
88277740
Use%
59%
1%
1%
77%
1%
Mounted on
/
/dev
/boot
/panasas
/share/khav
Другим важным отличием командной оболочки Unix является то, что shell
на самом деле представляет собой полноценный язык программирования, и имеет
свои синтаксические особенности и предобработку, не выполняя набранное
просто «как есть». Так, символы шаблонов ? и * здесь обрабатывает сама
оболочка, и когда Вы в нижеследующем примере набираете один аргумент, в
программу на самом деле будут переданы три, что следует иметь в виду при
программировании (однако, это избавляет Вас от работы по ручной обработке
шаблонов):
test@master:~/my_progs> ls -l
-rw-r--r-- 1 test 600 270 Mar
-rw-r--r-- 1 test 600 269 Mar
-rw-r--r-- 1 test 600 270 Mar
scalar.rep-27*
26 2007 scalar.rep-274
26 2007 scalar.rep-276
26 2007 scalar.rep-279
6
test@master:~/my_progs> echo ~
/home/test
test@master:~/my_progs> ls -l scalar.rep-27[46]
-rw-r--r-- 1 test 600 270 Mar 26 2007 scalar.rep-274
-rw-r--r-- 1 test 600 269 Mar 26 2007 scalar.rep-276
test@master:~/my_progs> ls -l scalar.[ro][eu][pt]-20*
-rw------- 1 test 600 13956 Mar 20 2007 scalar.out-205
-rw------- 1 test 600 2372 Mar 20 2007 scalar.out-206
-rw------- 1 test 600 10200 Mar 20 2007 scalar.out-207
-rw------- 1 test 600
804 Mar 20 2007 scalar.out-208
-rw-r--r-- 1 test 600 1183 Mar 20 2007 scalar.rep-205
-rw-r--r-- 1 test 600
411 Mar 20 2007 scalar.rep-206
-rw-r--r-- 1 test 600
935 Mar 20 2007 scalar.rep-207
-rw-r--r-- 1 test 600
355 Mar 20 2007 scalar.rep-208
test@master:~/my_progs> ls -l scalar.out-21?
-rw------- 1 test 600 2808 Mar 20 2007 scalar.out-212
-rw------- 1 test 600 2527 Mar 20 2007 scalar.out-213
-rw------- 1 test 600 1956 Mar 20 2007 scalar.out-214
-rw------- 1 test 600 2517 Mar 20 2007 scalar.out-215
-rw------- 1 test 600 1710 Mar 20 2007 scalar.out-216
-rw------- 1 test 600 2515 Mar 20 2007 scalar.out-217
-rw------- 1 test 600 1651 Mar 20 2007 scalar.out-218
-rw------- 1 test 600 13461 Mar 20 2007 scalar.out-219
test@master:~/my_progs> ls -l scalar.out-21[4-8]
-rw------- 1 test 600 1956 Mar 20 2007 scalar.out-214
-rw------- 1 test 600 2517 Mar 20 2007 scalar.out-215
-rw------- 1 test 600 1710 Mar 20 2007 scalar.out-216
-rw------- 1 test 600 2515 Mar 20 2007 scalar.out-217
-rw------- 1 test 600 1651 Mar 20 2007 scalar.out-218
test@master:~/my_progs> ls -l scalar.out-21[^4-8]
-rw------- 1 test 600 2808 Mar 20 2007 scalar.out-212
-rw------- 1 test 600 2527 Mar 20 2007 scalar.out-213
-rw------- 1 test 600 13461 Mar 20 2007 scalar.out-219
В этом примере можно увидеть, что оболочка в Unix умеет также еще один
вид символов шаблонов – перечисление символов в квадратных скобках. Работает
это аналогично символу ?, означающему «любой символ», но здесь символ будет
не абсолютно любым, а ограничен набором из перечисленных. Как видно из
примера, перечисления можно задавать через диапазон, можно задавать и
отрицание символом ^ в начале перечисления, означающим «любой символ не из
указанного набора».
Документация
Unix предоставляет систему документации, доступную непосредственно в
командной строке, так называемый online manual, оперативный справочник.
Документация по каждой команде, а зачастую и не только команде, доступна в
соответствующей так называемой man-странице (сокращение от manual,
руководство), странице справочника. Вызывается он командой man с указанием
имени страницы, которую следует показать. Следует заметить, что это именно
справочник, а не учебник, и он предполагает, что знание фундаментальных вещей
уже присутствует.
В документации по Unix приняты несколько соглашений. Рассмотрим их на
примере первых строк двух страниц справочника:
7
test@master:~> man free
FREE(1)
Linux User's Manual
FREE(1)
NAME
free - Display amount of free and used memory in the system
SYNOPSIS
free [-b | -k | -m] [-o] [-s delay ] [-t] [-V]
DESCRIPTION
free displays the total amount of free and used physical and swap memory in the system, as well as the buffers used by the kernel.
...
test@master:~> man gzip
GZIP(1)
GZIP(1)
NAME
gzip, gunzip, zcat - compress or expand files
SYNOPSIS
gzip [ -acdfhlLnNrtvV19 ] [-S suffix] [ name ... ]
gunzip [ -acfhlLnNrtvV ] [-S suffix] [ name ... ]
zcat [ -fhLV ] [ name ... ]
DESCRIPTION
Gzip reduces the size of the named files using Lempel-Ziv coding
...
SEE ALSO
znew(1), zcmp(1), zmore(1), zforce(1), gzexe(1), zip(1), unzip(1), compress(1), pack(1), compact(1)
...
Здесь в самом начале и в конце печатается имя страницы справочника и к
какому разделу она относится, затем любая страницы справочника начинается
всегда с одних и тех же разделов:
 NAME – краткое однострочное описание (по нему можно делать поиск)
 SYNOPSIS – краткое описание синтаксиса вызова
 DESCRIPTION – собственно подробное описание команды
После этого может идти разное количество разделов, в зависимости от
сложности той или иной команды. Часто включают раздел EXAMPLES с
примерами запуска для реальных ситуаций, раздел SEE ALSO (“см. также”)
перечисляет ссылки на другие страницы справочника, которые могут быть
интересны по этой теме. В примерах можно видеть основные принятые
соглашения по записи синтаксиса (их будем придерживаться далее и мы):
 В квадратных скобках перечисляются опциональные элементы, то есть
то, что можно опустить.
 Во многих случаях в документации обязательные аргументы
указываются в угловых скобках, вида cmd <arg1> <arg2> - здесь два
обязательных элемента, причем сами угловые скобки писать не надо.
Следует внимательно смотреть на точную форму записи, потому что
если угловые скобки отделены пробелами – это указывает уже на
использование символов перенаправления ввода-вывода оболочки, а не
типографское соглашение. Страницы справочника используют это
8
соглашение редко (обязательные параметры показаны просто как есть),
но оно может попасться в справке самих команд или иной документации.
 Если какие-то элементы взаимоисключают друг друга, они будут
указаны через символ | вертикальной черты.
 Однобуквенные опции-флаги без аргументов, в отличие от документации
DOS, могут быть сокращены до перечисления всех опций разом, то есть
вместо [-a] [-b] [-c] будет написано [-abc].
 Троеточие означает неограниченное повторение элемента, т.е.
[filename] означает одно имя файла, а [filename ...] – любое
количество имён файлов (квадратные скобки указывают, что в обоих
случаях их может быть нулевое количество – т.е. они опциональны).
 Одна man-страница может описывать сразу несколько команд, тогда в
разделе SYNOPSIS будет описано несколько вариантов запуска, для
каждой из команд, либо взаимоисключающие варианты запуска одной
команды.
Система страниц справочника предоставляет возможность поиска по
подстроке в однострочных описаниях страниц командой apropos:
test@master:~> apropos concat
zcat (1p)
- expand and concatenate data
tac (1)
- concatenate and print files in reverse
wcscat (3p)
- concatenate two wide-character strings
ntfscat (8)
- concatenate files and print them on the standard output
cat (1)
- concatenate files and print on the standard output
wcscat (3)
- concatenate two wide-character strings
strcat (3p)
- concatenate two strings
wcsncat (3p)
- concatenate a wide-character string with part of another
strcat (3)
- concatenate two strings
cat (1p)
- concatenate and print files
wcsncat (3)
- concatenate two wide-character strings
strncat (3)
- concatenate two strings
Можно видеть, что ссылки на страницы справочника всегда пишутся как
имя страницы и номер в скобках – это номер раздела справочника. В разных
разделах справочника могут быть страницы с одинаковыми именами, в этом
случае для вызова нужной страницы нужно указать номер раздела перед именем
через пробел (по умолчанию показывается первая найденная страница):
test@master:~> man kill
KILL(1)
User Commands
KILL(1)
NAME
kill - send signals to processes, or list signals
SYNOPSIS
kill [-s SIGNAL | -SIGNAL] PID...
kill -l [SIGNAL]...
kill -t [SIGNAL]...
DESCRIPTION
Send signals to processes, or list signals.
...
9
test@master:~> man 2 kill
KILL(2)
Linux Programmer's Manual
NAME
kill - send signal to a process
KILL(2)
SYNOPSIS
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
DESCRIPTION
The kill() system
group or process.
...
call can be used to send any signal to any process
Из этого примера видно, что страницы справочника существуют не только
для команд оболочки, но и функций установленных библиотек
программирования, и даже совершеннно не про команды (например, страница
regex(7) расскажет вам о синтаксисе регулярных выражений, применяемых во
многих программах Unix). Дальнейшее вы можете узнать с помощью команд:
 man man (справка по самому справочнику)
 man 1 intro
 man 2 intro
 и т.д. по аналогии и ссылкам из прочитанных страниц.
Некоторые другие базовые команды ОС Unix
Помимо уже рассмотренных выше команд, для начальной работы могут
быть необходимы еще несколько:
cp – копировать файлы;
mv – переместить (переименовать) файл;
rm – удалить файл;
chmod – изменить права доступа к файлу (например, сделать исполнимым);
mkdir – создать каталог;
rmdir – удалить (пустой) каталог;
du – посчитать занимаемое подкаталогом (его файлами) место на диске;
touch – создать пустой файл или обновить время модификации файла;
cat – показать файлы на стандартный вывод, можно склеивать файлы;
split – разрезать файлы;
less – пролистать содержимое файла (можно проматывать назад);
head – показать первые несколько строк файла (по умолчанию 10);
tail – показать последние несколько строк файла (по умолчанию 10);
grep – вывести строки из файла, в которых встречается подстрока;
diff – вывести различия между двумя текстовыми файлами;
sort – отсортировать текстовый файл;
bc –калькулятор с произвольной точностью (но медленный);
find – найти файлы по критерию (можно задавать сложные условия);
gzip – сжать файл;
10
tar – создать/распаковать архив нескольких файлов;
ftp – клиент командной строки, позволяющий работать с ftp-сервером;
joe – простой редактор файлов;
vi или vim – мощный редактор файлов, рассчитан на программиста;
exit или logout – выйти из оболочки (отключиться от машины).
Напоминаем, что справку по любой команде можно получить командой
man имя_команды.
Кроме того, на кластере установлен также файловый менеджер mc,
напоминающий Norton Commander или Far Manager, однако обладающий
существенно меньшими возможностями. Он пригоден на начальных этапах
освоения системы (обладает также простым встроенным редактором файлов),
однако для сложных случаев (например, написания скриптов, автоматизирующих
какие-либо задачи) всё равно потребуется знание командной строки и её утилит.
11
ОБМЕН ДАННЫМИ С КЛАСТЕРОМ
Лишь в редких случаях (при малом объеме) расчетная задача на кластере
позволяет создать программный файл целиком с нуля на самом кластере, и
просмотреть результаты на нём же. Скорее всего, Вы захотите передать на
кластер уже имеющиеся у Вас исходные тексты программ расчетов, потом
отредактировать их так, чтобы они могли запускаться в Unix и использовать
многопроцессорную среду, а затем, возможно, забрать с кластера результаты
расчетов для анализа.
Перекодировка файлов
При передаче текстовых файлов из среды Windows следует помнить, что на
Unix используется свое соглашение по символам перевода строки (один символ с
кодом 10, LF), отличное от соглашения в среде DOS/Windows (два символа с
кодами 13, CR, и 10, LF). Если Вы будете компилировать исходные тексты
программ, которые записаны в соглашении DOS/Windows, то Вы можете
получить множество предупреждений или ошибок, видеть в редакторе
непонятные вещи в конце строк (типа ^M), и т.д. На головной машине кластера
установлена утилита перекодировки из формата в DOS в формат Unix –
dos2unix. Верно и обратное – при передаче файлов с Unix на Windows
большинство программ так же не воспримут переводы строк в другом соглашении
(например, «Блокнот» Windows покажет всё в одну строку). В то же время многие
программы Windows умеют открывать такие файлы (например, Wordpad), а
редактор из состава Far Manager делает это автоматически, умея даже сохранять
файлы с переводом строк стиля Unix.
В среде Unix традиционной для русских символов является кодировка KOI8, тогда как в средах DOS и Windows используются свои кодировки (866, 1251,
иногда другие). Для выполнения перекодировки файлов с русскими буквами из
кодировок DOS и Windows в KOI8-R и обратно можно воспользоваться утилитой
iconv, умеющей большое количество разных кодировок, например, команда:
test@master:~/my_progs> iconv -f cp1251 -t koi8-r win-rus.txt > koi-rus.txt
прочитает файл win-rus.txt с русским текстом в кодировке Windows-1251, и
выведет его перекодированным на стандартный вывод, где перенаправление
оболочки запишет его в файл koi-rus.txt (можно перекодировать и в
обратном направлении).
Передача файлов
Передача файлов может осуществляться как с помощью обычного FTP, так
и по протоколу sftp, или копированию поверх протокола ssh.
В случае использования обычного протокола FTP – Вы кладёте файлы на
ftp-сервер, и заходите на него с кластера интерактивным клиентом командной
строки ftp, позволяющим как скачивать, так и закачивать на ftp-сервер файлы
(для автоматизированной скачки с ftp-сервера на кластер большого количества
12
файлов можно также воспользоваться установленной на кластере утилитой
wget). Пользоваться клиентом достаточно просто: он поддерживает команду
help, набрав которую можно получить список его собственных команд; для
соединения с сервером следует воспользоваться командой open, для передачи
файлов – get и put (есть и другие, обратитесь к странице справочника). Кроме
того, ftp-клиент встроен в файловый менеджер mc.
Если же у Вас нет доступного ftp-сервера для временного переброса
данных, придется воспользоваться передачей файлов поверх такого же sshсоединения, что используется и для обычной работы на кластере (что, впрочем,
имеет преимущества в виде шифрования данных, которое, правда, несколько
замедляет их передачу).
В пакет установки ssh-клиента Putty входят программы pscp и psftp,
которые реализуют функции передачи данных, это аналоги команд scp и sftp из
Unix (таким образом, кроме справки Putty, можно воспользоваться страницами
справочника Unix). Заметьте, что в данном случае Вы будете работать в
командной строке своей машины с Windows, а не на кластере! Для копирования
нескольких файлов необходимо запустить программу psftp, далее команды
аналогичны командам стандартного ftp-клиента для Linux:
Рис. 3. Окно программы psftp
Для использования программы pscp необходимо перейти в каталог, в
котором находится программа pscp (либо убедиться, что каталог Putty доступен
в PATH) и выполнить в командной строке Windows:
13
 Для загрузки с кластера:
pscp.exe
<user>@<host>:<source>
<target>
 Для копирования на кластер:
pscp.exe <source> <user>@<host>:<target>
То есть, здесь, как и в обычной команде cp, сначала указывается, что
копировать (откуда), а потом – куда. Например, если у нас логин test, и нам надо
скопировать файл D:\progs\myprog.cpp на кластер в каталог
/home/test/my_progs, то команда будет выглядеть так:
C:\Putty>pscp.exe D:\progs\myprog.cpp test@195.208.174.178:/home/test/my_progs/
после чего команда pscp запросит пароль и затем покажет, как идёт процесс
копирования файла. Имейте ввиду, что Вы также можете воспользоваться
перетаскиванием файла мышью на окно командной строки Windows, вместо
полного набора пути и имени вручную (либо использовать сочетания клавиш Far
Manager, если команда набирается в нём).
14
ПЕРВАЯ ПРОГРАММА В UNIX
Перед тем, как приступать к программированию настоящих параллельных
программ, ознакомимся сначала с созданием обычных однозадачных программ.
Если Вы уже знакомы с программированием в Unix, этот раздел можно смело
пропустить.
Создание и редактирование файлов
Пользовательские директории (вида /home/<имя_пользователя>),
физически размещенные на головной машине, доступны по протоколу NFS на
всех узлах. Это означает, что каталоги /share и /home на каждом узле
смонтированы из одного и того же места, и файл создаваемый на одно узле, будет
сразу же виден на всех остальных. То есть, Вам не требуется в программах
учитывать сетевое взаимодействие, на каждом узле все файлы видны одинаково
по тем же путям, но следует позаботиться о том, чтобы одновременный доступ к
одному и тому же файлу с разных узлов не привел к мешанине в данных. Также
для хранения данных доступна система хранения данных на 5 Тбайт, доступ к ней
открывается по просьбе пользователей – используйте её, если необходима работа
с массивами данных начиная от нескольких гигабайт (пользовательские каталоги
предназначены более для программ, нежели на интенсивную работу с диском).
Кроме того, на каждом узле доступен локальный каталог для временных файлов
(/tmp). На узлах после окончания работы программы временные файлы
необходимо удалять.
Итак, предположим, что Ваш пользователь на кластере только что создан,
никаких данных нет, хотим создать программу с нуля и освоить редактирование
файлов.
test@master:~> mkdir my_progs
test@master:~> cd my_progs/
test@master:~/my_progs> touch hello_args.c
test@master:~/my_progs> ls -l hello*
-rw-r--r-- 1 test users 0 2007-06-19 16:21 hello_args.c
test@master:~/my_progs> vim hello_args.c
В этом примере мы создали подкаталог my_progs, перешли в него и
создали пустой файл hello_args.c и убедились, что он действительно создан.
Разумеется, текстовый редактор мог бы создать новый файл и сам, автоматически,
это просто иллюстрация возможности создания пустых файлов. После этого мы
открываем файл в редакторе Vim. Однако, если Вы ничего не знали о редакторе
Vim ранее и запускаете его впервые в жизни, Вы будете удивлены, что он
работает странным образом. Например, если Вы открыли уже существовавший
файл, можно заметить, что курсор передвигается, но текст не вводится, иногда
могут случаться странные эффекты, и более всего непонятно, как из всего этого
выйти, чтоб запортившие файл изменения – не сохранились (ибо на стандартное
сочетание клавиш Ctrl-C он тоже не хочет реагировать).
15
Так происходит потому, что редактор Vim, как потомок редактора Vi,
существующего нынче практически во всех системах семейства Unix, сохраняет
все его основные свойства и концепции, добавляя лишь новые возможности,
вроде подсветки синтаксиса, многооконности, и т.д., которые по умолчанию,
впрочем, отключены – vim ведёт себя как обычный vi. А сам же редактор Vi был
создан почти 30 лет назад, во времена, когда на клавиатуре было меньше клавиш,
и стояла задача как можно сильнее сократить число необходимых нажатий на
клавиши, чтобы работа человека шла быстрее. Поэтому в нём, в отличие от
обыкновенных редакторов, в которых нажатия вводят непосредственно текст, а
команды редактирования применяются нажатиями сочетаний с кнопками Alt,
Shift и Ctrl, существуют два режима: командный режим и режим ввода текста.
Одни и те же кнопки по-разному работают в зависимости от режима: в режиме
ввода они собственно вводят текст, в командном режиме – производят с ним
операции. По умолчанию после запуска редактор находится в командном режиме,
в режим ввода надо специально переключиться, нажав кнопку i, ввести текст,
нажать Esc, чтобы вернуться в командный режим. На первый взгляд может
показаться, что наличие двух режимов лишь замедляет работу, однако это не так –
после некоторого периода обучения при должной сноровке работа станет быстрее,
чем в традиционных редакторах.
В командном режиме есть два типа нажатий – обычные клавиши, например,
нажатие w переместит курсор на одно слово вперёд, нажатие x удалит символ под
курсором, и т.д., и специальная кнопка : (двоеточие), при нажатии которой
курсор перемещается в строку ввода команд, и там уже набираются слова по
аналогии с командной строкой (вообще, в Unix регистр имеет значение, то есть,
если говорится нажать D, это не то же самое, что нажать d – то есть, надо на
самом деле нажать Shift-d; в данном случае это нажатие Shift и кнопки “;”, а для
нажатия % (кнопка перемещения на парную скобку) надо нажать Shift-5). Так, для
сохранения файла нужно в командном режиме ввести :write, для выход :quit,
причем эти команды можно сокращать до:w и :q соответственно; если у вас есть
несохраненные изменения, редактор не даст это сделать, потребуется выйти без
сохранения командой :q! (восклицательный знак на конце форсирует
применение команды и в некоторых других случаях).
Преимущества командного режима начинают проявляться тогда, когда Вы
начинаете пользоваться возможностями повторения команд. Так, практически все
однобуквенные команды позволяют перед ними нажать цифры, введя число
повторений. Если w переместит курсор на одно слово вперёд, а j перемещает
курсор на одну строку вниз, то нажатие 10w переместит курсор на 10 слов вперед,
а нажатие 45j – на 45 строк вниз. Нажатие G переместит курсор в конец файла, а
237G – на 237 строку файла. Кроме того, редактор запоминает последнюю
операцию командного режима, и позволяет повторить её одним нажатием .
(точки) – при этом вход в режим ввода, набор и выход обратно в командный
режим рассматриваются как одна операция, поэтому можно ввести слово на
16
одной строке, потом подводить курсор к нужным местам, нажимать точку, и оно
будет вставляться в эти места.
Чтобы освоить редактор vim, существует интерактивный курс – команда
vimtutor скопирует специальную заготовку во временный файл (так что можно
редактировать его прямо там, не боясь испортить), и покажет учебник на родном
русском языке (если это не так, обратитесь к администратору). После освоения
учебника Вы будете знать достаточно, чтобы уверенно пользоваться vim для
основных задач редактирования, кроме того, в нём показано, как подключить
стандартный набор настроек vim, делающих редактирование более удобным – в
частности, подсветку синтаксиса. Кроме того, существует множество других
команд, позволяющих сделать жизнь более удобной, вроде включения поддержки
мыши, позволяющей более удобно переключаться между окнами :split, но это
выходит уже за рамки базового курса. На рисунке показано, как выглядит окно с
запущенным редактором vim и исходным текстом программы scalar
(рассмотренной далее) при включенной подсветке синтаксиса:
Рис. 4 Внешний вид кода программы в редакторе VIM.
Рис. 4. Окно vim с цветовой подсветкой синтаксиса языка Си.
На текущий же момент введём очень простую программу, но немного
отступим от традиции “Hello, World!” – пусть программа дополнительно покажет
и те аргументы командной строки, с которыми её запустили:
17
test@master:~/my_progs> cat hello_args.c
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
printf("Hello, World! My arguments are:\n");
for (i = 0; i < argc; i++)
printf("argv[%d]: %s", i, argv[i]);
return 0;
}
18
Компиляция и запуск программ
Теперь
необходимо
скомпилировать
программу.
Наиболее
распространенным в наше время на Unix-системах является компилятор GNU
GCC, хотя существуют и другие, например, на нашем кластере установлен также
коммерческий компилятор ICC фирмы Intel, отличающийся высокой степенью
оптимизации генерируемого машинного кода для процессоров этой фирмы.
Компиляция одного файла очень проста:
test@master:~/my_progs> gcc hello_args.c
test@master:~/my_progs> ls -l
-rwxr-xr-x 1 test users 9108 2007-06-19 16:44 a.out
-rw-r--r-- 1 test users
190 2007-06-19 16:21 hello_args.c
Заметим, что мы не указали имя выходного файла, в таких случаях по
историческим причинам компилятор создает исполняемый файл с именем a.out.
Также заметим, что в Unix-системах исполняемые файлы не отличаются какимлибо специфическим расширением имени файла (системе, в отличие от
DOS/Windows, они безразличны, они лишь для человека), вместо этого
исполнимость файла определяется его правами – если на файле установлен бит +x
(executable), то ядро попытается его исполнить. В данном случае, как показывает
листинг, компилятор уже автоматически установил этот бит. Кроме того, в
отличие от DOS/Windows, исполняемые файлы ищутся лишь в путях, заданных
переменной PATH, но не в текущем каталоге, поэтому при попытке запуска
просто по имени файла мы получим сообщение ошибки от оболочки, и надо будет
указать нахождение файла в текущем каталоге:
test@master:~/my_progs> a.out
-bash: a.out: command not found
test@master:~/my_progs> ./a.out
Hello, World! My arguments are:
argv[0]: ./a.outtest@master:~/my_progs> ./a.out test
Hello, World! My arguments are:
argv[0]: ./a.outargv[1]: testtest@master:~/my_progs>
В этом примере видно, что наша программа работает, но имеет очевидную
логическую ошибку – печать идёт без переводов новых строк, в результате строки
склеивается и вывод выглядит плохо читаемым. Откроем редактор vim и увидим,
что мы забыли вставить символ перевод строки в вызов функции печати. Сделаем
это. Теперь перекомпилируем программу – компилятор автоматически
перезапишет выходной файл:
test@master:~/my_progs> gcc hello_args.c
test@master:~/my_progs> ls -l
-rwxr-xr-x 1 test users 9108 2007-06-19 17:46 a.out
-rw-r--r-- 1 test users
192 2007-06-19 17:45 hello_args.c
-rw-r--r-- 1 test users
190 2007-06-19 16:21 hello_args.c~
Кроме того, если Вы настроили редактор vim так, как описано в
предыдущем разделе, предыдущая версия файла будет сохранена как резервная
19
копия с приписанным к именем символом тильды (~) – в DOS/Windows в таком
случае было бы приписано расширение .bak. Хранение предпоследних версий
может быть удобно, если Вы редко возвращаетесь к программе и не помните,
какой была последняя правка. В этом случае на помощь придёт утилита diff:
test@master:~/my_progs> diff hello_args.c~ hello_args.c
9c9
<
printf("argv[%d]: %s", i, argv[i]);
-->
printf("argv[%d]: %s\n", i, argv[i]);
test@master:~/my_progs> diff -u hello_args.c~ hello_args.c
--- hello_args.c~
2007-06-19 16:21:47.000000000 +0700
+++ hello_args.c
2007-06-19 17:45:45.000000000 +0700
@@ -6,7 +6,7 @@
printf("Hello, World! My arguments are:\n");
for (i = 0; i < argc; i++)
printf("argv[%d]: %s", i, argv[i]);
printf("argv[%d]: %s\n", i, argv[i]);
+
return 0;
}
Вывод утилиты diff идет в машиночитаемом формате – возможно
автоматическое применение её результатов, называемых патчами (заплатками),
утилитой patch (чтобы из старого файла и присланного патча получить новую
версию, как говорят, пропатчить файл). Поэтому по умолчанию вывод не очень
информативен, если же указать ключ -u (unified diff), он станет более понятен
человеку – удаленные строки показаны с минусом, добавленные – с плюсом,
кроме того, показано некоторое количество неизмененных строк контекста.
В повседневном применении, однако, имя файла a.out мало кого устроит,
поэтому скомпилируем программу с указанием имени выходного файла,
скопируем дополнительные файлы в каталог и посмотрим, каким именно образом
оболочка раскрывает шаблоны имени файлов в аргументы запускаемой
программе:
test@master:~/my_progs>
test@master:~/my_progs>
total 244
-rwxr-xr-x 1 test users
-rwxr-xr-x 1 test users
-rw-r--r-- 1 test users
-rw-r--r-- 1 test users
-rwxr-xr-x 1 test users
-rw-r--r-- 1 test users
-rw-r--r-- 1 test users
-rw-r--r-- 1 test users
-rw------- 1 test
600
-rw------- 1 test
600
-rw------- 1 test
600
-rw------- 1 test
600
-rw------- 1 test
600
-rw------- 1 test
600
-rw------- 1 test
600
-rw------- 1 test
600
gcc -o hello_args hello_args.c
ls -l
9108
9108
192
190
13753
2257
2260
5464
2808
2527
1956
2517
1710
2515
1651
13461
2007-06-19
2007-06-25
2007-06-19
2007-06-19
2007-03-20
2007-03-20
2007-03-20
2007-03-20
2007-03-20
2007-03-20
2007-03-20
2007-03-20
2007-03-20
2007-03-20
2007-03-20
2007-03-20
17:46
15:56
17:45
15:23
09:43
09:43
09:43
09:43
10:38
10:39
10:40
11:17
11:20
11:24
11:25
11:26
a.out
hello_args
hello_args.c
hello_args.c~
scalar
scalar.c
scalar.c~
scalar.o
scalar.out-212
scalar.out-213
scalar.out-214
scalar.out-215
scalar.out-216
scalar.out-217
scalar.out-218
scalar.out-219
20
-rw------- 1 test
600 13955 2007-03-20 11:55 scalar.out-220
-rw------- 1 test
600
146 2007-03-26 16:10 scalar.out-274
-rw------- 1 test
600
144 2007-03-26 16:12 scalar.out-276
-rw------- 1 test
600
146 2007-03-26 16:18 scalar.out-279
-rw------- 1 test
600
904 2007-03-26 16:28 scalar.out-287
-rw-r--r-- 1 test
600
441 2007-03-20 10:39 scalar.rep-212
-rw-r--r-- 1 test
600
425 2007-03-20 10:39 scalar.rep-213
-rw-r--r-- 1 test
600
388 2007-03-20 10:40 scalar.rep-214
-rw-r--r-- 1 test
600
421 2007-03-20 11:18 scalar.rep-215
-rw-r--r-- 1 test
600
457 2007-03-20 11:20 scalar.rep-216
-rw-r--r-- 1 test
600
421 2007-03-20 11:24 scalar.rep-217
-rw-r--r-- 1 test
600
448 2007-03-20 11:25 scalar.rep-218
-rw-r--r-- 1 test
600 1210 2007-03-20 11:26 scalar.rep-219
-rw-r--r-- 1 test
600 1185 2007-03-20 11:55 scalar.rep-220
-rw-r--r-- 1 test
600
270 2007-03-26 16:10 scalar.rep-274
-rw-r--r-- 1 test
600
269 2007-03-26 16:12 scalar.rep-276
-rw-r--r-- 1 test
600
270 2007-03-26 16:19 scalar.rep-279
-rw-r--r-- 1 test
600
311 2007-03-26 16:28 scalar.rep-287
test@master:~/my_progs> ./hello_args arg1 arg2
Hello, World! My arguments are:
argv[0]: ./hello_args
argv[1]: arg1
argv[2]: arg2
test@master:~/my_progs> ./hello_args scalar.out-21*
Hello, World! My arguments are:
argv[0]: ./hello_args
argv[1]: scalar.out-212
argv[2]: scalar.out-213
argv[3]: scalar.out-214
argv[4]: scalar.out-215
argv[5]: scalar.out-216
argv[6]: scalar.out-217
argv[7]: scalar.out-218
argv[8]: scalar.out-219
test@master:~/my_progs> ./hello_args scalar.*-2[78]?
Hello, World! My arguments are:
argv[0]: ./hello_args
argv[1]: scalar.out-274
argv[2]: scalar.out-276
argv[3]: scalar.out-279
argv[4]: scalar.out-287
argv[5]: scalar.rep-274
argv[6]: scalar.rep-276
argv[7]: scalar.rep-279
argv[8]: scalar.rep-287
test@master:~/my_progs> ./hello_args s1 "Строка с пробелами" arg3 one\ more arg5
Hello, World! My arguments are:
argv[0]: ./hello_args
argv[1]: s1
argv[2]: Строка с пробелами
argv[3]: arg3
argv[4]: one more
argv[5]: arg5
Здесь наглядно видно, что специальные символы в командной строке
обрабатывает оболочка, и Вам, в отличие от DOS/Windows, не требуется
обрабатывать их вручную, или заботиться о разделителях – а просто использовать
передаваемые для обработки аргументы.
21
Программирование с использованием MPI
Стандарт MPI, Message Passing Interface, описывает более 120
библиотечных функций, которые могут быть использованы в параллельных
программах на кластерах. Разумеется, это очень обширная тема, и лучше всего
освещена в специализированных руководствах и книгах (часть из них есть даже
на нашем сайте, http://cluster.tpu.ru), как, собственно, и само параллельное
программирование – это целый отдельный мир. Однако в минимальном
применении можно обойтись достаточно простым набором из менее чем десятка
функций. Поэтому мы ограничимся лишь очень кратким введением в эту тему, и
дадим в качестве примера одну работающую программу, дающую представление
о практическом использовании MPI и нескольких основных функциях,
необходимых для работы.
Модель использования MPI предполагает, что на кластере для решения
задачи программа запускается в нескольких копиях (их число задается при
запуске). Каждая имеет для простоты только один поток вычисления, и даже если
другой процесс находится на том же вычислительном узле (а обычно каждый узел
имеет несколько процессоров, то есть способен выполнять несколько процессов),
всё равно общение с другими процессами происходит только через посылку
сообщений MPI – библиотека сама выберет наиболее оптимальный способ
доставки. Еще раз подчеркнем, что все копии программы (процессы),
запускаемые на кластере – идентичны, это один и тот же код вашей программы,
он будет одинаков везде. MPI, однако, присваивает каждому процессу номер
(начиная с нуля), называемый также рангом (rank) процесса, и по этому рангу Вы
можете отличить процессы внутри себя друг от друга, организовав там, где надо,
соответствующие ветвления, а где не надо, оставив абсолютно одинаковый код
для вычислений.
Кроме того, MPI позволяет организовать деление процессов на группы,
упоминаемые в функциях сокращением comm (коммуникаторы), однако в нашем
примере мы обойдемся всегда существующим по умолчанию коммуникатором
MPI_COMM_WORLD, включающим в себя все запущенные копии программы (на
самом деле, ранг – это номер процесса для коммуникатора, если Вы будете
создавать свои собственные коммуникаторы, следует иметь это ввиду).
Имена всех констант и функций MPI начинаются с префикса MPI_, и для их
использования следует подключить заголовочный файл mpi.h. Компиляция
программ MPI требует подключения соответствующих библиотек, однако для
пользователя существуют команды-обертки, скрывающие этот процесс
(подробнее рассмотрено в следующем разделе).
Главное, что следует помнить – все вызовы функций MPI могут
происходить только между вызовами MPI_Init() и MPI_Finalize(), причем
к моменту вызова последней все операции с пересылкой данных должны быть
завершены. Кроме того, хотя операции пересылки сообщений и представляют
22
собой способ синхронизации между процессами, отправка данных (возврат из
функции посылки) не гарантирует того, что процесс-получатель принял эти
данные или хотя бы даже начал операцию приема (если это возможно по смыслу
конкретной операции MPI). Всё, что имеет значение – это порядок операций
посылки и приёма, но поскольку жесткий порядок не всегда удобен, MPI
предоставляет вводить уникальные идентификаторы сообщений (msg tag) для
отправки и приема (числа в диапазоне от 0 до 32767). Если процесс ожидает
несколько сообщений на прием с разными идентификаторами, процесс может
выбрать, с каким из них принять сообщение. В простых программах это часто не
требуется, тогда можно использовать один идентификатор на все сообщения, и
они будут приниматься просто по порядку.
Отправка сообщения другому процессу: MPI_Send()
int
MPI_Send(void*
buf,
int
count,
MPI_Datatype
datatype, int dest, int msgtag, MPI_Comm comm)
 buf – адрес начала буфера посылки сообщения (например, массива)
 count – число передаваемых элементов в сообщении
 datatype – тип передаваемых элементов массива
 dest – номер процесса-получателя
 msgtag – идентификатор сообщения
 comm – идентификатор группы
Блокирующая посылка сообщения с идентификатором msgtag, состоящего
из count элементов типа datatype, процессу с номером dest. Все элементы
сообщения расположены подряд в буфере buf. Значение count может быть
нулем (или единицей, если вы хотите передать одну переменную, а не массив).
Тип передаваемых элементов datatype должен указываться с помощью
предопределенных констант типа, например MPI_DOUBLE для типа double или
MPI_INT для типа int. Разрешается передавать сообщение самому себе.
Блокировка гарантирует корректность повторного использования всех
параметров после возврата из подпрограммы - то есть, программа будет
остановлена (заблокирована) до тех пор, пока функция не завершится. Выбор
способа осуществления этой гарантии: копирование в промежуточный буфер или
непосредственная передача процессу dest, остается за MPI. Следует специально
отметить, что возврат из подпрограммы MPI_Send() не означает ни того, что
сообщение уже передано процессу dest, ни того, что сообщение покинуло
процессорный элемент, на котором выполняется процесс, выполнивший
MPI_Send().
23
Прием сообщения от другого процесса: MPI_Recv()
int
MPI_Recv(void*
buf,
int
count,
MPI_Datatype
datatype, int source, int msgtag, MPI_Comm comm, MPI_Status
*status)
 buf – адрес начала буфера, в который будет записано принятое
сообщение
 count – максимальное число элементов в принимаемом сообщении
 datatype – тип элементов принимаемого сообщения
 source – номер процесса-отправителя
 msgtag – идентификатор принимаемого сообщения
 comm – идентификатор группы
 status – сюда будут записаны параметры принятого сообщения
Прием сообщения с идентификатором msgtag от процесса source с
блокировкой (если нет входящих сообщений, программа будет остановлена до тех
пор, пока какой-либо процесс не пришлет сообщение). Число элементов в
принимаемом сообщении не должно превосходить значения count. Если число
принятых элементов меньше значения count, то гарантируется, что в буфере
buf изменятся только элементы, соответствующие элементам принятого
сообщения. Если нужно узнать точное число элементов в сообщении, то можно
воспользоваться подпрограммой MPI_Probe().
Блокировка гарантирует, что после возврата из подпрограммы все элементы
сообщения приняты и расположены в буфере buf – если нет входящих
сообщений, программа будет остановлена до тех пор, пока не придет сообщение,
удовлетворяющее заданным идентификаторам.
В качестве номера процесса-отправителя можно указать предопределенную
константу MPI_ANY_SOURCE – признак того, что подходит сообщение от любого
процесса. В качестве идентификатора принимаемого сообщения можно указать
константу MPI_ANY_TAG – признак того, что подходит сообщение с любым
идентификатором.
Если процесс посылает два сообщения другому процессу и оба эти
сообщения соответствуют одному и тому же вызову MPI_Recv(), то первым
будет принято то сообщение, которое было отправлено раньше.
В параметр status будут записаны атрибуты сообщения – номера
процессов отправки и получения, и код ошибки, который в нетривиальных
программах стоит проверять.
Первая программа MPI: скалярное произведение векторов
Наша первая программа будет вычислять скалярное произведение двух
длинных векторов. Как известно из математики, скалярное произведение двух
векторов есть сумма произведений пар значений каждого вектора. Но что, если
количество данных в векторах очень большое, например, несколько миллионов
значений? Очевидно, что вычисление произведения каждой пары – не зависит от
24
других пар, и это можно делать параллельно на разных узлах, таким образом
ускорив работу. Более того, каждый узел может просуммировать свою часть
произведений, таким образом, для получения финального результата нужно будет
просто получить сумму результатов каждого процесса, а не сумму всех тех
миллионов пар, что гораздо дольше. Итак, текст программы:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
test@master:~/my_progs> cat scalar.c
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <signal.h>
#define MYTAG 1
int myid, j;
char
processor_name[MPI_MAX_PROCESSOR_NAME];
double startwtime = 0.0, endwtime;
int main(int argc, char *argv[])
{
int
total, n, numprocs, i, dest;
double *a, *b, sum, result;
int
namelen;
MPI_Status status;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
MPI_Get_processor_name(processor_name, &namelen);
if (myid == 0) {
if (argc != 2) {
printf("Usage: %s <length of vector>\n", argv[0]);
exit(1);
}
total = atoi(argv[1]);
}
printf("Process %d of %d is on %s\n",
myid, numprocs, processor_name);
/*if (myid == 0)*/
startwtime = MPI_Wtime();
if (myid == 0)
n = total / numprocs + 1;
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);
a = malloc(n*sizeof(double));
b = malloc(n*sizeof(double));
if ((a == NULL) || (b == NULL)) {
fprintf(stderr,"Error allocating vectors (not enough memory?)\n");
exit(1);
}
if (myid == 0) {
for (dest=1; dest < numprocs; dest++) {
for (i=0; i < n; i++) {
a[i] = rand();
25
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
b[i] = rand();
}
MPI_Send(a, n, MPI_DOUBLE, dest, MYTAG, MPI_COMM_WORLD);
MPI_Send(b, n, MPI_DOUBLE, dest, MYTAG, MPI_COMM_WORLD);
}
n = total - n*(numprocs-1);
for (i=0; i < n; i++) {
a[i] = rand();
b[i] = rand();
}
} else {
MPI_Recv(a, n, MPI_DOUBLE, 0, MYTAG, MPI_COMM_WORLD, &status);
MPI_Recv(b, n, MPI_DOUBLE, 0, MYTAG, MPI_COMM_WORLD, &status);
}
printf("Process %d on node %s starting calc at %f sec\n",
myid, processor_name, MPI_Wtime()-startwtime);
sum = 0.0;
for (i=0; i<n; i++)
sum += a[i]*b[i];
printf("Process %d on node %s ending calc at %f sec\n",
myid, processor_name, MPI_Wtime()-startwtime);
MPI_Reduce(&sum, &result, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
if (myid == 0) {
endwtime = MPI_Wtime();
printf("Answer is %.16f\n", result);
printf("wall clock time = %f\n", endwtime-startwtime);
fflush(stdout);
}
MPI_Finalize();
return 0;
}
Разберем подробнее, что делает эта программа. В строках 1-18 мы
подключаем нужные заголовочные файлы, объявляем константу MYTAG, равную
единице, объявляем переменные нужных типов. В строке 20 мы инициализируем
подсистему MPI. В строках 21-23 мы получаем от подсистемы MPI параметры
нашего запуска: в переменной numprocs мы получим общее количество
запущенных процессов (поскольку получаем число процессов в глобальной
группе MPI_COMM_WORLD, которая включает в себя все процессы); в переменной
myid мы получаем ранг нашего конкретного процесса, и в переменной
processor_name – имя узла (на одном узле может быть запущено несколько
процессов, по числу ядер).
В строках 25-31 мы проверяем ранг нашего процесса – поскольку мы
выбрали, что процесс с рангом 0 будет «управляющим», этот кусок кода
исполнится только на нём. Сама же эта часть получает единственный аргумент
командной строки – длину векторов, печатая сообщение об ошибке, если
программа запущена без аргументов. Длина вектора из строкового представления
преобразуется в число и записывается в переменную total.
В строках 32-33 каждый процесс напечатает на стандартный вывод
сведения о себе – ранг и имя узла. В строке 37 каждый процесс (если снять
26
комментарий в строке 36, то будет лишь нулевой) запоминает текущее
астрономическое время (wall clock time) от момента начала старта подсистемы
MPI. Эта процедура необязательна, нам просто интересно, как долго будут
считать процессы.
В строке 40 мы вычисляем n, длину отрезка вектора, которую будет
использовать каждый процесс, причем делаем это так, чтобы оно было немного
больше нужного – поскольку остаток чуть меньшего размера мы будем считать в
управляющем процессе (не простаивать же ему, но и учесть, что у него немного
больше работы на управление). Далее в строке 41 мы демонстрируем
использование функции MPI_Bcast() – широковещательная рассылка, все
процессы получают в переменную n то значение, которое вычислил нулевой
процесс (в аргументе, задающем имя отправителя, мы ставим 0). На самом деле
очевидно, что в данном случае вместо строк 39-41 это число просто мог
вычислить каждый процесс, формула очень проста – но целью стоит
продемонстрировать как можно больше функций, каких только можно включить
даже в простую программу. В реальной жизни вычисление может оказаться
длительным, и его делает один процесс, пока остальные могут заняться чем-то
еще, а он потом передаст им результат для следующего этапа.
Далее в строках 43-49 мы выделяем у операционной системы память для
двух векторов, указанного числа элементов типа double (вещественных чисел
двойной точности) в каждом. Заметим, что эта память выделяется в каждом из
процессов, и поскольку n было подобрано таким, чтобы быть чуть больше
необходимого, процессу с номером 0 этого объема тоже хватит, нет нужды писать
дополнительную обработку номера ранга. Особое внимание следует обратить на
строки 36-49 – это проверка ошибки от операционной системы. Аппаратные
возможности кластера велики, но не безграничны, и пользователь мог задать
настолько большое значение длины вектора, что оно не влезет в память одного
процесса даже с учетом того, что один процесс выделяет и обрабатывает не весь
вектор, а лишь его часть.
В строках 51-68 демонстрируется основное применение MPI – пересылка
данных между процессами. Строки 51-64 исполняются на управляющем процессе,
а строки 65-68 – на каждом из остальных. Поскольку это демонстрационная
программа, данные здесь не являются реальными – в строках 52-59 мы заполняем
каждый вектор случайными числами и отсылаем очередному процессу. Каждый
процесс в строках 65-68 принимает свою часть вектора и сразу после этого
начинает работать дальше – процессы ожидают возврата из MPI_Recv() до
реального прихода сообщения. В строках же 60-64 управляющий процесс
вычисляет длину остатка вектор для самого себя.
В строках 73-75 происходит собственно реальная работа – каждый процесс
вычисляет скалярное произведение своих частей векторов. Сразу до (70-71) и
после (77-78) этого происходит печать времени начала и окончания счета, дабы
можно было оценить, как долго каждый процесс ожидал завершения пересылки
данных, чтобы начать считать, и когда он реально окончил счет, далее простаивая
в ожидании завершения остальных процессов.
27
После вычисления каждым процессом имеется n чисел, которые для
получения окончательного результата надо просто просуммировать тоже.
Естественным решением будет организовать в управляющем процессе цикл с
приемом и суммированием этих значений, а каждый процесс должен будет
послать ему этот результат, уже знакомыми функциями MPI_Send() и
MPI_Recv(). Но для ряда операций существуют более эффективные реализации,
которые следует продемонстрировать. Операция Reduce – это операция
получения одного значения из их набора (массива),
MPI предоставляет
возможность всем процессам для ряда коммутативных и ассоциативных операций
сделать это более элегантно. В данном случае мы указываем предопределенную
операцию MPI_SUM, для одного значение типа MPI_DOUBLE в переменной sum
каждого процесса, результат будет записан в переменную result в процессе 0.
Конец программы достаточно очевиден – управляющий процесс печатает
ответ (сбрасывая в строке 85 возможную буферизацию печати), вместе с
суммарным временем, которое было потрачено на всё, после чего в строке 88
выполняется обязательная финализация работы подсистемы MPI.
28
Запуск параллельных приложений на кластере
Компиляция программ MPI
После того как программа отредактирована, её необходимо
скомпилировать. Для компиляции MPI-программ рекомендуется пользоваться
командами mpicc/mpiCC (для программ на С и С++), и mpif77/mpif90 (для
программ на Фортране 77/90). Эти команды автоматически подключают
заголовочные файлы и библиотеки MPI. Для программ на языке С++ нужно
использовать расширение имени файла .C или .cpp, для программ на языке
Фортран 90 - .f90.
Рекомендуется использовать опции компиляторов для оптимизации
программ. Для компиляторов Intel и GNU gcc, установленных на нашем
кластере, приемлемый уровень оптимизации дает опция -O3, для справки о
других опциях оптимизации рекомендуем обращаться к руководствам по
компиляторам.
Если необходимо только скомпилировать один модуль, и не выполнять
сборку исполняемого файла, используется опция "-с", например:
test@master:~> mpiCC -c program2.C
При этом будет создан объектный модуль "program2.o". Объектный
модуль не является исполняемым, он используется как один из блоков при
компоновке исполняемого файла.
Если необходимо создать исполняемый файл, то имеет смысл
воспользоваться опцией -o <имя>, чтобы задать его имя (по умолчанию его имя
будет a.out). Например:
test@master:~> mpif90 -O3 program.f -o program.e
или, для рассмотренного в предыдущем разделе примера:
test@master:~/my_progs> mpif90 -o scalar scalar.c
При этом будет создан исполняемый файл program.e (или scalar для
примера предыдущего раздела), который можно запускать на исполнение
командой mpirun (но только на том кластере, где он был собран).
Для сборки многомодульных приложений целесообразно пользоваться
утилитой GNU make. Для запуска MPI-приложений используется система
управления заданиями Cleo (созданная в НИВЦ МГУ), она предназначена для
управления прохождением задач на многопроцессорных вычислительных
установках (в том числе кластерных). Она позволяет автоматически распределять
вычислительные ресурсы между задачами, управлять порядком их запуска,
временем работы, получать информацию о состоянии очередей.
29
Постановка задачи в очередь
Задача ставится в очередь командой mpirun, которая напоминает обычную
команду запуска MPI-приложений:
mpirun -np N [-q Q] [-maxtime T] [-p P] <программа с аргументами>
где N - число процессоров, должно быть не более разрешенного числа
процессоров для одной задачи. Q - это очередь, куда будет поставлена задача. T это максимальное время работы задачи в минутах. P - приоритет задачи в очереди.
Реально задача начнет выполняться, как только она будет на верхушке
очереди и будут свободны N процессоров. Система автоматически подбирает
свободные узлы (процессоры) для запуска задачи. Гарантируется, что на каждом
узле будет запущено не более прикладных процессов, чем реально доступно ядер
процессоров (4). Если задача поставлена в очередь, система выдает
подтверждение и присваивает задаче уникальный номер (ID).
Например, чтобы запустить скомпилированный пример скалярного
произведения двух векторов на всех 24 узлах (а на каждом два двухъядерных
процессора, что позволяет запустит до 4 процессов на узел) с указанием длины
вектора в почти миллиард элементов, можно так:
test@master:~/my_progs> mpirun -np 96 ./scalar 999999999
Using queue main
Successfully added to queue main (ID=205)
После постановки задачи в очередь пользователь может отключиться от
терминала, а затем в любой момент подключиться к системе и просматривать
результаты прежде запущенных задач.
Для
запуска
однопроцессных
приложений
используйте
ключ
<–as single>:
test@master:~> mpirun
–np 1
-as single
myprog.e
my_arguments
Запуск однопроцессных приложений отличается тем, что в данном случае
вы запускаете обычную программу Unix, без всякого параллельного
программирования.
По
умолчанию
система
ожидает
программу,
скомпилированную с MPI, и если так запустить не-MPI приложение, запуск
окончится ошибкой. В некоторых случаях, однако, необходимо запускать другие
приложение: если программирование MPI для вашей цели слишком сложно, или
задача очень плохо параллелится, или есть разные последовательные задачи
(например, с очень разными параметрами расчета). Тогда следует создать
обычную однопроцессную программу Unix, указать этот ключ, и система просто
запустит этот программу вместо головного узла на случайном процессоре из
свободных в текущий момент, рассматривая кластер не как связанную систему, а
как набор обыкновенных компьютеров. Помните, что головной узел не
предназначен для счета, на нем работают другие пользователи, не следует
запускать программы прямо на нём!
30
Пояснение к системе приоритетов
Задачи с большим приоритетом будут идти на счет раньше задач с меньшим
приоритетом. Приоритет обычных задач по умолчанию равен 10. Если для Вас не
важно, чтобы задача пошла на счет как можно быстрее и Вы считаете
целесообразным уступить очередь другим пользователям, Вы можете уменьшить
значение приоритета. Например:
test@master:~> mpirun -np 32 -p 8 cg.A.32
Эта задача со значением приоритета 8 пойдет на счет не раньше, чем пойдут
на счет все задачи с приоритетами 9 и 10.
Если для Вас, наоборот, требуется посчитать задачу как можно быстрее, то
Вы можете обратиться к нам с просьбой увеличить значение приоритета Вашей
задачи. Самостоятельно повысить приоритет своей задачи более чем до 10 Вы не
можете. Можно изменить приоритет задачи, стоящей в очереди, с помощью
команды cleo-priority.
Параметр -maxtime устанавливает предельное время работы задачи в
минутах (по умолчанию трое суток). Просим Вас обязательно указывать этот
параметр для всех задач. Это поможет нам оптимально планировать работу
кластера и поможет другим пользователям ориентироваться при постановке задач
в очередь. По умолчанию будет устанавливаться очень небольшое предельное
время. Учтите, что при истечении предельного времени задача будет сниматься со
счета (принудительно убиваться).
Например, пусть на кластере свободно 8 процессоров, а в очереди уже стоит
задача на 32 процессора (но все 32 процессора в ближайшие 7 часов не
освободятся). Тогда если поставить в очередь короткую 4-процессорную задачу,
указав максимальное время:
test@master:~> mpirun -np 4 -maxtime 10 program
то эта задача сразу пойдет на счет. Таким образом, вычислительные ресурсы
будут распределяться более оптимально.
Просим Вас разумно пользоваться возможностями системы и проявлять
уважение к другим пользователям.
Просмотр результатов
По окончании работы задачи пользователю выдается сообщение на
терминал (в дальнейшем может быть организовано также оповещение по
электронной почте). Выдача программы помещается в файл в рабочей директории
с именем <задача>.out-<номер>. Кроме того, создается файл отчета
<задача>.rep-<номер>, где указываются следующие данные: командная
строка при запуске задачи, число процессоров, код возврата, имя выходного
файла, рабочая директория, астрономическое время работы программы, имена
31
узлов, на которых была запущена программа. Имена файла отчета и выходного
файла можно настраивать в конфигурационном файле.
Для рассматриваемого примера со скалярным произведением векторов
выходной файл может выглядеть так:
test@master:~/my_progs> cat scalar.out-205
Process 65 of 96 is on node-2
Process 32 of 96 is on node-18
Process 64 of 96 is on node-2
Process 35 of 96 is on node-18
Process 38 of 96 is on node-19
Process 42 of 96 is on node-1
Process 69 of 96 is on node-3
Process 51 of 96 is on node-21
Process 54 of 96 is on node-22
Process 31 of 96 is on node-17
Process 45 of 96 is on node-20
Process 49 of 96 is on node-21
Process 68 of 96 is on node-3
Process 80 of 96 is on node-6
Process 71 of 96 is on node-3
Process 36 of 96 is on node-19
Process 88 of 96 is on node-8
Process 77 of 96 is on node-5
Process 83 of 96 is on node-6
Process 50 of 96 is on node-21
Process 21 of 96 is on node-15
Process 61 of 96 is on node-24
Process 66 of 96 is on node-2
Process 93 of 96 is on node-9
Process 94 of 96 is on node-9
Process 73 of 96 is on node-4
Process 63 of 96 is on node-24
Process 52 of 96 is on node-22
Process 58 of 96 is on node-23
Process 9 of 96 is on node-12
Process 1 of 96 is on node-10
Process 8 of 96 is on node-12
Process 39 of 96 is on node-19
Process 11 of 96 is on node-12
Process 34 of 96 is on node-18
Process 3 of 96 is on node-10
Process 57 of 96 is on node-23
Process 10 of 96 is on node-12
Process 86 of 96 is on node-7
Process 13 of 96 is on node-13
Process 70 of 96 is on node-3
Process 19 of 96 is on node-14
Process 59 of 96 is on node-23
Process 26 of 96 is on node-16
Process 2 of 96 is on node-10
Process 27 of 96 is on node-16
Process 47 of 96 is on node-20
Process 89 of 96 is on node-8
Process 55 of 96 is on node-22
Process 53 of 96 is on node-22
Process 41 of 96 is on node-1
Process 29 of 96 is on node-17
Process 81 of 96 is on node-6
Process 48 of 96 is on node-21
Process 84 of 96 is on node-7
32
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
14 of 96 is on node-13
44 of 96 is on node-20
92 of 96 is on node-9
76 of 96 is on node-5
4 of 96 is on node-11
56 of 96 is on node-23
6 of 96 is on node-11
30 of 96 is on node-17
87 of 96 is on node-7
12 of 96 is on node-13
40 of 96 is on node-1
46 of 96 is on node-20
75 of 96 is on node-4
85 of 96 is on node-7
72 of 96 is on node-4
82 of 96 is on node-6
25 of 96 is on node-16
15 of 96 is on node-13
22 of 96 is on node-15
67 of 96 is on node-2
95 of 96 is on node-9
33 of 96 is on node-18
62 of 96 is on node-24
91 of 96 is on node-8
5 of 96 is on node-11
7 of 96 is on node-11
28 of 96 is on node-17
43 of 96 is on node-1
74 of 96 is on node-4
78 of 96 is on node-5
20 of 96 is on node-15
24 of 96 is on node-16
16 of 96 is on node-14
37 of 96 is on node-19
60 of 96 is on node-24
90 of 96 is on node-8
18 of 96 is on node-14
23 of 96 is on node-15
79 of 96 is on node-5
17 of 96 is on node-14
0 of 96 is on node-10
1 on node node-10 starting calc at 1.986553 sec
2 on node node-10 starting calc at 4.099962 sec
3 on node node-10 starting calc at 6.494678 sec
1 on node node-10 ending calc at 6.811479 sec
4 on node node-11 starting calc at 8.380775 sec
5 on node node-11 starting calc at 10.281216 sec
2 on node node-10 ending calc at 10.619027 sec
3 on node node-10 ending calc at 12.247417 sec
4 on node node-11 ending calc at 12.355679 sec
6 on node node-11 starting calc at 12.404281 sec
5 on node node-11 ending calc at 14.375157 sec
7 on node node-11 starting calc at 14.478773 sec
6 on node node-11 ending calc at 16.317051 sec
8 on node node-12 starting calc at 16.344161 sec
9 on node node-12 starting calc at 18.209255 sec
7 on node node-11 ending calc at 18.274197 sec
8 on node node-12 ending calc at 20.203265 sec
10 on node node-12 starting calc at 20.371354 sec
11 on node node-12 starting calc at 22.236358 sec
12 on node node-13 starting calc at 24.101140 sec
9 on node node-12 ending calc at 24.285586 sec
13 on node node-13 starting calc at 25.966044 sec
33
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
11
10
12
14
13
15
16
14
15
17
18
16
19
20
17
21
18
19
20
22
21
23
24
22
23
25
26
24
27
25
28
29
26
28
27
30
31
32
29
33
31
30
34
32
33
35
36
34
37
35
36
38
39
40
37
41
39
38
40
42
41
43
44
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node-12 ending calc at 26.195200 sec
node-12 ending calc at 26.278865 sec
node-13 ending calc at 28.122228 sec
node-13 starting calc at 28.131973 sec
node-13 ending calc at 29.971013 sec
node-13 starting calc at 30.141702 sec
node-14 starting calc at 32.007457 sec
node-13 ending calc at 32.055611 sec
node-13 ending calc at 33.947192 sec
node-14 starting calc at 34.130383 sec
node-14 starting calc at 35.996762 sec
node-14 ending calc at 37.986985 sec
node-14 starting calc at 38.175061 sec
node-15 starting calc at 40.043447 sec
node-14 ending calc at 40.090141 sec
node-15 starting calc at 41.911764 sec
node-14 ending calc at 42.028253 sec
node-14 ending calc at 43.877068 sec
node-15 ending calc at 44.064366 sec
node-15 starting calc at 44.074125 sec
node-15 ending calc at 45.922043 sec
node-15 starting calc at 46.088846 sec
node-16 starting calc at 47.953646 sec
node-15 ending calc at 47.981564 sec
node-15 ending calc at 49.885462 sec
node-16 starting calc at 50.082035 sec
node-16 starting calc at 51.947098 sec
node-16 ending calc at 53.823834 sec
node-16 starting calc at 54.126657 sec
node-16 ending calc at 55.965117 sec
node-17 starting calc at 55.991784 sec
node-17 starting calc at 57.857756 sec
node-16 ending calc at 58.020547 sec
node-17 ending calc at 59.859178 sec
node-16 ending calc at 59.866633 sec
node-17 starting calc at 60.022600 sec
node-17 starting calc at 61.887429 sec
node-18 starting calc at 63.752350 sec
node-17 ending calc at 63.877885 sec
node-18 starting calc at 65.617448 sec
node-17 ending calc at 65.855990 sec
node-17 ending calc at 65.865320 sec
node-18 starting calc at 67.788874 sec
node-18 ending calc at 67.810459 sec
node-18 ending calc at 69.625431 sec
node-18 starting calc at 69.797325 sec
node-19 starting calc at 71.663182 sec
node-18 ending calc at 71.708298 sec
node-19 starting calc at 73.527963 sec
node-18 ending calc at 73.611953 sec
node-19 ending calc at 75.514085 sec
node-19 starting calc at 75.686998 sec
node-19 starting calc at 77.555478 sec
node-1 starting calc at 79.424400 sec
node-19 ending calc at 79.588560 sec
node-1 starting calc at 81.293021 sec
node-19 ending calc at 81.528820 sec
node-19 ending calc at 81.567667 sec
node-1 ending calc at 83.436041 sec
node-1 starting calc at 83.453322 sec
node-1 ending calc at 85.318031 sec
node-1 starting calc at 85.476362 sec
node-20 starting calc at 87.341581 sec
34
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
Process
42
45
43
44
46
45
47
48
46
49
47
48
50
51
52
49
53
51
50
52
54
53
55
56
54
57
55
56
58
59
60
57
61
59
58
60
62
63
64
61
63
65
62
66
64
67
68
65
66
69
67
70
68
71
69
72
73
70
72
71
74
75
76
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
on
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node
node-1 ending calc at 87.357478 sec
node-20 starting calc at 89.206999 sec
node-1 ending calc at 89.275385 sec
node-20 ending calc at 91.345189 sec
node-20 starting calc at 91.364721 sec
node-20 ending calc at 93.186706 sec
node-20 starting calc at 93.360995 sec
node-21 starting calc at 95.226052 sec
node-20 ending calc at 95.275176 sec
node-21 starting calc at 97.091059 sec
node-20 ending calc at 97.192541 sec
node-21 ending calc at 99.090204 sec
node-21 starting calc at 99.260569 sec
node-21 starting calc at 101.124842 sec
node-22 starting calc at 102.989866 sec
node-21 ending calc at 103.094547 sec
node-22 starting calc at 104.855610 sec
node-21 ending calc at 105.084581 sec
node-21 ending calc at 105.116581 sec
node-22 ending calc at 107.010051 sec
node-22 starting calc at 107.021547 sec
node-22 ending calc at 108.873117 sec
node-22 starting calc at 109.039311 sec
node-23 starting calc at 110.905427 sec
node-22 ending calc at 110.929646 sec
node-23 starting calc at 112.770830 sec
node-22 ending calc at 112.870543 sec
node-23 ending calc at 114.774826 sec
node-23 starting calc at 114.942875 sec
node-23 starting calc at 116.810026 sec
node-24 starting calc at 118.678662 sec
node-23 ending calc at 118.791487 sec
node-24 starting calc at 120.547573 sec
node-23 ending calc at 120.776525 sec
node-23 ending calc at 120.796954 sec
node-24 ending calc at 122.539467 sec
node-24 starting calc at 122.711106 sec
node-24 starting calc at 124.580326 sec
node-2 starting calc at 126.447008 sec
node-24 ending calc at 126.618692 sec
node-24 ending calc at 128.540667 sec
node-2 starting calc at 128.568682 sec
node-24 ending calc at 128.609746 sec
node-2 starting calc at 130.433556 sec
node-2 ending calc at 132.440000 sec
node-2 starting calc at 132.614312 sec
node-3 starting calc at 134.478339 sec
node-2 ending calc at 134.523263 sec
node-2 ending calc at 136.559419 sec
node-3 starting calc at 136.604531 sec
node-2 ending calc at 138.420101 sec
node-3 starting calc at 138.470344 sec
node-3 ending calc at 140.376324 sec
node-3 starting calc at 140.649617 sec
node-3 ending calc at 142.497832 sec
node-4 starting calc at 142.514426 sec
node-4 starting calc at 144.379514 sec
node-3 ending calc at 144.559493 sec
node-4 ending calc at 146.372721 sec
node-3 ending calc at 146.425581 sec
node-4 starting calc at 146.542097 sec
node-4 starting calc at 148.408210 sec
node-5 starting calc at 150.273361 sec
35
Process 73 on node node-4 ending calc at 150.438133 sec
Process 75 on node node-4 ending calc at 152.369008 sec
Process 77 on node node-5 starting calc at 152.393202 sec
Process 74 on node node-4 ending calc at 152.431586 sec
Process 78 on node node-5 starting calc at 154.258755 sec
Process 76 on node node-5 ending calc at 156.204467 sec
Process 79 on node node-5 starting calc at 156.435276 sec
Process 80 on node node-6 starting calc at 158.304309 sec
Process 77 on node node-5 ending calc at 158.322973 sec
Process 81 on node node-6 starting calc at 160.172196 sec
Process 78 on node node-5 ending calc at 160.382663 sec
Process 79 on node node-5 ending calc at 162.235015 sec
Process 80 on node node-6 ending calc at 162.318579 sec
Process 82 on node node-6 starting calc at 162.335486 sec
Process 81 on node node-6 ending calc at 164.170514 sec
Process 83 on node node-6 starting calc at 164.344626 sec
Process 84 on node node-7 starting calc at 166.212309 sec
Process 82 on node node-6 ending calc at 166.247443 sec
Process 85 on node node-7 starting calc at 168.077163 sec
Process 83 on node node-6 ending calc at 168.138188 sec
Process 84 on node node-7 ending calc at 170.076853 sec
Process 86 on node node-7 starting calc at 170.236582 sec
Process 87 on node node-7 starting calc at 172.101324 sec
Process 88 on node node-8 starting calc at 173.966105 sec
Process 85 on node node-7 ending calc at 174.158338 sec
Process 89 on node node-8 starting calc at 175.832028 sec
Process 87 on node node-7 ending calc at 176.095715 sec
Process 86 on node node-7 ending calc at 176.099371 sec
Process 88 on node node-8 ending calc at 177.992950 sec
Process 90 on node node-8 starting calc at 177.995608 sec
Process 89 on node node-8 ending calc at 179.841781 sec
Process 91 on node node-8 starting calc at 180.007976 sec
Process 92 on node node-9 starting calc at 181.873386 sec
Process 90 on node node-8 ending calc at 181.924975 sec
Process 93 on node node-9 starting calc at 183.738248 sec
Process 91 on node node-8 ending calc at 183.800574 sec
Process 92 on node node-9 ending calc at 185.843274 sec
Process 94 on node node-9 starting calc at 185.864344 sec
Process 93 on node node-9 ending calc at 187.764613 sec
Process 95 on node node-9 starting calc at 187.905170 sec
Process 0 on node node-10 starting calc at 189.448858 sec
Process 94 on node node-9 ending calc at 189.775795 sec
Process 95 on node node-9 ending calc at 191.719839 sec
Process 0 on node node-10 ending calc at 193.169813 sec
Answer is 1965817060924467643529822208.0000000000000000
wall clock time = 193.170001
Видно, что на коротком промежутке времени большое влияние оказывают
случайные факторы – процессы пишут сообщение о старте не по порядку. Однако
далее, поскольку на пересылку данных и счет уходит более значительное время, и
здесь уже явно виден порядок, в котором нулевой процесс отсылает данные.
Видно также, что в большинстве случаев нулевой процесс успевает послать
очередную порцию данных более чем одному процессу, прежде чем предыдущий
выполнит счет, однако в данном случае вычисления крайне просты, поэтому из
193 секунд работы всех процессов более 189 до начала счета нулевым процессом
ушли на генерацию и пересылку данных. В реальных задачах со сложными
вычислениями время пересылки данных станет существенно меньше времени
36
пересылки данных функциями MPI, так что параллелизм оборудования станет
использоваться в достаточно полной мере.
Следует также иметь в виду, что реализация конкретной библиотеки MPI не
обязана упорядочивать вывод от процессов – в отличие от примера выше, строки
starting и ending могли бы быть выведены в совершенно произвольном
порядке, порядок выполнения программы можно было бы понять только по
меткам времени. Не обязана она и выводить его в файл сразу по мере печати
информации процессами (например, если ваши процессы постоянно пишут что-то
на экран, и вы хотите с помощью команды типа tail -f taskname.out1234 отслеживать процесс выполнения). Поэтому вывод результатов
одновременно более чем одним процессом имеет ограниченное применение, в
случае большого количества данных пользуйтесь отдельными файлами
(возможно, в отдельном хранилище данных).
Просмотр состояния очереди
Посмотреть текущее состояние очереди можно командой:
tasks [параметры]
Сначала показываются работающие в данный момент задачи, а затем
ожидающие, в т.ч. заблокированные.
Команда tasks поддерживает следующие параметры:
 -q <очередь> – просмотр заданной очереди на текущем кластере.
Если параметр не задан, в качестве имени очереди берется значение
переменной среды QS_QUEUE. Обычно на нашем кластере есть только
одна очередь, так что эту опцию можно не указывать.
 -l – просмотр расширенной информации о задачах.
 -o – показать только свои задачи (по умолчанию).
 -f – показать только задачи других пользователей. Вместе с -o будет
показан полный список задач в очереди для всех пользователей.
 -t – включить в вывод показ текущих настроек лимитов времени.
Команда tasks применяется не только для просмотра состояния, но и для
других операций над очередью. Подробнее можно узнать в странице справочника
man tasks.
Удаление задачи
Удалить свою задачу, стоящую в очереди или выполняющуюся, можно
командой:
tasks [-q <очередь>] -d <номер>
Удалить все свои задачи можно командой:
tasks [-q <очередь>] -d all
В случае необходимости удаления нескольких (но не всех) задач по
определенному критерию (например, только выполняющиеся, или с
37
определенным именем) у команды tasks есть возможность их задания вместо
ручного перебора нужных номеров задач, за подробной информацией обратитесь
к man tasks.
38
Download