Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lab2.doc
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
178.18 Кб
Скачать

1.4 Визначені константи типу елементів повідомлень

Константи MPI

Тип в C

MPI_CHAR

signed char

MPI_SHORT

signed int

MPI_INT

signed int

MPI_LONG

signed long int

MPI_UNSIGNED_CHAR

unsigned char

MPI_UNSIGNED_SHORT

unsigned int

MPI_UNSIGNED

unsigned int

MPI_UNSIGNED_LONG

unsigned long int

MPI_FLOAT

float

MPI_DOUBLE

double

MPI_LONG_DOUBLE

long double

Інші визначені типи

MPI_Status - структура; атрибути повідомлень; містить три обов'язкові поля:

  • MPI_Source (номер процесу відправника)

  • MPI_Tag (ідентифікатор повідомлення)

  • MPI_Error (код помилки)

MPI_Request - системний тип; ідентифікатор операції посилки-прийому повідомлення

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

  • MPI_COMM_WORLD - зарезервований ідентифікатор групи, що складає їхніх всіх процесів програми

Константи-заглушки

  • MPI_COMM_NULL

  • MPI_DATATYPE_NULL

  • MPI_REQUEST_NULL

Константа невизначеного значення

  • MPI_UNDEFINED

Глобальні операції

MPI_MAX

MPI_MIN

MPI_SUM

MPI_PROD

Будь-який процес/ідентифікатор

MPI_ANY_SOURCE

MPI_ANY_TAG

Код успішного завершення процедури

MPI_SUCCESS

2. Хід роботи

    1. Уважно ознайомтеся із теоретичною частиною лабораторної роботи.

    2. Уважно ознайомтеся з наступним кодом програми, щоб зрозуміти принципи написання паралельних програм з використанням МРІ.

#include <stdio.h>

#include "mpi.h"

/*

* Початок і завершення:

* MPI_Init, MPI_Finalize

* Функції визначення кількості завдань у програмі й свого порядкового номера:

* MPI_Comm_size, MPI_Comm_rank

*/

int main( int argc, char **argv )

{

int size, rank, i;

/* Ініціалізуємо бібліотеку */

MPI_Init( &argc, &argv );

/* Визначаємо кількість завдань у запущеному додатку */

MPI_Comm_size( MPI_COMM_WORLD, &size );

/* ... і свій власний номер: від 0 до (size-1) */

MPI_Comm_rank( MPI_COMM_WORLD, &rank );

/* завдання з номером 0 повідомляють користувача розмір групи,

* до якої прикріплена область зв'язку,

* до якої прикріплений описувач (комунікатор) MPI_COMM_WORLD,

* тобто число процесів у додатку!!

*/

if( rank==0 )

printf("Total processes count = %d\n", size );

/* Кожне завдання виводить користувачеві свій номер */

printf("Hello! My rank in MPI_COMM_WORLD = %d\n", rank );

/* Точка синхронізації, потім завдання 0 друкує

* аргументи командного рядка. У командному рядку

* можуть бути параметри, що додаються завантажником MPIRUN.

*/

MPI_Barrier( MPI_COMM_WORLD );

if( rank == 0 )

for( puts("Command line of process 0:"), i=0; i<argc; i++ )

printf( "%d: \"%s\"\n", i, argv[i] );

/* Всі завдання завершують виконання */

MPI_Finalize();

return 0;

}

Результат виконання програми

Total processes count = 11

Hello! My rank in MPI_COMM_WORLD = 0

Command line of process 0:

0: "C:\WMPI1.3\EXAMPLES\C\TEST\DEBUG\CONSOL~1.EXE"

1: "argument 0"

Hello! My rank in MPI_COMM_WORLD = 1

Hello! My rank in MPI_COMM_WORLD = 7

Hello! My rank in MPI_COMM_WORLD = 2

Hello! My rank in MPI_COMM_WORLD = 9

Hello! My rank in MPI_COMM_WORLD = 8

Hello! My rank in MPI_COMM_WORLD = 6

Hello! My rank in MPI_COMM_WORLD = 3

Hello! My rank in MPI_COMM_WORLD = 5

Hello! My rank in MPI_COMM_WORLD = 10

Hello! My rank in MPI_COMM_WORLD = 4

Наберіть код програми без коментарів (коментарі – усе що знаходиться в між /*....*/) у текстовому редакторі, відкомпілюйте та виконайте на віддаленому комп’ютері, так як було показано у Лабораторній роботі №1. Команди компіляції та запуску: mpicc та mpirun. Кількість паралельних процесів при виконанні вкажіть відповідно до вашого варіанту (Таблиця 2.1). Результат виконання програми скопіюйте у звіт.

Таблиця 2.1 – Варіанти завдань

№ в журналі

Кількість паралельних процесів

buffer (значення, що пересилається)

Тип даних

tag (ідентифікатор повідомлення)

