Главная » Просмотр файлов » Руководство по MPI

Руководство по MPI (547935), страница 4

Файл №547935 Руководство по MPI (Руководство по MPI) 4 страницаРуководство по MPI (547935) страница 42015-08-23СтудИзба
Просмтор этого файла доступен только зарегистрированным пользователям. Но у нас супер быстрая регистрация: достаточно только электронной почты!

Текст из файла (страница 4)

MPI_Status status;

int count;

MPI_Recv( ... , MPI_INT, ... , &status );

MPI_Get_count( &status, MPI_INT, &count );

/* ... теперь count содержит количество принятых ячеек */

Обратите внимание, что аргумент-описатель типа у MPI_Recv и MPI_Get_count должен быть одинаковым, иначе, в зависимости от реализации в count вернется неверное значение; или произойдет ошибка времени выполнения.

Константы-пустышки включают:

  • MPI_COMM_NULL;

  • MPI_DATATYPE_NULL;

  • MPI_REQUEST_NULL.

Константа неопределенного значения используется в процедуре MPI_Comm_Split и имеет имя MPI_UNDEFINED.

Константы глобальных операций используются в процедурах коллективного взаимодействия процессов для указания типа выполняемой операции. Данные константы включают:

  • MPI_MAX;

  • MPI_MIN;

  • MPI_SUM;

  • MPI_PROD.

Константы, определяющие любой процесс/идентификатор, используются для обозначения

  • MPI_ANY_SOURCE;

  • MPI_ANY_TAG.

В стандарте MPI существует несколько предопределенных типов, среди них:

  • MPI_Status - структура; атрибуты сообщений; содержит три обязательных поля:

  • MPI_Source (номер процесса отправителя);

  • MPI_Tag (идентификатор сообщения);

  • MPI_Error (код ошибки);

  • MPI_Request - системный тип; идентификатор операции посылки-приема сообщения;

  • MPI_Comm - системный тип; идентификатор группы (коммуникатора);

  • MPI_COMM_WORLD - зарезервированный идентификатор группы, состоящей их всех процессов приложения.

3.8 Латентность и пропускная способность

3.8.1 Понятия латентности и пропускной способности

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

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

Для улучшения характеристик латентности и пропускной способности необходимо:

  • подсчитать кол-во каналов передачи данных между процессами при разработке крупномодульных приложений;

  • использовать архивацию данных для больших сообщений, а также использовать описываемые типы данных вместо MPI_PACK и MPI_UNPACK если возможно;

  • использовать при возможности коллективные операции; это устраняет вызов MPI_Send и MPI_RECV каждый раз при коммуникации процессов;

  • определять номер принимающего процесса при вызове подпрограммы MPI; использование MPI_ANY_SOURCE может увеличивать латентность;

  • использовать MPI_RECV_INIT и MPI_STARTALL вместо вызова MPI_Irecv в цикле в случаях, когда запросы/прием не могут быть выполнены сразу.

Например, вы написали программу, содержащую фрагмент:

j = 0

for (i=0; i

if (i==rank) continue;

MPI_Irecv(buf[i], count, dtype, i, 0, comm, &requests[j++]);

}

MPI_Waitall(size-1, requests, statuses);

Предположим, что одна из итераций с вызовом MPI_IRECV не завершилась перед следующей итерацией цикла. В этом случае, MPI пробует выполнить оба запроса. Это может продолжаться, приводя к большему времени ожидания. Чтобы избежать этого, можно переписать эту часть кода так:

j = 0

for (i=0; i

if (i==rank) continue;

MPI_Recv_init(buf[i], count, dtype, i, 0, comm,

&requests[j++]);

}

MPI_Startall(size-1, requests);

MPI_Waitall(size-1, requests, statuses);

В этом случае все итерации с вызовом MPI_RECV_INIT выполняются только один раз при вызове MPI_STARTALL. При таком подходе вы не получите дополнительного времени ожидания при использовании MPI_Irecv и может улучшить латентность приложения.

3.8.2 Выбор подпрограмм/функций MPI

Для достижения наименьшей латентности и наибольшей пропускной способности сообщений для синхронной передачи "точка-точка", используйте блокирующие функции MPI MPI_Send и MPI_RECV. Для асинхронной передачи, используйте неблокирующие функции MPI MPI_Isend и MPI_IRECV.

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

Для задач требующих использования коллективных операций, используют соответствующую коллективную функцию MPI.

4 Входные и выходные данные

4.1 Этапы создания программ

Создание параллельной программы состоит из следующих этапов:

  • последовательный алгоритм подвергается декомпозиции (распараллеливанию), т.е. разбивается на независимо работающие ветви; для взаимодействия в ветви вводятся две дополнительные нематематические операции: прием и передача данных;

  • распараллеленный алгоритм записывается в виде программы, в которой операции приема и передачи записываются в терминах конкретной системы связи между ветвями;

  • полученная таким образом программа компилируется и компонуется с библиотеками среды параллельного программирования при помощи компилятора, используемого на данной системе для получения машинно-зависимого кода.

4.2 Компиляция модулей

Для компиляции и сборки программного модуля, написанного на С, используется команда mpicc. Аналогично для С++ используется команда mpiCC, для Fortran 77 используется mpif77, а для Fortran 90 – mpif90. Все команды пакета MPICH for GM настроены на использование компиляторов фирмы Compaq.

Эти команды предусматривают некоторые опции и подключают специальные библиотеки, необходимые для компиляции и сборки программ MPI:

  • опция -с указывается для выполнения только компиляции файла, не создавая объектный файл;

  • при задании опции -о осуществляется сборка и компиляция, а также создается объектный и запускаемый файлы.

Примеры

1 Компиляция программного модуля myprog.c

mpicc –c myprog.c

2 Сборка и компиляция программного модуля myprog.c с созданием выходного файла myfile

mpicc myprog.c –o myfile

4.3 Запуск программ, использующих MPI

Запуск на исполнение MPI-программы производится с помощью команды:

mpirun –np [-h –maxtime –quantum -stdiodir] [параметры_программы...]

Параметры команды mpirun слелующие:

  • параметр -h используется для выдачи интерактивной подсказки по параметрам команды mpirun;

  • параметр -np обозначает число процессоров, требуемое программе;

  • параметр -maxtime задает максимальное время счета. От этого времени зависит положение задачи в очереди. После истечения этого времени задача принудительно заканчивается;

  • параметр -quantum указывает, что задача является фоновой, и задает размер кванта для фоновой задачи;

  • параметр -stdiodir задает имя каталога стандартного вывода, в который будут записываться протокол запуска задачи, файл стандартного вывода и имена модулей, на которых запускалась задача.

Более подробное описание параметров команды запуска задач и постановки задачи в очередь приведено в руководстве “Подсистема коллективного доступа к ресурсам СК” [7].

5 Средства отладки и профилирования

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

5.1 Обработчики ошибок

Стандарт MPI определяет механизм для установки пользовательских обработчиков ошибок и определяет поведение двух встроенных обработчиков: MPI_ERRORS_RETURN и MPI_ERRORS_ARE_FATAL. В библиотеку mpe встроено еще два обработчика ошибок для облегчения использования отладчика dbx с программами, написанными с использованием стандарта MPI:

MPE_Errors_call_dbx_in_xterm

MPE_Signals_call_debugger

Данные обработчики ошибок расположены в директории mpe, основного дерева каталогов MPICH. При конфигурировании MPICH с опцией -mpedbg, эти отладчики включаются в основные библиотеки MPICH, и появляется возможность (с помощью аргумента командной строки mpedbg) установить обработчик MPE_Errors_call_dbx_in_xterm вызываемым по умолчанию обработчиком ошибок (вместо MPI_ERRORS_ARE_FATAL). В приложении А приведен пример программы, обрабатывающей ошибки с помощью процедур MPI (tester.c).

5.2 Профилировочные библиотеки

Профилировочный интерфейс MPE (Message Passing Extensions) представляет собой инструмент для добавления процедур анализа производительности в любую MPI-программу. С пакетом MPICH поставляется три профилировочные библиотеки:

  • библиотека определения времени выполнения процедур MPI;

  • библиотека создания файла журнала и утилита UpShot;

  • библиотека анимации процесса работы программы в реальном времени.

В Приложении А приведен пример программы с использованием профилировочных библиотек cpilog.c.

5.2.1 Библиотека определения времени выполнения процедур MPI

