Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Программирование для многопроцессорных систем в стандарте MPI - Шпаковский Г.И., Серикова Н.В

..pdf
Скачиваний:
240
Добавлен:
24.05.2014
Размер:
1.69 Mб
Скачать

8.Добавить для всех конфигураций библиотеку ws2_32.lib (Это библиотека Microsoft Winsock2 library. Она по умолчанию находится в вашем пути к биб-

лиотекам). Добавить mpich.lib в режим release и mpichd.lib в режим debug.

281

9.Закрыть диалоговое окно установки проекта.Добавить к проекту исходные файлы.

10. Build.

Запуск приложения обычно производится из командной строки с помощью оператора mpirun, например:

mpi run -np 4 cpi

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

Приложение 4. ХАРАКТЕРИСТИКИ КОММУНИКАЦИОННЫХ СЕТЕЙ ДЛЯ КЛАСТЕРОВ

Ниже приведены сравнительные характеристики некоторых сетей.

 

 

 

 

 

Таблица 1

Характеристики некоторых коммуникационных технологий

 

 

 

 

 

 

 

SCI

Myrinet

cLAN

ServerNet

Fast

 

 

 

 

 

Ethernet

Латентность

5,6 мкс

17 мкс

30 мкс

13 мкс

170 мкс

Пропускная спо-

80

40

100

180

10

собность ( MPI )

Мбайт/c

Мбайт/c

Мбайт/c

Мбайт/c

Мбайт/c

Пропускная спо-

400

160

150

н/д

12,5

собность (аппа-

Мбайт/c

Мбайт/c

Мбайт/c

 

Мбайт/c

ратная)

 

 

 

 

 

Реализация MPI

ScaMPI

HPVMи др.

MPI /Pro

MVICH

MPICH

282

Коммуникационные сети. Производительность коммуникационных сетей в кластерных системах определяют две основные характеристики: латентность – время начальной задержки при посылке сообщений и пропускная способность сети, определяющая скорость передачи информации по каналам связи. При этом важны не столько пиковые характеристики, заявляемые производителем, сколько реальные, достигаемые на уровне пользовательских приложений, например, на уровне 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 инсталляций по всему миру.

283

Узлы в Myrinet соединяются друг с другом через коммутатор (до 16 портов). Максимальная длина линий связи варьируется в зависимости от конкретной реализации. На данный момент наиболее распространены реализации сетей LAN и SAN. В последнем случае, при использовании в рамках вычислительной системы, длина кабеля не может превышать 3-х метров, а в LAN - 10,7 метра.

Приложение 5. ВАРИАНТЫ РЕШЕНИЯ ЗАДАНИЙ ДЛЯ САМОСТОЯТЕЛЬНОЙ РАБОТЫ

Задание 3.1.

#include <stdio.h> #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 <stdio.h> #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 );

}

284

printf( "Process %d got %d\n", rank, value ); } while (value >= 0);

MPI_Finalize( ); return 0; }

Задание 3.6.

#include "mpi.h" #include <stdio.h> int main(argc, argv) int argc;

char **argv;

{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 <stdio.h>

#include <stdlib.h> #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]; 285

}
else if (rank == 1)
{

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<NUMBER_OF_TESTS; k++)

