Программирование для многопроцессорных систем в стандарте MPI - Шпаковский Г.И., Серикова Н.В.. Программирование для многопроцессорных систем в стандарте MPI -. Организация вычислений в многопроцессорных системах
Скачать 1.61 Mb.
|
MPI_IBSEND (buf, count, datatype, dest, tag, comm, request) Запускает неблокирующую буферизованную посылку 58. MPI_INIT ( ) Инициализация параллельных вычислений 59. MPI_INITIALIZED ( flag ) Указывает, был ли выполнен MPI_INIT 60. MPI_IPROBE (source, tag, comm, flag, status) Неблокирующий тест сообщения 61. MPI_IRECV (buf, count, datatype, source, tag, comm, request) Начинает неблокирующий прием 62. MPI_IRSEND (buf, count, datatype, dest, tag, comm, request) Запускает неблокирующую посылку по готовности 63. MPI_ISEND (buf, count, datatype, dest, tag, comm, request) Запускает неблокирующую посылку 64. MPI_ISSEND (buf, count, datatype, dest, tag, comm, request) Запускает неблокирющую синхронную передачу 65. MPI_PACK (inbuf, incount, datatype, outbuf, outsize, position, comm) Упаковывает данные в непрерывный буфер 66. MPI_PACK_SIZE (incount, datatype, comm, size) Возвращает размер, необходимый для упаковки типа данных 67. MPI_PROBE (source, tag, comm, status) Блокирующий тест сообщения 68. MPI_RECV (buf, count, datatype, source, tag, comm, status) Основная операция приема 69. MPI_RECV_INIT(buf, count, datatype, source, tag, comm, request) Создает handle для приема 70. MPI_REDUCE ( sendbuf, recvbuf, count, datatype, op, root, comm) Выполняет глобальную операцию над значениями всех процессов и возвраща- ет результат в один процесс 71. MPI_REDUCE_SCATTER ( sendbuf, recvbuf, recvcounts, datatype, op, comm) Выполняет редукцию и рассылает результаты 72. MPI_REQUEST_FREE (request) Освобождает объект коммуникационного запроса 73. MPI_RSEND (buf, count, datatype, dest, tag, comm) Операция посылки по готовности 74. MPI_RSEND_INIT (buf, count, datatype, dest, tag, comm, request) Создает дескриптор для посылки по готовности 276 75. MPI_SCAN ( sendbuf, recvbuf, count, datatype, op, comm ) Вычисляет частичную редукцию данных на совокупности процессов 76. MPI_SCATTER ( sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root,comm) Рассылает содержимое буфера одного процесса всем процессам в группе 77. MPI_SCATTERV( sendbuf, sendcounts, displs, sendtype, recvbuf, recvcount, recvtype, root, comm) Рассылает частибуфера одного процесса всем процессам в группе 78. MPI_SEND (buf, count, datatype, dest, tag, comm) Основная операция посылки 79. MPI_SEND_INIT (buf, count, datatype, dest, tag, comm, request) Строит дескриптор для стандартной посылки 80. MPI_SENDRECV (sendbuf, sendcount, sendtype, dest, sendtag, recvbuf, recvcount, recvtype, source, recvtag, comm, status) Посылает и принимает сообщение 81. MPI_SENDRECV_REPLACE (buf, count, datatype, dest, sendtag, source, recvtag,comm, status) Посылает и принимает сообщение, используя один буфер 82. MPI_SSEND (buf, count, datatype, dest, tag, comm) Базисная синхронная передача 83. MPI_SSEND_INIT (buf, count, datatype, dest, tag, comm, request) Строит дескриптор для синхронной передачи 84. MPI_START (request) Инициирует обмен с персистентным дескриптором запросов 85. MPI_STARTALL (count, array_of_requests) Запускает совокупность запросов 86. MPI_TEST(request, flag, status) Проверяет завершение посылки или приема 87. MPI_TESTALL (count, array_of_requests, flag, array_of_statuses) Проверяет завершение всех ранее начатых операций обмена 88. MPI_TESTANY (count, array_of_requests, index, flag, status) Проверяет завершение любой ранее начатой операции 89. MPI_TESTSOME (incount, array_of_requests, outcount, ar- ray_of_indices,array_of_statuses) Проверяет завершение заданных операций 90. MPI_TEST_CANCELLED (status, flag) Проверяет отмену запроса 91. MPI_TOPO_TEST (comm, status) Определяет тип связанной с коммуникатором топологии 92. MPI_TYPE_COMMIT(datatype) Объявляет тип данных 93. MPI_TYPE_CONTIGUOUS (count, oldtype, newtype) Создает непрерывный тип данных 94. MPI_TYPE_EXTENT(datatype, extent) Определяет экстент типа данных 277 95. MPI_TYPE_FREE (datatype) Отмечает объект типа данных для удаления 96. MPI_TYPE_INDEXED ( count, array_of_blocklengths, array_of_displacements, oldtype, newtype) Создает индексированный тип данных 97. MPI_TYPE_LB ( datatype, displacement) Возвращает нижнюю границу типа данных 98. MPI_TYPE_SIZE (datatype, size) Возвращает число байтов, занятых элементами типа данных 99. MPI_TYPE_STRUCT (count, array_of_blocklengths, array_of_displacements, array_of_types, newtype) Создает новый тип данных 100. MPI_TYPE_UB ( datatype, displacement) Возвращает верхнюю границу типа данных 101. MPI_TYPE_VECTOR ( count, blocklength, stride, oldtype, newtype) Создает векторный тип данных 102. MPI_UNPACK (inbuf, insize, position, outbuf, outcount, datatype, comm) Распаковывает данные из непрерывного буфера 103. MPI_WAIT (request, status) Ожидает завершения посылки или приема 104. MPI_WAITALL ( count, array_of_requests, array_of_statuses) Ожидает завершения всех обменов 105. MPI_WAITANY (count, array_of_requests, index, status) Ожидает завершения любой из описанных посылки или приема 106. MPI_WAITSOME (incount, array_of_requests, outcount, array_of_indices, array_of_statuses) Ожидает завершения некоторых заданных обменов 107. MPI_WTICK ( ) Возвращает величину разрешения при измерении времени 108. MPI_WTIME ( ) Возвращает полное время выполнения операций на используемом процессоре Приложение 3. ОРГАНИЗАЦИИ ПАРАЛЛЕЛЬНЫХ ВЫЧИСЛЕНИЙ В СЕТИ ПОД УПРАВЛЕНИЕМ WINDOWS NT 3.1. ОРГАНИЗАЦИЯ ПАРАЛЛЕЛЬНЫХ ВЫЧИСЛЕНИЙ Для выполнения параллельных программ на базе интерфейса MPI необходимо: 1. Создать и настроить локальную сеть (Fast Ethernet, SCI др.) под управлением Windows NT. 2. Инсталлировать MPICH (версий 1.2.1, 1.2.2 или 1.2.3). 3. Настроить компилятор С++ для работы с MPICH. 4. Запустить приложение. Пункт 1 является штатной для локальных сетей операцией и далее не рассмат- ривается. Пункт 2 содержит ряд вариантов для для Unix подобных систем. Однако 278 для Windows NT возможности существенно ограничены и обычно используются дистрибутивы с расширением .exe. Это самоинсталлирующиеся версии, которые бесплатно можно получить по адресу http://www.mcs.anl.gov/mpi/mpich в Ин- тернет. Последняя версия называется mpich.nt.1.2.3.src.exe (6.65 MB Jan 11, 2002). Для более подробного изучения инсталляции и работы с MPICH существуют ру- ководства: 1. Instsllation Guide to mpich , a Portable Implementation of MPI 2. User’s Guide for mpich , a Portable Implementation of MPI, которые можно получить по адресу: http://www.mcs.anl/gov/mpi/mpich или ftp.mcs.anl.gov в директории pub/mpi. Если файл слишком велик, можно попы- таться получить его по частям из pub/mpi/mpisplit и затем объединить. В дистри- бутив MPICH входит также библиотека MPE. 3.2. НАСТРОЙКИ VISUAL C++ 6.0 ДЛЯ РАБОТЫ С MPICH Чтобы создать новый проект mpich.nt с MSDEV, после того, как уже инстал- лирован mpich.nt, необходимо выполнить следующие действия: 1. Открыть MS Developer Studio - Visual C++. 2. Создать новый проект с любым желаемым именем и в любой директории. Са- мым простым проектом является консольное приложение Win32 без файлов в нем. 3. Закончить работу мастера по установке нового проекта. 4. Перейти на Project->Settings или нажать клавишу Alt F7, чтобы вызвать диало- говое окно настройки параметров нового проекта. 5. Установить параметры для использования многопоточных (multithreaded) биб- лиотек. Установить указатели Debug и Release режимов. 279 280 6. Установить include путь для всех целевых конфигураций: Argonne National Lab\MPICH.NT.1.2.1\SDK\include. 7. Установить lib путь для всех целевых конфигураций: Argonne National Lab\MPICH.NT.1.2.1\SDK\lib. 281 8. Добавить для всех конфигураций библиотеку ws2_32.lib (Это библиотека Microsoft Winsock2 library. Она по умолчанию находится в вашем пути к биб- лиотекам). Добавить mpich.lib в режим release и mpichd.lib в режим debug. 282 9. Закрыть диалоговое окно установки проекта.Добавить к проекту исходные файлы. 10. Build. Запуск приложения обычно производится из командной строки с помощью оператора mpirun, например: mpi run -np 4 cpi В этой команде могут быть также указаны различные опции, связанные с отлад- кой приложений, спецификой выполнения для различных устройств и платформ. Более подробно запуск приложений рассмотрен в главе 2. Приложение 4. ХАРАКТЕРИСТИКИ КОММУНИКАЦИОННЫХ СЕТЕЙ ДЛЯ КЛАСТЕРОВ Ниже приведены сравнительные характеристики некоторых сетей. Таблица 1 Характеристики некоторых коммуникационных технологий SCI Myrinet cLAN ServerNet Fast Ethernet Латентность 5,6 мкс 17 мкс 30 мкс 13 мкс 170 мкс Пропускная спо- собность ( MPI ) 80 Мбайт/c 40 Мбайт/c 100 Мбайт/c 180 Мбайт/c 10 Мбайт/c Пропускная спо- собность (аппа- ратная) 400 Мбайт/c 160 Мбайт/c 150 Мбайт/c н/д 12,5 Мбайт/c Реализация MPI ScaMPI HPVMи др. MPI /Pro MVICH MPICH 283 Коммуникационные сети. Производительность коммуникационных сетей в кластерных системах определяют две основные характеристики: латентность – время начальной задержки при посылке сообщений и пропускная способность се- ти, определяющая скорость передачи информации по каналам связи. При этом важны не столько пиковые характеристики, заявляемые производителем, сколько реальные, достигаемые на уровне пользовательских приложений, например, на уровне MPI–приложений. В частности, после вызова пользователем функции по- сылки сообщения Send() сообщение последовательно пройдет через целый набор слоев, определяемых особенностями организации программного обеспечения и аппаратуры, прежде, чем покинуть процессор - отсюда и вариации на тему ла- тентности. Кстати, наличие латентности определяет и тот факт, что максимальная скорость передачи по сети не может быть достигнута на сообщениях с небольшой длиной. Коммуникационная технология Fast Ethernet. Сети этого типаиспользу- ются чаще всего благодаря низкой стоимости оборудования. Однако большие на- кладные расходы на передачу сообщений в рамках Fast Ethernet приводят к серь- езным ограничениям на спектр задач, которые можно эффективно решать на та- ком кластере. Если от кластера требуется большая универсальность, то нужно пе- реходить на другие, более производительные коммуникационные технологии. Коммуникационная технология SCI. Основа технологии SCI – это кольца, состоящие из быстрых однонаправленных линков c пиковой пропускной способ- ностью на аппаратном уровне 400 Мбайт/c. Реальная пропускная способность на уровне MPI–приложений с использованием 32-разрядной шины PCI с частотой 33 МГц достигает 80 Мбайт/c, латентность – порядка 5,6 мкс. Основной поставщик промышленных SCI–компонентов на современном рынке – норвежская компания Dolphin Interconnect Solutions. Вместе с компанией Scali Computer она предлагает интегрированное кластерное решение Wulfkit, в состав которого входят “основная” и “дочерняя” сетевые платы, два специальных кабеля и соответствующее программное обеспечение. Программный пакет Scali Software Platform включает средства конфигурирования и администрирования кластеров, и, что немаловажно, ScaMPI – оптимизированную под SCI реализацию интерфейса MPI (Message Passing Interface). Поддерживаются операционные системы Linux, Solaris и NT Существующие кластеры, построенные на основе технологии SCI, содержат до 100 узлов, в качестве которых используются одно-, двух- и четырехпроцессорные компьютеры на базе Intel или UltraSPARC. Все узлы объединяются в топологию “двухмерный тор”, образуемую двумя SCI-кольцами с использованием двух сете- вых адаптеров на каждом узле. Одним из преимуществ подобного решения явля- ется отказ от дорогостоящих многопортовых коммутаторов. Самый большой кла- стер на базе SCI установлен в университете города Падеборн (Германия) – 96 двухпроцессорных узлов на базе Pentium II. Коммуникационная технология Myrinet . Сетевую технологию Myrinet представляет компания Myricom, которая впервые предложила свою коммуника- ционную технологию в 1994 году, а на сегодняшний день имеет уже более 1000 инсталляций по всему миру. 284 Узлы в Myrinet соединяются друг с другом через коммутатор (до 16 портов). Максимальная длина линий связи варьируется в зависимости от конкретной реа- лизации. На данный момент наиболее распространены реализации сетей LAN и SAN. В последнем случае, при использовании в рамках вычислительной системы, длина кабеля не может превышать 3-х метров, а в LAN - 10,7 метра. Приложение 5. ВАРИАНТЫ РЕШЕНИЯ ЗАДАНИЙ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ Задание 3.1. #include #include "mpi.h" int main( argc, argv ) int argc; char **argv; { int rank, size; MPI_Init( &argc, &argv ); MPI_Comm_size( MPI_COMM_WORLD, &size ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); printf( "Hello world from process %d of %d\n", rank, size ); MPI_Finalize(); return 0; } Задание 3.3. #include #include "mpi.h" int main( argc, argv ) int argc; char **argv; { int rank, value, size; MPI_Status status; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); do { if (rank == 0) { scanf( "%d", &value ); MPI_Send( &value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD ); } else { MPI_Recv( &value, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD, &status ); if (rank < size - 1) MPI_Send( &value, 1, MPI_INT, rank + 1, 0, MPI_COMM_WORLD ); } 285 printf( "Process %d got %d\n", rank, value ); } while (value >= 0); MPI_Finalize( ); return 0; } Задание 3.6. #include "mpi.h" #include { int rank, size, i, buf[1]; MPI_Status status; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); MPI_Comm_size( MPI_COMM_WORLD, &size ); if (rank == 0) { for (i=0; i<100*(size-1); i++) { MPI_Recv( buf,1,MPI_INT,MPI_ANY_SOURSE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); printf( "Msg from %d with tag %d\n", status.MPI_SOURCE, status.MPI_TAG ); } } else { for (i=0; i<100; i++) MPI_Send( buf, 1, MPI_INT, 0, i, MPI_COMM_WORLD ); } MPI_Finalize(); return 0; } Задание 3.13. /* пересылка вектора из 1000 элементов типа MPI_DOUBLE со страйдом 24 между элементами. Используем MPI_Type_vector */ #include #include #include "mpi.h" #define NUMBER_OF_TESTS 10 int main( argc, argv ) int argc; char **argv; { MPI_Datatype vec1, vec_n, old_types[2]; MPI_Aint indices[2]; double *buf, *lbuf, t1, t2, tmin; register double *in_p, *out_p; int i, j, k, nloop, rank, n, stride, blocklens[2]; 286 MPI_Status status; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); n = 1000; stride = 24; nloop = 100000/n; buf = (double *) malloc( n * stride * sizeof(double) ); if (!buf) { fprintf( stderr, "Could not allocate send/recv buffer of size %d\n",n * stride ); MPI_Abort( MPI_COMM_WORLD, 1 ); } lbuf = (double *) malloc( n * sizeof(double) ); if (!lbuf) { fprintf( stderr, "Could not allocated send/recv lbuffer of size %d\n", n ); MPI_Abort( MPI_COMM_WORLD, 1 ); } if (rank == 0) printf( "Kind\tn\tstride\ttime (sec)\tRate (MB/sec)\n" ); /* создаем новый векторный тип с заданным страйдом */ MPI_Type_vector( n, 1, stride, MPI_DOUBLE, &vec1 ); MPI_Type_commit( &vec1 ); tmin = 1000; for (k=0; k { /* убедимся, что оба процесса готовы к приему/передаче */ MPI_Sendrecv( MPI_BOTTOM, 0, MPI_INT, 1, 14, MPI_BOTTOM, 0, MPI_INT, 1, 14, MPI_COMM_WORLD, &status ); t1 = MPI_Wtime(); for (j=0; j MPI_Send( buf, 1, vec1, 1, k, MPI_COMM_WORLD ); MPI_Recv( buf, 1, vec1, 1, k, MPI_COMM_WORLD, &status ); } t2 = (MPI_Wtime() - t1) / nloop; ; /* время для пересылок*/ if (t2 < tmin) tmin = t2; } else if (rank == 1) { /* убедимся, что оба процесса готовы к приему/передаче */ MPI_Sendrecv( MPI_BOTTOM, 0, MPI_INT, 0, 14, MPI_BOTTOM, 0, MPI_INT, 0, 14, MPI_COMM_WORLD, &status ); for (j=0; j MPI_Send( buf, 1, vec1, 0, k, MPI_COMM_WORLD ); } } } tmin = tmin / 2.0; if (rank == 0) printf( "Vector\t%d\t%d\t%f\t%f\n", n, stride, tmin, n*sizeof(double)*1.0e-6 / tmin ); 287 MPI_Type_free( &vec1 ); MPI_Finalize( ); return 0; } Задание 3.14. /* пересылка вектора из 1000 элементов типа MPI_DOUBLE со страйдом 24 между элементами. Используем MPI_Type_struct */ #include #include #include "mpi.h" #define NUMBER_OF_TESTS 10 int main( argc, argv ) int argc; char **argv; { MPI_Datatype vec1, vec_n, old_types[2]; MPI_Aint indices[2]; double *buf, *lbuf, t1, t2, tmin; register double *in_p, *out_p; int i, j, k, nloop, rank, n, stride, blocklens[2]; MPI_Status status; MPI_Init( &argc, &argv ); MPI_Comm_rank( MPI_COMM_WORLD, &rank ); n = 1000; stride = 24; nloop = 100000/n; buf = (double *) malloc( n * stride * sizeof(double) ); if (!buf) { fprintf( stderr, "Could not allocate send/recv buffer of size %d\n",n * stride ); MPI_Abort( MPI_COMM_WORLD, 1 ); } lbuf = (double *) malloc( n * sizeof(double) ); if (!lbuf) { fprintf( stderr, "Could not allocated send/recv lbuffer of size %d\n", n ); MPI_Abort( MPI_COMM_WORLD, 1 ); } if (rank == 0) printf( "Kind\tn\tstride\ttime (sec)\tRate (MB/sec)\n" ); /* создаем новый тип */ blocklens[0] = 1; blocklens[1] = 1; indices[0] = 0; indices[1] = stride * sizeof(double); old_types[0] = MPI_DOUBLE; old_types[1] = MPI_UB; MPI_Type_struct( 2, blocklens, indices, old_types, &vec_n ); MPI_Type_commit( &vec_n ); tmin = 1000; for (k=0; k 288 MPI_Sendrecv( MPI_BOTTOM, 0, MPI_INT, 1, 14, MPI_BOTTOM, 0, MPI_INT, 1, 14, MPI_COMM_WORLD, &status ); t1 = MPI_Wtime(); for (j=0; j MPI_Recv( buf, n, vec_n, 1, k, MPI_COMM_WORLD, &status ); } t2 = (MPI_Wtime() - t1) / nloop; ; /* время для пересылок*/ if (t2 < tmin) tmin = t2; } else if (rank == 1) { /* убедимся, что оба процесса готовы к приему/передаче */ MPI_Sendrecv( MPI_BOTTOM, 0, MPI_INT, 0, 14, MPI_BOTTOM, 0, MPI_INT, 0, 14, MPI_COMM_WORLD, &status ); for (j=0; j MPI_Send( buf, n, vec_n, 0, k, MPI_COMM_WORLD ); } } } tmin = tmin / 2.0; if (rank == 0) printf("Struct\t%d\t%d\t%f\t%f\n",n,stride,tmin, n*sizeof(double)*1.0e-6 / tmin ); MPI_Type_free( &vec_n ); MPI_Finalize( ); return 0; } |