Данная библиотека достаточно проста. Профилировочная версия каждой процедуры MPI (MPI_Xxx) вызывает функцию PMPI_Wtime (возвращающую текущее время) перед и после каждого вызова соответствующей PMPI_Xxx процедуры. Времена накапливаются для каждого процесса и выводятся в файл (отдельный файл для каждого процесса) в профилировочной версии MPI_Finalize. В дальнейшем эти файлы можно использовать для создания отчета по всему приложению или по отдельным процессам. Текущая реализация библиотеки не обрабатывает вложенные циклы.

5.2.2 Создание файла журнала и утилита UpShot

Эта профилировочная библиотека предназначена для генерации файла журнала (log-файла), в котором фиксируются события, привязанные ко времени.

Для сохранения определенных типов событий в памяти, в процессе выполнения вызывается процедура MPI_Log_event, а сборка и объединение этих частей памяти с информацией о событиях происходит в MPI_Finalize. Для остановки и перезапуска операций записи событий во время выполнения программы может использоваться процедура MPI_Pcontrol.

Анализ файла журнала может быть осуществлен при помощи разнообразных программных средств. Используемый для этой цели в MPICH инструмент, называется UpShot. Состояния процессов в UpShot показаны с помощью параллельных осей времени для каждого процесса. Окно внизу экрана показывает гистограмму продолжительностей процессов с несколькими корректируемыми параметрами. Вид файла журнала, полученного с помощью утилиты UpShot, представлен на рисунке 1.

Рисунок 1 – Вид файла журнала

5.2.3 Анимация процесса работы программы в реальном времени

Графическая библиотека MPE предоставляет возможности для простой анимации в реальном времени. Библиотека содержит процедуры, которые позволяют разделять X-дисплей нескольким процессам. На основе данной библиотеки существует возможность графически изображать процесс передачи сообщений и их интенсивность в процессе работы программы.

Для сборки программы с использованием графических библиотек MPE при компиляции можно указать опцию –lmpe.

В MPICH предусмотрены также опции для компиляции и сборки программ с различными профилировочными библиотеками MPE:

-mpitrace

Для компиляции и сборки с отладочными библиотеками.

-mpianim

Для компиляции и сборки с анимационными библиотеками.

-mpilog

Для компиляции и сборки с регистрирующими библиотеками .

Пример

mpif77 -mpilog -o fpilog fpilog.f

Более подробную информацию об использовании профилировочных библиотек и о синтаксисе процедур MPE можно найти в документации по МРЕ [3, 1] а также в страницах справочного руководства (man pages).

Для использования отладчиков и профилировочных библиотек необходимо указывать специальные опции при конфигурации пакета MPICH, которые можно найти в п. 3.5 Руководства системного программиста по ОПО СК “МВС-1000М” [8].

5.3 Аргументы командной строки для mpirun

Команда mpirun предоставляет программисту некоторые возможности для облегчения использования отладчика со своей программой.

Команда

mpirun -dbx -np 2 program

начинает выполнение программы на двух машинах, запуская локальную копию программы в отладчике dbx. Опция -gdb позволяет использовать в качестве gdb отладчика, а опция -xxgdb запускает программу в Х Window интерфейсе для gdb – xxgbd.

5.4 Аргументы MPI для программ пользователя

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

-mpedbg

при возникновении ошибки в программе пользователя, запускает xterm, присоединенный к процессу, вызвавшему ошибку. MPICH должен быть сконфигурирован с опцией -mpedbg. Данный аргумент работает не на всех системах;

-mpiversion

печатает версию MPICH и аргументы, использованные при его конфигурировании;

-mpichdebug

генерирует детальную информацию по каждой производимой MPICH операции;

-mpiqueue

описывает состояние очередей вызова MPI_Finalize. Может быть использован для поиска “потерянных” сообщений.

Данные аргументы указываются программе пользователя, а не команде mpirun. Например,

mpirun -np 2 a.out -mpichdebug

Приложение A

(справочное)

Примеры программ с использованием функций MPI

В данном приложении приведены фрагменты MPI-программ (схематичные примеры) и ряд примеров прикладных программ, использующих MPI.

Перечень прикладных программ представлен в Таблице 2.

Таблица 2

имя файла

язык

комментарий

параметр -np

fpi.f

Fortran 77

Вычисляет число pi, интегрируя f (x) =4 / (1+x2).

np>=1

ctest.c

C

Пример измерения латентности для вызовов процедур MPI.

np=2

cart.c

C

Тест виртуальной топологии

np>1

tester.c

C

Тест обработки ошибок

np>=1

srtest.c

C

Тест пересылки сообщений

np>1

ping_pong.f

Fortran 77

Измеряет время передачи сообщений между двумя процессами

np=2

mpitest.c

C

Тест эффективности основных операций MPI

np>=4

cpilog.c

C

Программа с использованием профилировочных библиотек

np>2

А1 Схематичные примеры MPI-программ

А1.1 Схематичный пример инициализации параллельной части программы, определение кол-ва процессов в группе MPI_COMM_WORLD, где каждый процесс печатает размер группы и свой номер.

main(int argc, char **argv)

{

int me, size;

. . .

MPI_Init (&argc, &argv);

MPI_Comm_rank (MPI_COMM_WORLD, &me);

MPI_Comm_size (MPI_COMM_WORLD, &size);

(void)printf ("Process %d size %d\n", me, size);

. . .

MPI_Finalize();

}

А1.2 Схематичный пример программы, где главный процесс рассылает сообщения остальным процессам, а рабочие процессы группы принимают данные и выводят сообщение об этом.

#include "mpi.h"

main (argc, argv)

int argc;

char **argv;

{

char message[20];

int myrank;

MPI_Status status;

MPI_Init (&argc, &argv);

MPI_Comm_rank (MPI_COMM_WORLD, &myrank);

if (myrank==0) /* код для процесса 0*/

{

strcpy (message, "Hello, there");

MPI_Send(messege, strlen(messege), MPI_CAHR, 1, 99, MPI_COMM_WORLD);

}

else /* код для процесса 1 */

{

MPI_Recv (message, 20, MPI_CHAR, 0, 99, MPI_COMM_WORLD, &status);

printf ("receiveds :%s:\n", message);

}

MPI_Finalize();

}

А1.3 Схематичный пример программы, демонстрирующий обмен сообщениями между процессами группы с помощью процедур MPI_Send и MPI_Recv

main(int argc, char **argv)

{

int me, size;

int SOME_TAG=0;

MPI_Status status;

. . .

MPI_Init (&argc, &argv);

MPI_Comm_rank (MPI_COMM_WORLD, &me); /* local */

MPI_Comm-size (MPI_COMM_WORLD, &size); /* local */

if (me % 2)==0)

{

/* Посылает процессам, пока не дойдет до последнего */

if ((me+1) < size)

MPI_Send (..., me+1, SOME_TAG, MPI_COMM_WORLD);

}

else

MPI_Recv (..., me-1, SOME_TAG, MPI_COMM_WORLD, &status);

. . .

MPI_Finalize();

}

А2 Тест виртуальных топологий (cart.c)

Это программа на С, генерирующая виртуальную топологию. При компиляции этого примера необходимо подключить (указать путь) файл test.h, который входит в стандартные примеры MPICH и находится в директории /common/mpich/examples/test/topol

#include "mpi.h"

#include

#include "test.h"

#define NUM_DIMS 2

int main( int argc, char **argv )