{if (rank == 0)

{/* убедимся, что оба процесса готовы к приему/передаче */ 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<nloop; 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;

/* убедимся, что оба процесса готовы к приему/передаче */ MPI_Sendrecv( MPI_BOTTOM, 0, MPI_INT, 0, 14,

MPI_BOTTOM, 0, MPI_INT, 0, 14, MPI_COMM_WORLD, &status ); for (j=0; j<nloop; j++)

{MPI_Recv( buf, 1, vec1, 0, k, MPI_COMM_WORLD, &status ); 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 );

286

MPI_Type_free( &vec1 ); MPI_Finalize( );

return 0;

}

Задание 3.14.

/* пересылка вектора из 1000 элементов типа MPI_DOUBLE

со страйдом 24 между элементами. Используем MPI_Type_struct */ #include <stdio.h>

#include <stdlib.h> #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<NUMBER_OF_TESTS; k++)

{ if (rank == 0) { /* убедимся, что оба процесса готовы к приему/передаче */ 287

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<nloop; j++)

{MPI_Send( buf, n, vec_n, 1, k, MPI_COMM_WORLD ); 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<nloop; j++)

{MPI_Recv( buf, n, vec_n, 0, k, MPI_COMM_WORLD, &status ); 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;

}

Задание 3.15.

/* пересылка вектора из 1000 элементов типа MPI_DOUBLE со страйдом 24 между элементами. Самостоятельная упаковка и распаковка (не используем типы данных MPI) */

#include <stdio.h> #include <stdlib.h> #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;

 

 

288

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" ); tmin = 1000;

for (k=0; k<NUMBER_OF_TESTS; k++)

{ if (rank == 0) { /* убедимся, что оба процесса готовы к приему/передаче */

 

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<nloop; j++)

 

{ for (i=0; i<n; i++)

/* создаем пользовательский тип */

 

lbuf[i] = buf[i*stride];

 

MPI_Send( lbuf, n, MPI_DOUBLE, 1, k, MPI_COMM_WORLD );

 

MPI_Recv( lbuf, n, MPI_DOUBLE, 1, k, MPI_COMM_WORLD, &status );

 

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

buf[i*stride] = lbuf[i];

 

}

 

 

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<nloop; j++)

 

{ MPI_Recv( lbuf, n, MPI_DOUBLE, 0, k, MPI_COMM_WORLD, &status );

 

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

buf[i*stride] = lbuf[i];

 

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

lbuf[i] = buf[i*stride];

MPI_Send( lbuf, n, MPI_DOUBLE, 0, k, MPI_COMM_WORLD );

}

}

}

tmin = tmin / 2.0;

289

if (rank == 0)

printf( "User\t%d\t%d\t%f\t%f\n",n,stride,tmin, n *sizeof(double)*1.0e-6 / tmin ); MPI_Finalize( );

return 0;

}

Задание 3.18.

#include <mpi.h>

 

#include <memory.h>

 

#include <stdlib.h>

 

#include <stdio.h>

 

#include <malloc.h>

 

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

 

{ int iMyRank, i, gsize;

 

MPI_Comm _Comm = MPI_COMM_WORLD;

/* в группе все процессы */

MPI_Status status;

 

double x[100][100][100], e[9][9][9];

 

int oneslice, twoslice, threeslice, sizeof_double;

 

MPI_Init(&argc, &argv);

 

MPI_Comm_size(_Comm, &gsize);

 

MPI_Comm_rank(_Comm, &iMyRank);

 

/* извлекаем секцию а(1-17-2, 3-11, 2-10) и записываем в е */ MPI_Type_extent(MPI_DOUBLE, &sizeof_double);

MPI_Type_vector(9, 1, 2, MPI_DOUBLE, &oneslice); MPI_Type_hvector(9, 1, 100 * sizeof_double, oneslice, &twoslice); MPI_Type_hvector(9, 1, 100 * 100 * sizeof_double, twoslice, &threeslice); MPI_Type_commit(&threeslice);

MPI_Sendrecv(&x[1][3][2], 1, threeslice, iMyRank, 0, e, 9*9*9, MPI_DOUBLE, iMyRank, 0, MPI_COMM_WORLD, &status);

if (iMyRank == 0) { printf("x = (");

for (i = 0; i < 100; ++i) printf("%f", x[i]); printf(")");

}

MPI_Finalize(); return 0;

}

Задание 3.19.

#include <mpi.h> #include <memory.h> #include <stdlib.h> #include <stdio.h> #include <malloc.h> #define MATRIXSIZE 10

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

290

Соседние файлы в предмете Программирование