1

2

"a"

MPI_CHAR

908

2

3

8373

MPI_SHORT

458

3

4

5977

MPI_INT

460

4

5

753922

MPI_LONG

541

5

6

253

MPI_UNSIGNED_CHAR

744

6

7

50949

MPI_UNSIGNED_SHORT

657

7

8

100

MPI_UNSIGNED

611

8

2

200

MPI_UNSIGNED_LONG

991

9

3

82,96

MPI_FLOAT

171

10

4

19,7

MPI_DOUBLE

789

11

5

580,3

MPI_LONG_DOUBLE

685

12

6

"b"

MPI_CHAR

567

13

7

1475

MPI_SHORT

399

14

8

7931

MPI_INT

574

15

2

7669441

MPI_LONG

261

16

3

215

MPI_UNSIGNED_CHAR

358

17

4

47684

MPI_UNSIGNED_SHORT

406

18

5

90

MPI_UNSIGNED

784

19

6

120

MPI_UNSIGNED_LONG

569

20

7

69,26

MPI_FLOAT

922

21

8

442,4

MPI_DOUBLE

993

22

2

9053,2

MPI_LONG_DOUBLE

752

23

3

"c"

MPI_CHAR

575

24

4

1964

MPI_SHORT

759

25

5

2459

MPI_INT

761

26

6

339017

MPI_LONG

188

27

7

244

MPI_UNSIGNED_CHAR

234

28

8

33525

MPI_UNSIGNED_SHORT

248

29

2

95

MPI_UNSIGNED

621

30

3

138

MPI_UNSIGNED_LONG

144

2.3 Уважно ознайомтеся з наступним кодом програми, щоб зрозуміти спосіб пересилки повідомлень між процесами. Наберіть код програми без коментарів у текстовому редакторі. Відкомпілюйте програму та виконайте на двох процесорах. Результат виконання програми скопіюйте у звіт.

#include <stdio.h>

#include "mpi.h"

/* Ідентифікатори повідомлень */

#define tagFloatData 1

#define tagDoubleData 2

/* Цей макрос створений для зручності, */

/* він дозволяє вказувати довжину масиву в кількості комірок*/

#define ELEMS(x) ( sizeof(x) / sizeof(x[0]) )

int main( int argc, char **argv )

{

int size, rank, count;

float floatData[10];

double doubleData[20];

MPI_Status status;

/* Ініціюємо бібліотеку */

MPI_Init( &argc, &argv );

/* Визначаємо кількість завдань у запущеному додатку */

MPI_Comm_size( MPI_COMM_WORLD, &size );

/* ... і свій власний номер: від 0 до (size-1) */

MPI_Comm_rank( MPI_COMM_WORLD, &rank );

/* користувач повинен запустити рівно два завдання, інакше буде помилка */

if( size != 2 ) {

/* завдання з номером 0 повідомляють користувача про помилку */

if( rank==0 )

printf("Error: two processes required instead of %d, abort\n",

size );

/* Всі завдання-абоненти коммунікатора MPI_COMM_WORLD

* будуть очыкувати, поки завдання 0 не виведе повідомлення.

*/

MPI_Barrier( MPI_COMM_WORLD );

/* Без крапки синхронізації може виявитися, що одне із завдань

* викличе MPI_Abort раніше, ніж встигне виконатись printf()

* у завданні 0, MPI_Abort негайно примусово завершить

* всі завдання й повідомлення виведене не буде

*/

/* всі завданння аварійно завершують роботу */

MPI_Abort(

MPI_COMM_WORLD, /* Комунікатор області зв'язку, на яку */

/* поширюється дія помилки */

MPI_ERR_OTHER ); /* Цілочисельний код помилки */

return -1;

}

if( rank==0 ) {

/* Завдання 0 щось таке передає завданню 1 */

MPI_Send(

floatData, /* 1) адреса переданого масиву */

5, /* 2) скільки: 5 осередків, тобто floatData[0]..floatData[4] */

MPI_FLOAT, /* 3) тип комірки */

1, /* 4) кому: завданню 1 */

tagFloatData, /* 5) ідентифікатор повідомлення */

MPI_COMM_WORLD ); /* 6) комунікатор області зв'язку, через яку */

/* відбувається передача */

/* і ще одна передача: дані іншого типу */

MPI_Send( doubleData, 6, MPI_DOUBLE, 1, tagDoubleData, MPI_COMM_WORLD );

} else {

/* Завдання 1 щось таке приймає від завдання 0 */

/* чекаємо повідомлення й поміщаємо дані, що прийшли, у буфер */

MPI_Recv(

doubleData, /* 1) адреса масиву, куди записується прийняте */

ELEMS( doubleData ), /* 2) фактична довжина прийнятих даних */

/* масиву в числі комірок */

MPI_DOUBLE, /* 3) повідомляємо MPI, що повідомлення, що прийшло, */

/* складається із чисел типу 'double' */

0, /* 4) від кого: від завдання 0 */

tagDoubleData, /* 5) очікуємо повідомлення з таким ідентифікатором */

MPI_COMM_WORLD, /* 6) комунікатор області зв'язку, через яку */

/* очікується прийом повідомлення */

&status ); /* 7) сюди буде записаний статус завершення прийому */

/* Обчислюємо фактично прийнята кількість даних */

MPI_Get_count(

&status, /* статус завершення */

MPI_DOUBLE, /* повідомляємо MPI, що повідомлення, що прийшло, */

/* складається із чисел типу 'double' */

&count ); /* сюди буде записаний результат */

/* Виводимо фактичну довжину прийнятого на екран */

printf("[DOUBLE] Received %d elems\n", count );

/* Аналогічно приймаємо повідомлення з даними типу float

* Зверніть увагу: завдання-приймач має можливість

* приймати повідомлення не в тім порядку, у якому вони

* відправлялися, якщо ці повідомлення мають різні ідентифікатори

*/

MPI_Recv( floatData, ELEMS( floatData ), MPI_FLOAT,

0, tagFloatData, MPI_COMM_WORLD, &status );

MPI_Get_count( &status, MPI_FLOAT, &count );

printf("[FLOAT] Received %d elems\n", count );

}

/* Обидва завдання завершують виконання */

MPI_Finalize();

return 0;

}