{

int rank, size, i;

int errors=0;

int dims[NUM_DIMS];

int periods[NUM_DIMS];

int coords[NUM_DIMS];

int new_coords[NUM_DIMS];

int reorder = 1;

MPI_Comm comm_temp, comm_cart, new_comm;

int topo_status;

int ndims;

int new_rank;

int remain_dims[NUM_DIMS];

int newnewrank;

MPI_Init( &argc, &argv );

MPI_Comm_rank( MPI_COMM_WORLD, &rank );

MPI_Comm_size( MPI_COMM_WORLD, &size );

/* Обнуление массива сетки и создание топологии */

for(i=0;i

MPI_Dims_create ( size, NUM_DIMS, dims );

/* Создание нового коммуникатора для топологии */

MPI_Cart_create ( MPI_COMM_WORLD, 2, dims, periods, reorder, &comm_temp );

MPI_Comm_dup ( comm_temp, &comm_cart );

/* Определение состояния нового коммуникатора */

MPI_Topo_test ( comm_cart, &topo_status );

if (topo_status != MPI_CART) errors++;

/* Определение кол-ва измерений сетки в топологии */

MPI_Cartdim_get( comm_cart, &ndims );

if ( ndims != NUM_DIMS ) errors++;

/* Проверка корректности полученной топологии */

for(i=0;i

MPI_Cart_get ( comm_cart, NUM_DIMS, dims, periods, coords );

/* Проверка соответствия координат процесса в сетке топологии номеру процесса */

MPI_Cart_rank ( comm_cart, coords, &new_rank );

if ( new_rank != rank ) errors++;

/* Проверка соответствия номера процесса координатам процесса в сетке топологии */

MPI_Cart_coords ( comm_cart, rank, NUM_DIMS, new_coords );

for (i=0;i

if ( coords[i] != new_coords[i] )

errors++;

/* Сдвиг в каждом измерении сетки топологии и проверка ее работы*/

for (i=0;i

int source, dest;

MPI_Cart_shift(comm_cart, i, 1, &source, &dest);

#ifdef VERBOSE

printf ("[%d] Shifting %d in the %d dimension\n",rank,1,i);

printf ("[%d] source = %d dest = %d\n",rank,source,dest);

#endif

}

/* Выделение подгрупп коммуникатора для подсеток топологии */

remain_dims[0] = 0;

for (i=1; i

MPI_Cart_sub ( comm_cart, remain_dims, &new_comm );

/* Определение статуса нового коммуникатора */

MPI_Topo_test ( new_comm, &topo_status );

if (topo_status != MPI_CART) errors++;

/* Определение кол-ва измерений сетки в топологии */

MPI_Cartdim_get( new_comm, &ndims );

if ( ndims != NUM_DIMS-1 ) errors++;

/* Проверка корректности полученной топологии */

for(i=0;i

MPI_Cart_get ( new_comm, ndims, dims, periods, coords );

/* Проверка соответствия координат процесса в сетке топологии номеру процесса */

MPI_Comm_rank ( new_comm, &newnewrank );

MPI_Cart_rank ( new_comm, coords, &new_rank );

if ( new_rank != newnewrank ) errors++;

/* Проверка соответствия номера процесса координатам процесса в сетке топологии */

MPI_Cart_coords ( new_comm, new_rank, NUM_DIMS -1, new_coords );

for (i=0;i

if ( coords[i] != new_coords[i] )

errors++;

/* Завершение программы */

MPI_Comm_free( &new_comm );

MPI_Comm_free( &comm_temp );

MPI_Comm_free( &comm_cart );

Test_Waitforall( );

if (errors) printf( "[%d] done with %d ERRORS!\n", rank,errors );

MPI_Finalize();

return 0;

}

Вывод результата работы программы для np=2

call_batch: calling batch

All processes completed test

Вывод результата работы программы для np=32

call_batch: calling batch

All processes completed test

А3 Тест пересылки сообщений (srtest.c)

Эта программа выдает сообщения о коммуникациях в группе.

#include "mpi.h"

#include

#define BUFLEN 512

int main(argc,argv)

int argc;

char *argv[];

{

int i, myid, numprocs, next, rc, namelen;

char buffer[BUFLEN], processor_name[MPI_MAX_PROCESSOR_NAME];

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);

fprintf(stderr,"Process %d on %s\n", myid, processor_name);

strcpy(buffer,"hello there");

if (myid == numprocs-1)

next = 0;

else

next = myid+1;

if (myid == 0)

{

printf("%d sending '%s' \n",myid,buffer);

MPI_Send(buffer, strlen(buffer)+1, MPI_CHAR, next, 99, MPI_COMM_WORLD);

printf("%d receiving \n",myid);

MPI_Recv(buffer, BUFLEN, MPI_CHAR, MPI_ANY_SOURCE, 99, MPI_COMM_WORLD,

&status);

printf("%d received '%s' \n",myid,buffer);

}

else

{

printf("%d receiving \n",myid);

MPI_Recv(buffer, BUFLEN, MPI_CHAR, MPI_ANY_SOURCE, 99, MPI_COMM_WORLD,

&status);

printf("%d received '%s' \n",myid,buffer);

MPI_Send(buffer, strlen(buffer)+1, MPI_CHAR, next, 99, MPI_COMM_WORLD);

printf("%d sent '%s' \n",myid,buffer);

}

MPI_Barrier(MPI_COMM_WORLD);

MPI_Finalize();

}

Вывод результата работы программы для np=2

call_batch: calling batch

1 receiving

0 sending 'hello there'

0 receiving

0 received 'hello there'

1 received 'hello there'

1 sent 'hello there'

Вывод результата работы программы для np=32

call_batch: calling batch

20 receiving

30 receiving

8 receiving

13 receiving

10 receiving

16 receiving

2 receiving

4 receiving

6 receiving

9 receiving

7 receiving

12 receiving

3 receiving

14 receiving

21 receiving

11 receiving

17 receiving

18 receiving

19 receiving

5 receiving

15 receiving

24 receiving

22 receiving

26 receiving

23 receiving

28 receiving

27 receiving

25 receiving

29 receiving

31 receiving

1 receiving

0 sending 'hello there'

20 received 'hello there'

20 sent 'hello there'

30 received 'hello there'

30 sent 'hello there'

8 received 'hello there'

8 sent 'hello there'

18 received 'hello there'

18 sent 'hello there'

13 received 'hello there'

13 sent 'hello there'

10 received 'hello there'

10 sent 'hello there'

21 received 'hello there'

21 sent 'hello there'

16 received 'hello there'

16 sent 'hello there'

4 received 'hello there'

4 sent 'hello there'

2 received 'hello there'

2 sent 'hello there'

6 received 'hello there'

6 sent 'hello there'

12 received 'hello there'

12 sent 'hello there'

11 received 'hello there'

11 sent 'hello there'

9 received 'hello there'

9 sent 'hello there'

14 received 'hello there'

14 sent 'hello there'

19 received 'hello there'

19 sent 'hello there'

22 received 'hello there'

22 sent 'hello there'

28 received 'hello there'

28 sent 'hello there'

25 received 'hello there'

25 sent 'hello there'

27 received 'hello there'

27 sent 'hello there'

31 received 'hello there'

31 sent 'hello there'

3 received 'hello there'

3 sent 'hello there'

7 received 'hello there'

7 sent 'hello there'

17 received 'hello there'

17 sent 'hello there'

26 received 'hello there'

26 sent 'hello there'

23 received 'hello there'

23 sent 'hello there'

24 received 'hello there'

24 sent 'hello there'

29 received 'hello there'

29 sent 'hello there'

5 received 'hello there'

5 sent 'hello there'

15 received 'hello there'

15 sent 'hello there'

0 receiving

0 received 'hello there'

1 received 'hello there'

1 sent 'hello there'

А4 Вычисление числа Pi ( fpi.f )

Это пример программы на Fortran 77, который вычисляет число pi интегрируя f(x) = 4/(1 + x2).

Каждый процесс:

  • получает число интервалов, используемых в приближении;

  • вычисляет в них интегралы;

  • синхронизирует для общего суммирования.

Программа выдает результат вычислений, погрешность и время вычисления.

program main

include 'mpif.h'

double precision PI25DT

parameter (PI25DT = 3.141592653589793238462643d0)

double precision mypi, pi, h, sum, x, f, a

integer n, myid, numprocs, i, rc

c Интегрируемая функция

f(a) = 4.d0 / (1.d0 + a*a)

call MPI_INIT( ierr )

call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr )

call MPI_COMM_SIZE( MPI_COMM_WORLD, numprocs, ierr )

print *, "Process ", myid, " of ", numprocs, " is alive"

sizetype = 1

sumtype = 2

n = 0

10 if ( myid .eq. 0 ) then

write(6,98)

98 format('Enter the number of intervals: (0 quits)')

read(5,99) n

99 format(i10)

c if ( n .eq. 0 ) then

c n = 100

c else

c n = 0

c endif

print *, "got input n =", n

endif

call MPI_BCAST(n,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr)

c проверка принятия сообщения

if ( n .le. 0 ) goto 30

c вычисление размера интервала

h = 1.0d0/n

sum = 0.0d0

do 20 i = myid+1, n, numprocs

x = h * (dble(i) - 0.5d0)

sum = sum + f(x)

20 continue

mypi = h * sum

c прием всех частичных сумм

call MPI_REDUCE(mypi,pi,1,MPI_DOUBLE_PRECISION,MPI_SUM,0,

$ MPI_COMM_WORLD,ierr)

c печать ответа в 0-й ветви.

if (myid .eq. 0) then

write(6, 97) pi, abs(pi - PI25DT)

97 format(' pi is approximately: ', F18.16,

+ ' Error is: ', F18.16)

endif

goto 10

30 call MPI_FINALIZE(rc)

stop

end

Вывод результата работы программы для np=2

call_batch: calling batch

Process 1 of 2 is alive

Process 0 of 2 is alive

Enter the number of intervals: (0 quits)

Вывод результата работы программы для np=32

call_batch: calling batch

Process 29 of 32 is alive

Process 5 of 32 is alive

Process 2 of 32 is alive

Process 11 of 32 is alive

Process 4 of 32 is alive

Process 3 of 32 is alive

Process 6 of 32 is alive

Process 7 of 32 is alive

Process 8 of 32 is alive

Process 13 of 32 is alive

Process 9 of 32 is alive

Process 10 of 32 is alive

Process 12 of 32 is alive

Process 15 of 32 is alive

Process 14 of 32 is alive

Process 16 of 32 is alive

Process 19 of 32 is alive

Process 17 of 32 is alive

Process 18 of 32 is alive

Process 20 of 32 is alive

Process 21 of 32 is alive

Process 22 of 32 is alive

Process 23 of 32 is alive

Process 24 of 32 is alive

Process 26 of 32 is alive

Process 25 of 32 is alive

Process 27 of 32 is alive

Process 28 of 32 is alive

Process 30 of 32 is alive

Process 31 of 32 is alive

Process 1 of 32 is alive

Process 0 of 32 is alive

Enter the number of intervals: (0 quits)

A5 Измерение латентности вызовов процедур MPI (ctest.c)

Это пример программы на C , где латентность вызовов процедур MPI находится путем измерения разницы между временем вызова процедуры и результатами времени в эталонном тесте Dongarra.

#include "mpi.h"

#include

#include

#define MAX_TIMES 16386

static double times[MAX_TIMES];

int main( argc, argv )

int argc;

char **argv;

{

int i;

int ntest = MAX_TIMES;

double minsep, maxsep, avesep, sep, sd, deltasep, mult;

int citoutput = 1, nmatch;

MPI_Init( &argc, &argv );

/* Установление счетчиков времени */

for (i=0; i

times[i] = MPI_Wtime();

/* Получение начальных данных. При этом не измеряется время неудачных обращений к кэшу команды, занимающее дополнительное время */

for (i=0; i

times[i] = MPI_Wtime();

/* Просмотр вариантов */

minsep = 1.0e6;

maxsep = 0.0;

avesep = 0.0;

for (i=1; i

sep = times[i] - times[i-1];

if (sep < minsep) minsep = sep;

if (sep > maxsep) maxsep = sep;

avesep += sep;

}

avesep /= (ntest-1);

/* C Вычисление среднеквадратичного отклонение разниц относительно устойчивым способом */

sd = 0.0;

for (i=1; i

sep = times[i] - times[i-1];

sd += (sep - avesep) * (sep - avesep);

}

/* Масштаб в мкс */

sd *= 1.0e+12;

sd = sqrt(sd) / (ntest - 2);

/* Интересный вопрос - - все ли (или большинство) разниц являются множителями minsep. Сначала находят deltasep (время между первым и вторым различными измерениями.

*/

deltasep = maxsep;

for (i=1; i

sep = times[i] - times[i-1];

if (sep > minsep && sep < deltasep) deltasep = sep;

}

deltasep -= minsep;

/* Далее находят кол-во разниц, являющихся множителями deltasep */

nmatch = 0;

for (i=1; i

sep = times[i] - times[i-1];

mult = (sep - minsep) / deltasep;

if (fabs( mult - (int)mult) < 0.05) nmatch++;

}

/* Печать результатов */

printf( "#Variance in clock:\n\

#Minimum time between calls: %6.2f usec\n\

#Maximum time between calls: %6.2f usec\n\

#Average time between calls: %6.2f usec\n\

#Standard deviation: %12.3e\n",

minsep * 1.e6, maxsep * 1.e6, avesep * 1.e6, sd );

if (nmatch > ntest/4) {

printf( "#Apparent resolution of clock is: %6.2f usec\n",

deltasep * 1.0e6 );

}

printf(

"# This program should be run multiple times for better understanding\n" );

/* Print C.It graphics stuff if requested */

if (citoutput) {

for (i=1; i

sep = times[i] - times[i-1];

printf( "%f\n", sep * 1.0e6 );

}

printf( "hist\nwait\nnew page\n" );

}

MPI_Finalize();

return 0;

}

Вывод результата работы программы для np=2

call_batch: calling batch

#Variance in clock:

#Variance in clock:

#Minimum time between calls: 0.00 usec

#Maximum time between calls: 978.11 usec

#Average time between calls: 1.37 usec

#Standard deviation: 2.856e-01

#Apparent resolution of clock is: 0.95 usec

# This program should be run multiple times for better understanding

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

…………………

975.966454

2.026558

…………………

0.000000

0.000000

…………………

Вывод результата работы программы для np=32

call_batch: calling batch

#Variance in clock:

#Minimum time between calls: 0.00 usec

#Maximum time between calls: 977.99 usec

#Average time between calls: 0.84 usec

#Standard deviation: 2.230e-01

#Apparent resolution of clock is: 0.95 usec

# This program should be run multiple times for better understanding

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

0.000000

…………………

0.000000

#Minimum time between calls: 0.00 usec

#Maximum time between calls: 978.11 usec

#Average time between calls: 1.01 usec

#Standard deviation: 2.457e-01

#Apparent resolution of clock is: 0.95 usec

# This program should be run multiple times for better understanding

0.000000

0.000000

0.000000

…………………

A6 Тест обработки ошибок (testerr.c)

Эта программа показывает работу процедур для обработки ошибок.

#include

#include

void Test_Send( void );

void Test_Recv( void );

void Test_Datatype( void );

void Test_Errors_warn( MPI_Comm *comm, int *code, ... )

{

char buf[MPI_MAX_ERROR_STRING+1];

int myid, result_len;

static int in_handler = 0;

if (in_handler) return;

in_handler = 1;

/* Преобразование кода ошибки в сообщение и печать */

MPI_Error_string( *code, buf, &result_len );

printf( "%s\n", buf );

in_handler = 0;

}

static int errcount = 0;

void Test_Failed( char * msg )

{

printf( "FAILED: %s\n", msg );

errcount++;

}

void Test_Passed( char * msg )

{

printf( "Passed: %s\n", msg );

}

int main( int argc, char *argv[] )

{

MPI_Errhandler TEST_ERRORS_WARN;

MPI_Init( &argc, &argv );

MPI_Errhandler_create( Test_Errors_warn, &TEST_ERRORS_WARN );

MPI_Errhandler_set(MPI_COMM_WORLD, TEST_ERRORS_WARN);

Test_Send();

Test_Recv();

Test_Datatype();

MPI_Finalize();

return 0;

}

void Test_Send( void )

{

int buffer[100];

int dest;

MPI_Datatype bogus_type = MPI_DATATYPE_NULL;

MPI_Status status;

int myrank, size;

int large_tag, flag, small_tag;

int *tag_ubp;

MPI_Comm_rank( MPI_COMM_WORLD, &myrank );

MPI_Comm_size( MPI_COMM_WORLD, &size );

dest = size - 1;

if (MPI_Send(buffer, 20, MPI_INT, dest,

1, MPI_COMM_NULL) == MPI_SUCCESS){

Test_Failed("NULL Communicator Test");

}

else

Test_Passed("NULL Communicator Test");

if (MPI_Send(buffer, -1, MPI_INT, dest,

1, MPI_COMM_WORLD) == MPI_SUCCESS){

Test_Failed("Invalid Count Test");

}

else

Test_Passed("Invalid Count Test");

if (MPI_Send(buffer, 20, bogus_type, dest,

1, MPI_COMM_WORLD) == MPI_SUCCESS){

Test_Failed("Invalid Type Test");

}

else

Test_Passed("Invalid Type Test");

small_tag = -1;

if (small_tag == MPI_ANY_TAG) small_tag = -2;

if (MPI_Send(buffer, 20, MPI_INT, dest,

small_tag, MPI_COMM_WORLD) == MPI_SUCCESS) {

Test_Failed("Invalid Tag Test");

}

else

Test_Passed("Invalid Tag Test");

/* Тег сообщения слишком велик */

MPI_Attr_get( MPI_COMM_WORLD, MPI_TAG_UB, (void **)&tag_ubp, &flag );

if (!flag) Test_Failed("Could not get tag ub!" );

large_tag = *tag_ubp + 1;

if (large_tag > *tag_ubp) {

if (MPI_Send(buffer, 20, MPI_INT, dest,

-1, MPI_COMM_WORLD) == MPI_SUCCESS) {

Test_Failed("Invalid Tag Test");

}

else

Test_Passed("Invalid Tag Test");

}

if (MPI_Send(buffer, 20, MPI_INT, 300,

1, MPI_COMM_WORLD) == MPI_SUCCESS) {

Test_Failed("Invalid Destination Test");

}

else

Test_Passed("Invalid Destination Test");

if (MPI_Send((void *)0, 10, MPI_INT, dest,

1, MPI_COMM_WORLD) == MPI_SUCCESS){

Test_Failed("Invalid Buffer Test (send)");

}

else

Test_Passed("Invalid Buffer Test (send)");

}

void Test_Recv( void )

{

}

void Test_Datatype( void )

{

}

#ifdef FOO

void

ReceiverTest3()

{

int buffer[20];

MPI_Datatype bogus_type = MPI_DATATYPE_NULL;

MPI_Status status;

int myrank;

int *tag_ubp;

int large_tag, flag, small_tag;

MPI_Comm_rank( MPI_COMM_WORLD, &myrank );

if (myrank == 0) {

fprintf( stderr,

"There should be eight error messages about invalid communicator\n\

count argument, datatype argument, tag, rank, buffer send and buffer recv\n" );

}

/* Тест посылки сообщений может не выдавать ошибок, пока он не запущен */

if (MPI_Recv((void *)0, 10, MPI_INT, src,

15, MPI_COMM_WORLD, &status) == MPI_SUCCESS){

Test_Failed("Invalid Buffer Test (recv)");

}

else

Test_Passed("Invalid Buffer Test (recv)");

/* Прием посылаеммого сообщения */

{ int flag, ibuf[10];

MPI_Iprobe( src, 15, MPI_COMM_WORLD, &flag, &status );

if (flag)

MPI_Recv( ibuf, 10, MPI_INT, src, 15, MPI_COMM_WORLD, &status );

}

return;

#endif

Вывод результата работы программы для np=2

call_batch: calling batch

Null communicator

Null communicator

Passed: NULL Communicator Test

Invalid count argument is -1

Passed: Invalid Count Test

Datatype is MPI_TYPE_NULL

Passed: Invalid Type Test

Invalid message tag -2

Passed: Invalid Tag Test

Invalid message tag -1

Passed: Invalid Tag Test

Invalid rank 300

Passed: Invalid Destination Test

Invalid buffer pointer

Passed: Invalid Buffer Test (send)

Passed: NULL Communicator Test

Invalid count argument is -1

Passed: Invalid Count Test

Datatype is MPI_TYPE_NULL

Passed: Invalid Type Test

Invalid message tag -2

Passed: Invalid Tag Test

Вывод результата работы программы для np=32

call_batch: calling batch

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Null communicator

Passed: NULL Communicator Test

Invalid count argument is -1

Passed: Invalid Count Test

Datatype is MPI_TYPE_NULL

Passed: Invalid Type Test

Invalid message tag -2

Passed: Invalid Tag Test

Invalid message tag –1

Passed: Invalid Tag Test

Invalid rank 300

Passed: Invalid Destination Test

Invalid buffer pointer

Passed: Invalid Buffer Test (send)

Null communicator

Passed: NULL Communicator Test

Invalid count argument is -1

Passed: Invalid Count Test

Datatype is MPI_TYPE_NULL

Passed: Invalid Type Test

Invalid message tag -2

Passed: Invalid Tag Test

Invalid message tag -1

Passed: Invalid Tag Test

Invalid rank 300

Passed: Invalid Destination Test

Invalid buffer pointer

……………………………………………………

A7 Обмен сообщениями (ping_pong.f)

Этот пример измеряет скорость пересылки сообщений.

PROGRAM PingPong

INCLUDE 'mpif.h'

integer p

integer my_rank

integer test

integer min_size

integer max_size

integer incr

integer size

parameter (min_size = 0, max_size = 10000, incr = 200)

parameter (size = 80000)

double precision x(0:size)

integer pass

integer status(MPI_STATUS_SIZE)

integer ierr

integer i

double precision wtime_overhead

double precision start, finish,timex

double precision raw_time, cumulativ,y,tmin

double precision dtime(0:127,0:127),delta,tmax,tavg

double precision tmax2,tmin2,tavg2

integer comm, count(0:127)

integer MAX_ORDER, MAX

parameter (MAX_ORDER = 1000, MAX = 8)

character*23 nodes(0:127),dummy

character*4 pname(0:127), myname

C

call MPI_INIT( ierr)

call MPI_COMM_SIZE(MPI_COMM_WORLD, p, ierr )

call MPI_COMM_RANK(MPI_COMM_WORLD, my_rank, ierr )

call MPI_COMM_DUP(MPI_COMM_WORLD, comm, ierr )

call MPI_GET_PROCESSOR_NAME(myname,len,ierr)

call MPI_GATHER(myname,4,MPI_CHARACTER,pname,4,

+ MPI_CHARACTER,0,MPI_COMM_WORLD,ierr)

call MPI_BCAST(pname,512,MPI_CHARACTER,0,MPI_COMM_WORLD,ierr)

if(my_rank.eq.0) print*,"Starting..."

C

C

y=4.D0*DATAN(1.D0)

do 9 i=1,size

x(i)=y

9 continue

noff=mod(p,2)

C mynoff=mod(myrank,2)

if(noff.eq.1) then

print*, "Error: odd number of processes..."

stop

endif

print 181, my_rank

tavg=0.D0

tmin=99.D99

tmax=0.D0

delta=3.0D-004

C nloops=20

nloops=200

mynoff=mod(my_rank,2)

do 101 nnn=0,1

do 100 i=1,p-1,2

ndest=my_rank+i

nsend=my_rank-i

if(ndest.ge.p) ndest=mod(ndest,p)

if(nsend.lt.0) nsend=nsend+p

call MPI_BARRIER(comm, ierr)

if (mynoff.eq.nnn) then

timex=0.D0

do 20 k=1,nloops

start = MPI_WTIME()

call MPI_SEND(x, size,MPI_DOUBLE_PRECISION,

+ ndest,0,comm,ierr)

finish = MPI_WTIME()

timex=timex+(finish-start)

11 continue

20 continue

ttime=timex/dble(nloops)

tavg=tavg+ttime

if(ttime.gt.tmax) tmax=ttime

if(ttime.lt.tmin) tmin=ttime

else

nflag=0

do 22 k=1,nloops

call MPI_RECV(x,size,MPI_DOUBLE_PRECISION,nsend,

+ 0,comm,status, ierr)

do 21 k1=1,size

if (DABS(x(k1)-y).gt.1D-16) then

print 179, x(k1)

print 182, nsend,comm,status,ierr

print 180, my_rank, k1, k1

print 178, y

nflag=1

endif

21 continue

22 continue

if(nflag.eq.1)print 177, pname(nsend),

+ pname(my_rank),nsend,my_rank

endif

100 continue

101 continue

call MPI_REDUCE(tmin, tmin2, 1, MPI_DOUBLE_PRECISION, MPI_MIN, 0,

+ MPI_COMM_WORLD, ierr)

call MPI_REDUCE(tmax, tmax2, 1, MPI_DOUBLE_PRECISION, MPI_MAX, 0,

+ MPI_COMM_WORLD, ierr)

call MPI_REDUCE(tavg, tavg2, 1, MPI_DOUBLE_PRECISION, MPI_SUM, 0,

+ MPI_COMM_WORLD, ierr)

if (my_rank.eq.0) then

print*,"Max time: ",tmax2

print*,"Min time: ",tmin2

print*,"Avg time: ",tavg2/dble(p**2/4)

endif

176 format("Excessive Message Delay?: ",A," -> ",A,2x,I3,2x,I3,

+ 2x,D17.10)

177 format("Message Error: ",A," -> ",A,2x,I3,2x,I3,2x,D17.10,2x,

+ D17.10)

181 format(2x,"my rank ", I5)

178 format(10x,"Sent: ",Z17)

179 format(10x,"Recv: ",Z17)

182 format(5x,"Message from",2x,I3,3x,"comm",2x,I4,3x,"status",

+ 2x,Z8,3x,"ierr",2x,I4)

180 format(12x,"my rank ",I4,3x,"index ",I8,3x,"in hex",Z8)

call MPI_FINALIZE(ierr)

end

Вывод результата работы программы для np=2

call_batch: calling batch

Starting...

my rank 1

my rank 0

Max time: 3.239690558984876E-003

Min time: 3.174345009028912E-003

Avg time: 6.414035568013787E-003

A8 Тест эффективности основных операций MPI ( mpitest)

#include

#include

#include

#define Wtime MPI_Wtime

#define MEGABYTE (1024*1024)

#define BUFFER_SIZE 1024

#define TAG1 17

#define MASTER_RANK 0

#define MAX_REQUESTS 16

#define MILLION 1000000.0

static int NTIMES = 10000;

static int NTIMES_PREC = 100000;

#define NTIMES_TIMING NTIMES_PREC

#define NTIMES_BARRIER NTIMES_PREC

#define NTIMES_LATENCY NTIMES_PREC

#define TEST_SENDRECV 0

#define MASTER if(i_am_the_master)

int nproc,myid;

int i_am_the_master = 0;

int buf[BUFFER_SIZE],obuf[BUFFER_SIZE];

void Test_MPI_Routines(MPI_Comm comm);

int main(int argc,char *argv[]) {

int i;

double t_start,t_end;

MPI_Init(&argc,&argv);

MPI_Comm_size(MPI_COMM_WORLD,&nproc);

MPI_Comm_rank(MPI_COMM_WORLD,&myid);

i_am_the_master = (myid == MASTER_RANK);

t_start = Wtime();

MASTER printf("MPItest/C 1.0: running %d processes...\n",nproc);

if(nproc < 4) {

MASTER printf("MPItest expects at least 4 processes\n");

MPI_Finalize();

exit(0);

}

MASTER /* читает параметры коммандной строки */

for(i = 1; i < argc; i ++)

switch(argv[i][0]) {

case 'T': NTIMES = atoi(argv[i]+1); break; case 't': NTIMES_PREC = atoi(argv[i]+1); break; default: fprintf(stderr,"WARNING: unrecognized option: %s\n",argv[i]);

break;

}

MPI_Bcast(&NTIMES,1,MPI_INT,MASTER_RANK,MPI_COMM_WORLD);

MPI_Bcast(&NTIMES_PREC,1,MPI_INT,MASTER_RANK,MPI_COMM_WORLD);

MASTER printf("Testing basic MPI routines.\n");

Test_MPI_Routines(MPI_COMM_WORLD);

t_end = Wtime();

MASTER printf("MPItest/C complete in %g sec.\n",t_end-t_start);

MPI_Finalize();

return 0;

}

void Test_MPI_Routines(MPI_Comm comm) {

int nproc,myid,i;

int i_am_the_master = 0;

double t, t1, t2, tt, dt, lat, tb;

MPI_Status status, statuses[MAX_REQUESTS];

MPI_Request request, requests[MAX_REQUESTS];

MPI_Comm_size(MPI_COMM_WORLD,&nproc);

MPI_Comm_rank(MPI_COMM_WORLD,&myid);

i_am_the_master = (myid == MASTER_RANK);

MPI_Barrier(comm);

/* Инициализация буффера */

for(i = 0; i < BUFFER_SIZE; i ++) buf[i] = myid;

/* ----- Измерение времени между вызовами MPI_Wtime() ------ */

MASTER printf("** Timing for MPI operations in microseconds ***\n");

dt = 0;

MASTER for(i = 0; i < NTIMES_TIMING; i ++)

{

t1 = Wtime();

t2 = Wtime();

dt += (t2 - t1);

}

dt /= (double) NTIMES_TIMING;

t = dt;

t *= MILLION;

MASTER printf("%g\t\tTiming\n",t);

fflush(stdout);

/* ----------- Проверка барьера синхронизации ---------- */

tb = 0;

for(i = 0; i < NTIMES_BARRIER; i ++)

{

MPI_Barrier(comm);

t1 = Wtime();

MPI_Barrier(comm);

t2 = Wtime();

tb += (t2 - t1 - dt);

}

tb /= (double) NTIMES_BARRIER;

t = tb;

t *= MILLION;

MASTER printf("%g\t\tBarrier\n",t);

fflush(stdout);

/* ----- Объединение данных от всех ветвей с помощью MPI_Allreduce ------ */

t = 0;

for(i = 0; i < NTIMES; i ++)

{

MPI_Barrier(comm);

t1 = Wtime();

MPI_Allreduce(buf,obuf,1,MPI_INT,MPI_SUM,comm);

MPI_Barrier(comm);

t2 = Wtime();

t += (t2 - t1 - dt - tb);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\tGlobal sum (Allreduce)\n",t);

fflush(stdout);

/* -------Объединение данных от всех ветвей с помощью MPI_Allreduce ------ */

t = 0;

for(i = 0; i < NTIMES; i ++)

{

MPI_Barrier(comm);

t1 = Wtime();

MPI_Allreduce(buf,obuf,10,MPI_INT,MPI_SUM,comm);

MPI_Barrier(comm);

t2 = Wtime();

t += (t2 - t1 - dt - tb);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\t10 global sums (Allreduce)\n",t);

fflush(stdout);

/* -------Объединение данных от всех ветвей с помощью MPI_Allreduce ------ */

t = 0;

for(i = 0; i < NTIMES; i ++)

{

MPI_Barrier(comm);

t1 = Wtime();

MPI_Reduce(buf,obuf,1,MPI_INT,MPI_SUM,MASTER_RANK,comm);

t2 = Wtime();

t += (t2 - t1 - dt);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\tGlobal sum (Reduce)\n",t);

fflush(stdout);

/* -------Объединение данных от всех ветвей с помощью MPI_Allreduce ------ */

t = 0;

for(i = 0; i < NTIMES; i ++)

{

MPI_Barrier(comm);

t1 = Wtime();

MPI_Reduce(buf,obuf,10,MPI_INT,MPI_SUM,MASTER_RANK,comm);

t2 = Wtime();

t += (t2 - t1 - dt);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\t10 Global sums (Reduce)\n",t);

fflush(stdout);

/*Использование процедуры передачи сообщения от главного процесса остальным*/

t = 0;

for(i = 0; i < NTIMES; i ++)

{

MPI_Barrier(comm);

t1 = Wtime();

MPI_Bcast(buf,1,MPI_INT,MASTER_RANK,comm);

MPI_Barrier(comm);

t2 = Wtime();

t += (t2 - t1 - dt - tb);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\tBroadcast\n",t);

fflush(stdout);

/* Использование процедуры сбора сообщений главным процессом от остальных */

t = 0;

for(i = 0; i < NTIMES; i ++)

{

MPI_Barrier(comm);

t1 = Wtime();

MPI_Gather(buf,1,MPI_INT,obuf,1,MPI_INT,MASTER_RANK,comm);

MPI_Barrier(comm);

t2 = Wtime();

t += (t2 - t1 - dt - tb);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\tGather\n",t);

fflush(stdout);

/* Использование неблокирующей посылки сообщений и ожидания ее конца MPI_Wait */

t = 0;

if(i_am_the_master)

for(i = 0; i < NTIMES; i ++)

{

t1 = Wtime();

MPI_Isend(buf,10,MPI_INT,1,TAG1,comm,&request);

MPI_Wait(&request,&status);

t2 = Wtime();

t += (t2 - t1 - dt);

}

else if(myid == 1)

for(i = 0; i < NTIMES; i ++)

{

MPI_Irecv(obuf,10,MPI_INT,MASTER_RANK,TAG1,comm,&request);

MPI_Wait(&request,&status);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\tNon-blocking send with wait\n",t);

fflush(stdout);

/* Использование блокирующей посылки сообщений ---------- */

t = 0;

if(i_am_the_master)

for(i = 0; i < NTIMES; i ++)

{

t1 = Wtime();

MPI_Send(buf,10,MPI_INT,1,TAG1,comm);

t2 = Wtime();

t += (t2 - t1 - dt);

}

else if(myid == 1)

for(i = 0; i < NTIMES; i ++)

MPI_Recv(obuf,10,MPI_INT,MASTER_RANK,TAG1,comm,&status);

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\tBlocking vector send\n",t);

fflush(stdout);

/* -------- Использование одновременной передачи и приема сообщения ---- */

t = 0;

if(i_am_the_master)

for(i = 0; i < NTIMES; i ++)

{

t1 = Wtime();

MPI_Sendrecv(buf,1,MPI_INT,1,TAG1,obuf,1, MPI_INT, 1, TAG1, comm,statuses);

t2 = Wtime();

t += (t2 - t1 - dt);

}

else if(myid == 1)

for(i = 0; i < NTIMES; i ++)

MPI_Sendrecv(buf, 1, MPI_INT, MASTER_RANK, TAG1,obuf, 1, MPI_INT, MASTER_RANK, TAG1, comm,statuses);

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\tSendRecv\n",t);

fflush(stdout);

/* -- Использование последовательной передачи и приема сообщения ----*/

t = 0;

if(i_am_the_master)

for(i = 0; i < NTIMES; i ++)

{

t1 = Wtime();

MPI_Send(buf,1,MPI_INT,1,TAG1,comm);

MPI_Recv(obuf,1,MPI_INT, 1,TAG1,comm,&status);

t2 = Wtime();

t += (t2 - t1 - dt);

}

else if(myid == 1)

for(i = 0; i < NTIMES; i ++)

{

MPI_Recv(obuf,1,MPI_INT,MASTER_RANK,TAG1,comm,&status);

MPI_Send(buf,1,MPI_INT,MASTER_RANK,TAG1,comm);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\tSend and receive\n",t);

fflush(stdout);

/* ----Одновременное выполнение запросов на посылка сообщенияs ---- */

#if 1

t = 0;

if(i_am_the_master)

{

MPI_Send_init(&buf[0],1,MPI_INT,1,TAG1,comm,&requests[0]);

MPI_Send_init(&buf[1],1,MPI_INT,1,TAG1,comm,&requests[1]);

MPI_Send_init(&buf[2],1,MPI_INT,1,TAG1,comm,&requests[2]);

MPI_Send_init(&buf[3],1,MPI_INT,1,TAG1,comm,&requests[3]);

MPI_Send_init(&buf[4],1,MPI_INT,1,TAG1,comm,&requests[4]);

for(i = 0; i < NTIMES; i ++)

{

t1 = Wtime();

MPI_Startall(5,requests);

MPI_Waitall(5,requests,statuses);

t2 = Wtime();

t += (t2 - t1 - dt);

}

MPI_Request_free(&requests[0]);

MPI_Request_free(&requests[1]);

MPI_Request_free(&requests[2]);

MPI_Request_free(&requests[3]);

MPI_Request_free(&requests[4]);

}

else if(myid == 1)

{

MPI_Recv_init(&obuf[0],1,MPI_INT,0,TAG1,comm,&requests[0]);

MPI_Recv_init(&obuf[1],1,MPI_INT,0,TAG1,comm,&requests[1]);

MPI_Recv_init(&obuf[2],1,MPI_INT,0,TAG1,comm,&requests[2]);

MPI_Recv_init(&obuf[3],1,MPI_INT,0,TAG1,comm,&requests[3]);

MPI_Recv_init(&obuf[4],1,MPI_INT,0,TAG1,comm,&requests[4]);

for(i = 0; i < NTIMES; i ++)

{

MPI_Startall(5,requests);

MPI_Waitall(5,requests,statuses);

}

MPI_Request_free(&requests[0]);

MPI_Request_free(&requests[1]);

MPI_Request_free(&requests[2]);

MPI_Request_free(&requests[3]);

MPI_Request_free(&requests[4]);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\t5 sends in one\n",t);

fflush(stdout);

#endif

/* ----------- Выполнение посылки сообщения по запросу ---------- */

t = 0;

if(i_am_the_master)

for(i = 0; i < NTIMES; i ++)

{

t1 = Wtime();

MPI_Isend(&buf[0],1,MPI_INT,1,TAG1,comm, &requests[0]);

MPI_Isend(&buf[0],1,MPI_INT,1,TAG1,comm, &requests[1]);

MPI_Isend(&buf[0],1,MPI_INT,1,TAG1,comm, &requests[2]);

MPI_Isend(&buf[0],1,MPI_INT,1,TAG1,comm, &requests[3]);

MPI_Isend(&buf[0],1,MPI_INT,1,TAG1,comm, &requests[4]);

MPI_Waitall(5,requests,statuses);

t2 = Wtime();

t += (t2 - t1 - dt);

}

else if(myid == 1)

for(i = 0; i < NTIMES; i ++)

{

MPI_Irecv(&obuf[0],1,MPI_INT,MASTER_RANK,TAG1,comm, &requests[0]);

MPI_Irecv(&obuf[1],1,MPI_INT,MASTER_RANK,TAG1,comm, &requests[1]);

MPI_Irecv(&obuf[2],1,MPI_INT,MASTER_RANK,TAG1,comm, &requests[2]);

MPI_Irecv(&obuf[3],1,MPI_INT,MASTER_RANK,TAG1,comm, &requests[3]);

MPI_Irecv(&obuf[4],1,MPI_INT,MASTER_RANK,TAG1,comm, &requests[4]);

MPI_Waitall(5,requests,statuses);

}

t /= (double) NTIMES;

t *= MILLION;

MASTER printf("%g\t\t5 async. sends\n",t);

fflush(stdout);

/* ----------- Проверка посылки\приема сигнала ---------- */

t = 0;

if(i_am_the_master)

for(i = 0; i < NTIMES_LATENCY; i ++)

{

t1 = Wtime();

/* Was:

MPX_Sig_send(1,TAG1,comm);

MPX_Sig_wait(1,TAG1,comm);

*/

MPI_Send(NULL,0,MPI_INT,1,TAG1,comm);

MPI_Recv(NULL,0,MPI_INT,1,TAG1,comm,&status);

t2 = Wtime();

t += (t2 - t1 - dt);

}

else if(myid == 1)

for(i = 0; i < NTIMES_LATENCY; i ++)

{

MPI_Recv(NULL,0,MPI_INT,MASTER_RANK,TAG1,comm,&status);

MPI_Send(NULL,0,MPI_INT,MASTER_RANK,TAG1,comm);

}

t /= (double) NTIMES_LATENCY;

t *= MILLION;

MASTER printf("%g\t\tsignal sending (latency)\n",t);

fflush(stdout);

}

Вывод результата работы программы для np=5

call_batch: calling batch

MPItest/C 1.0: running 5 processes...

Testing basic MPI routines.

** Timing for MPI operations in microseconds ***

0.655001 Timing

60.8215 Barrier

48.7546 Global sum (Allreduce)

52.8754 10 global sums (Allreduce)

48.4172 Global sum (Reduce)

48.7901 10 Global sums (Reduce)

26.4905 Broadcast

8.60672 Gather

0.908893 Non-blocking send with wait

0.909001 Blocking vector send

4.42849 SendRecv

5.79681 Send and receive

7712.04 5 sends in one

Вывод результата работы программы для np=32

call_batch: calling batch

MPItest/C 1.0: running 32 processes...

Testing basic MPI routines.

** Timing for MPI operations in microseconds ***

0.614616 Timing

172.913 Barrier

143.482 Global sum (Allreduce)

152.485 10 global sums (Allreduce)

138.163 Global sum (Reduce)

116.008 10 Global sums (Reduce)

58.7728 Broadcast

17.9147 Gather

1.63228 Non-blocking send with wait

1.2411 Blocking vector send

4.4676 SendRecv

5.83727 Send and receive

A9 Пример программы с использованием профилировочных библиотек MPE ( cpilog.c)

Эта программа вычисляет число pi , и выводит информацию о времени вычисления для каждого процесса отдельно. Программа использует профилировочные библиотеки MPE. Просмотр файла регистрационного журнала cpilog.clog можно выполнить при помощи утилиты Jumpshot-2

#include "mpi.h"

#include "mpe.h"

#include

#include

double f( double );

double f( double a)

{

return (4.0 / (1.0 + a*a));

}

int main( int argc, char *argv[])

{

int n, myid, numprocs, i, j;

double PI25DT = 3.141592653589793238462643;

double mypi, pi, h, sum, x;

double startwtime = 0.0, endwtime;

int namelen;

int event1a, event1b, event2a, event2b,

event3a, event3b, event4a, event4b;

char processor_name[MPI_MAX_PROCESSOR_NAME];

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);

fprintf(stderr,"Process %d running on %s\n", myid, processor_name);

/*

MPE_Init_log() & MPE_Finish_log() не нуждается в библиотеке liblmpe.a. Но в случае ее прилинкования ,

MPI_Init() автоматически вызовет процедуре MPE_Init_log().

*/

/*

MPE_Init_log();

*/

/* Назначение ID номера от MPE, пользователю не надо делать это вручную */

event1a = MPE_Log_get_event_number();

event1b = MPE_Log_get_event_number();

event2a = MPE_Log_get_event_number();

event2b = MPE_Log_get_event_number();

event3a = MPE_Log_get_event_number();

event3b = MPE_Log_get_event_number();

event4a = MPE_Log_get_event_number();

event4b = MPE_Log_get_event_number();

if (myid == 0) {

MPE_Describe_state(event1a, event1b, "Broadcast", "red");

MPE_Describe_state(event2a, event2b, "Compute", "blue");

MPE_Describe_state(event3a, event3b, "Reduce", "green");

MPE_Describe_state(event4a, event4b, "Sync", "orange");

}

if (myid == 0)

{

n = 1000000;

startwtime = MPI_Wtime();

}

MPI_Barrier(MPI_COMM_WORLD);

MPE_Start_log();

for (j = 0; j < 5; j++)

{

MPE_Log_event(event1a, 0, "start broadcast");

MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);

MPE_Log_event(event1b, 0, "end broadcast");

MPE_Log_event(event4a,0,"Start Sync");

MPI_Barrier(MPI_COMM_WORLD);

MPE_Log_event(event4b,0,"End Sync");

MPE_Log_event(event2a, 0, "start compute");

h = 1.0 / (double) n;

sum = 0.0;

for (i = myid + 1; i <= n; i += numprocs)

{

x = h * ((double)i - 0.5);

sum += f(x);

}

mypi = h * sum;

MPE_Log_event(event2b, 0, "end compute");

MPE_Log_event(event3a, 0, "start reduce");

MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);

MPE_Log_event(event3b, 0, "end reduce");

}

/*

MPE_Finish_log("cpilog");

*/

if (myid == 0)

{

endwtime = MPI_Wtime();

printf("pi is approximately %.16f, Error is %.16f\n",

pi, fabs(pi - PI25DT));

printf("wall clock time = %f\n", endwtime-startwtime);

}

MPI_Finalize();

return(0);

}

Для просмотра файла регистрационного журнала в текстовом режиме можно использовать утилиту clog_print, например:

./clog_print cpilog.clog >> readfile

Для данного примера файл регистрационного журнала будет следующим:

ts=0.000000 type=loc len=9, pid=0 srcid=900 line=339 file=clog.c

ts=0.000000 type=comm len=5, pid=0 et=init pt=-1 ncomm=91 srcid=900

ts=0.000000 type=loc len=9, pid=0 srcid=901 line=284 file=clog.c

ts=0.000000 type=raw len=7, pid=0 id=-201 data=-1 srcid=901 desc=MPI_PROC_NULL

ts=0.000000 type=raw len=7, pid=0 id=-201 data=-2 srcid=901 desc=MPI_ANY_SOURCE

ts=0.000000 type=raw len=7, pid=0 id=-201 data=-1 srcid=901 desc=MPI_ANY_TAG

ts=0.001953 type=loc len=9, pid=0 srcid=902 line=364 file=clog.c

ts=0.001953 type=sdef len=10, pid=0 id=200 start=500 end=501 color=red desc=Broa

ts=0.001953 type=sdef len=10, pid=0 id=201 start=502 end=503 color=blue desc=Com

ts=0.001953 type=sdef len=10, pid=0 id=202 start=504 end=505 color=green desc=Re

ts=0.001953 type=sdef len=10, pid=0 id=203 start=506 end=507 color=orange desc=S

ts=0.001953 type=raw len=7, pid=0 id=11 data=1 srcid=901 desc=

ts=0.001953 type=raw len=7, pid=0 id=12 data=2 srcid=901 desc=

ts=0.001953 type=raw len=7, pid=0 id=500 data=0 srcid=901 desc=start broadcast

ts=0.001953 type=raw len=7, pid=0 id=13 data=1 srcid=901 desc=

ts=0.001953 type=raw len=7, pid=0 id=14 data=2 srcid=901 desc=

ts=0.001953 type=raw len=7, pid=0 id=501 data=0 srcid=901 desc=end broadcast

ts=0.001953 type=raw len=7, pid=0 id=506 data=0 srcid=901 desc=Start Sync

ts=0.001953 type=raw len=7, pid=0 id=11 data=3 srcid=901 desc=

ts=0.001953 type=raw len=7, pid=0 id=12 data=4 srcid=901 desc=

ts=0.001953 type=raw len=7, pid=0 id=507 data=0 srcid=901 desc=End Sync

ts=0.001953 type=raw len=7, pid=0 id=502 data=0 srcid=901 desc=start compute

ts=0.020508 type=raw len=7, pid=0 id=503 data=0 srcid=901 desc=end compute

ts=0.020508 type=raw len=7, pid=0 id=503 data=0 srcid=901 desc=end compute

ts=0.020508 type=raw len=7, pid=0 id=504 data=0 srcid=901 desc=start reduce

ts=0.020508 type=raw len=7, pid=0 id=25 data=1 srcid=901 desc=

ts=0.020508 type=raw len=7, pid=0 id=26 data=2 srcid=901 desc=

Характеристики

Тип файла
Документ
Размер
555,5 Kb
Тип материала
Высшее учебное заведение

Список файлов учебной работы

Свежие статьи
Популярно сейчас
А знаете ли Вы, что из года в год задания практически не меняются? Математика, преподаваемая в учебных заведениях, никак не менялась минимум 30 лет. Найдите нужный учебный материал на СтудИзбе!
Ответы на популярные вопросы
Да! Наши авторы собирают и выкладывают те работы, которые сдаются в Вашем учебном заведении ежегодно и уже проверены преподавателями.
Да! У нас любой человек может выложить любую учебную работу и зарабатывать на её продажах! Но каждый учебный материал публикуется только после тщательной проверки администрацией.
Вернём деньги! А если быть более точными, то автору даётся немного времени на исправление, а если не исправит или выйдет время, то вернём деньги в полном объёме!
Да! На равне с готовыми студенческими работами у нас продаются услуги. Цены на услуги видны сразу, то есть Вам нужно только указать параметры и сразу можно оплачивать.
Отзывы студентов
Ставлю 10/10
Все нравится, очень удобный сайт, помогает в учебе. Кроме этого, можно заработать самому, выставляя готовые учебные материалы на продажу здесь. Рейтинги и отзывы на преподавателей очень помогают сориентироваться в начале нового семестра. Спасибо за такую функцию. Ставлю максимальную оценку.
Лучшая платформа для успешной сдачи сессии
Познакомился со СтудИзбой благодаря своему другу, очень нравится интерфейс, количество доступных файлов, цена, в общем, все прекрасно. Даже сам продаю какие-то свои работы.
Студизба ван лав ❤
Очень офигенный сайт для студентов. Много полезных учебных материалов. Пользуюсь студизбой с октября 2021 года. Серьёзных нареканий нет. Хотелось бы, что бы ввели подписочную модель и сделали материалы дешевле 300 рублей в рамках подписки бесплатными.
Отличный сайт
Лично меня всё устраивает - и покупка, и продажа; и цены, и возможность предпросмотра куска файла, и обилие бесплатных файлов (в подборках по авторам, читай, ВУЗам и факультетам). Есть определённые баги, но всё решаемо, да и администраторы реагируют в течение суток.
Маленький отзыв о большом помощнике!
Студизба спасает в те моменты, когда сроки горят, а работ накопилось достаточно. Довольно удобный сайт с простой навигацией и огромным количеством материалов.
Студ. Изба как крупнейший сборник работ для студентов
Тут дофига бывает всего полезного. Печально, что бывают предметы по которым даже одного бесплатного решения нет, но это скорее вопрос к студентам. В остальном всё здорово.
Спасательный островок
Если уже не успеваешь разобраться или застрял на каком-то задание поможет тебе быстро и недорого решить твою проблему.
Всё и так отлично
Всё очень удобно. Особенно круто, что есть система бонусов и можно выводить остатки денег. Очень много качественных бесплатных файлов.
Отзыв о системе "Студизба"
Отличная платформа для распространения работ, востребованных студентами. Хорошо налаженная и качественная работа сайта, огромная база заданий и аудитория.
Отличный помощник
Отличный сайт с кучей полезных файлов, позволяющий найти много методичек / учебников / отзывов о вузах и преподователях.
Отлично помогает студентам в любой момент для решения трудных и незамедлительных задач
Хотелось бы больше конкретной информации о преподавателях. А так в принципе хороший сайт, всегда им пользуюсь и ни разу не было желания прекратить. Хороший сайт для помощи студентам, удобный и приятный интерфейс. Из недостатков можно выделить только отсутствия небольшого количества файлов.
Спасибо за шикарный сайт
Великолепный сайт на котором студент за не большие деньги может найти помощь с дз, проектами курсовыми, лабораторными, а также узнать отзывы на преподавателей и бесплатно скачать пособия.
Популярные преподаватели
Добавляйте материалы
и зарабатывайте!
Продажи идут автоматически
6390
Авторов
на СтудИзбе
307
Средний доход
с одного платного файла
Обучение Подробнее