Результат виконання програми

[DOUBLE] Received 6 elems

[FLOAT] Received 5 elems

2.4 Розглянемо тепер дві програми, що виконують одну і ту ж задачу пересилки числового значення від одного процесу до іншого, однак перша програма з використанням синхронних процедур send/receive, а інша - асинхронних процедур isend/ireceive.

Наберіть код обох програм у текстовому редакторі та збережіть у вигляді вихідних програм на С. Змініть у програмах значення змінних tag=1234 (ідентифікатор повідомлення) та buffer=5678 (значення, що пересилається) відповідно до вашого варіанту (Таблиця 2.1). Врахуйте в програмі тип даних що передаються. Відкомпілюйте ці обидві програми та виконайте на двох процесорах.

Результат виконання обох програм скопіюйте у звіт. Проаналізуйте відмінності роботи кожної програми та занотуйте у звіт.

а) Пересилка повідомлення з використанням синхронних процедур.

#include <stdio.h>

#include "mpi.h"

#include <math.h>

int main(argc,argv)

int argc;

char *argv[];

{

int myid, numprocs;

int tag,source,destination,count;

int buffer;

MPI_Status status;

MPI_Init(&argc,&argv);

MPI_Comm_size(MPI_COMM_WORLD,&numprocs);

MPI_Comm_rank(MPI_COMM_WORLD,&myid);

tag=1234;

source=0;

destination=1;

count=1;

if(myid == source){

buffer=5678;

MPI_Send(&buffer,count,MPI_INT,destination,tag,MPI_COMM_WORLD);

printf("synchronous: processor %d sent %d\n",myid,buffer);

}

if(myid == destination){

MPI_Recv(&buffer,count,MPI_INT,source,tag,MPI_COMM_WORLD,&status);

printf("synchronous: processor %d got %d , message tag is %d\n", myid, buffer, tag);

}

MPI_Finalize();

}

б) Пересилка повідомлення з використанням асинхронних процедур.

#include <stdio.h>

#include "mpi.h"

#include <math.h>

int main(argc,argv)

int argc;

char *argv[];

{

int myid, numprocs;

int tag,source,destination,count;

int buffer;

MPI_Status status;

MPI_Request request;

MPI_Init(&argc,&argv);

MPI_Comm_size(MPI_COMM_WORLD,&numprocs);

MPI_Comm_rank(MPI_COMM_WORLD,&myid);

tag=1234;

source=0;

destination=1;

count=1;

request=MPI_REQUEST_NULL;

if(myid == source){

buffer=5678;

MPI_Isend(&buffer,count,MPI_INT,destination,tag,MPI_COMM_WORLD,&request);

}

if(myid == destination){

MPI_Irecv(&buffer,count,MPI_INT,source,tag,MPI_COMM_WORLD,&request);

}

MPI_Wait(&request,&status);

if(myid == source){

printf("asynchronous: processor %d sent %d\n",myid,buffer);

}

if(myid == destination){

printf("asynchronous: processor %d got %d, message tag is %d\n",myid,buffer,tag);

}

MPI_Finalize();

}

3. ЗМІСТ ЗВІТУ

    1. Тема, мета лабораторної роботи

    2. Короткі теоретичні відомості

    3. Опис виконання лабораторної роботи згідно пунктів 2.2-2.4

    4. Відповідь на одне контрольне запитання згідно номера варіанту (порядковий номер у списку журналу групи)

    5. Висновки

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]