1.2.
Системы с распределенной памятью
В системах этого типа на каждом вычислительном узле функционирует собственные копии
операционной системы, под управлением которых выполняются независимые программы.
Это могут быть как действительно независимые программы, так и параллельные ветви одной
программы. В этом случае единственно возможным механизмом взаимодействия между ними
является механизм передачи сообщений. Этот механизм реализуется в виде прикладных
библиотек, которые должны подключаться к параллельной программе.
Для систем с распределенной памятью широко применяется интерфейс MPI—Message
Passing Interface.
Message Passing
● Метод передачи данных из памяти одного процессора в память другого
● Данные пересылаются в виде пакетов
● Сообщение может состоять из одного или нескольких пакетов
Стандарт MPI-1 включает в себя следующие базовые функции:
2. //todo
2.1 Критические секции
Критическая секция -это область кода, в котором вследствие некоторых
последовательностей разного доступа, могут генерироваться различные результаты.
Сущности доступа это потоки или процессы. Ссылаясь на критическую зону, также
можно подразумевать набор данных, которые могут быть открыты для доступа для
большего количества процессов/потоков.
Критическая секция, к которой доступ не синхронизирован (т.е не может быть
гарантирована четкая последовательность доступа) генерирует так называемые
условия гонки (race condition). Появление подобного условия может генерировать
разные результаты в одинаковых контекстах.
Пример критической секции представлен в виде псевдокода:
Ex1 Ex2
a := 0 for i = 1 to 15 do
for i = 1 to 15 do a := a + 1
a := a + 1 end
end
print (a)
/*
[Hancu_B_S@hpc Open_MP]$ /opt/openmpi/bin/mpirun -n 8 -machinefile
The count of threads on the MPI process 7 of the compute node '--compute0-1.local--' is 2
...
The count of threads on the MPI process 3 of the compute node '--compute0-0.local--' is 2
Total number of threads=16
6.1. Определение общего числа процессов(потоков) всех хостов.
Для 1 процессора ( -n 1) результат Total number = 2 --- (1 процессор * 2 потока)
Для 2 процессора ( -n 2) результат Total number = 4 --- (2 процессор * 2 потока)
Chunksare groups of iterations (in contiguous order) that are assigned to threads (размер куска
кода/блока)
Программист может контролировать то, каким образом потоки будут загружаться работой
при обработке цикла. Существует несколько вариантов.
static является вариантом по умолчанию. Ещё до входа в цикл каждый поток «знает», какие
части цикла он будет обрабатывать.
Static-Divide the loop into equal-sized chunks or as equal as possible in the case where the number
of loop iterations is not evenly divisible by the number of threads multiplied by the chunk size. By
default, chunk size is loop_count/number_of_threads.Set chunk to 1 to interleave the iterations.
(https://software.intel.com/en-us/articles/openmp-loop-scheduling)
Второй вариант - ключевое слово dynamic:
В данном случае невозможно предсказать порядок, в котором итерации цикла будут
назначены потокам. Каждый поток выполняет указанное число итераций. Если это число не
задано, по умолчанию оно равно 1. После того как поток завершит выполнение заданных
итераций, он переходит к следующему набору итераций.
Dynamic - Use the internal work queue to give a chunk-sized block of loop iterations to each thread.
When a thread is finished, it retrieves the next block of loop iterations from the top of the work
queue. By default, the chunk size is 1.
Dynamicschedule - each thread grabs "chunk" iterations until all iterations are done. Faster threads
are assigned more iterations
Директива reduction
Формат директивы: reduction(оператор: список)
Возможные операторы — "+", "*", "-", "&", "|", "^", "&&", "||".
Принцип работы:
https://habr.com/company/intel/blog/88574/
7.3. Ce schimbari sunt necesare in program pentru a modifica distribuirea pe fire a operatiilor?
Возможно -> schedule(dynamic)
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank_gr != MPI_UNDEFINED) {
MPI_Comm_size(com_new, &size_new);
MPI_Comm_rank(com_new, &rank_new);
MPI_Barrier(com_new);
D1 = D1 + rank;
MPI_Sendrecv(&D1, 1, MPI_INT, dest, 12, &D2, 1, MPI_INT, sour, 12, ring1, &status);
/*
D1 - initial address of send buffer (choice) (что будем передавать)
dest - rank of destination (integer) (кому передавать)
D2 - initial address of receive buffer (choice)(что будем получать)
sour - rank of source (integer) ((от кого получать))
*/
printf("Process %d(%d), received from %d the %f and send to %d the %f\n",
rank_new, rank, sour, D2, dest, D1 );
MPI_Group_free(&newgr);
MPI_Comm_free(&ring1);
MPI_Comm_free(&com_new);
}
MPI_Finalize();
return 0;
}
8.2.
8.3.
int ranks[5] = {1, 3, 4, 7, 9};
----для 6 не будет работать. тк в ranks используются ранки больше чем 5. Для : процессов
допустимы ранки : {0, 1, 2, 3, 4, 5}
----/home/F_gr_TI42/DOLOMANJI/test$ /opt/openmpi/bin/mpirun -n 12 -host
compute-0-0,compute-0-1,compute-0-2,compute-0-3 a.exe
Process 3(7), received from 1 and send to 0
Process 1(3), received from 4 and send to 3
Process 4(9), received from 2 and send to 1
Process 2(4), received from 0 and send to 4
Process 0(1), received from 3 and send to 2
9.
#include <mpi.h>
#include <stdio.h>
intmain(intargc, char**argv)
{
intuniverse_size[count] ={4,2,3};
char*worker_program[count] ={"/A_1.exe", "/A_2.exe", "/A_3.exe"};
MPI_Init(&argc, &argv);
IN array_of_info info objects telling the runtime system where and how to start
processes (array of handles, significant only at root)
OUT intercomm intercommunicator between original group and newly spawned group
(handle) => для общения предков с потомками
int MPI_Comm_spawn(char *command, char **argv, int maxprocs, MPI_Info info, int root,
MPI_Comm comm, MPI_Comm *intercomm, int *array_of_errcodes) - запускает ряд
процессов MPIи устанавливает с ними связь, возвращая интеркоммуникатор.
MPI_File_open(MPI_COMM_WORLD,"array.dat",amode,MPI_INFO_NULL,&OUT);
MPI_Type_contiguous(8,MPI_INT,&MPI_ROW);
MPI_Type_commit(&MPI_ROW);
etype =MPI_ROW;
ftype0 =MPI_ROW;
MPI_Type_extent(MPI_ROW,&rowsize);
disps[1] =2*rowsize;
MPI_Type_struct(2,blengths,disps,types,&ftype1);
MPI_Type_commit(&ftype1);
disps[1] =3*rowsize;
MPI_Type_struct(2,blengths,disps,types,&ftype2);
MPI_Type_commit(&ftype2);
if(rank ==0) {
MPI_File_set_view(OUT,0,etype,ftype0,"native",MPI_INFO_NULL);
}
if(rank ==1){
MPI_File_set_view(OUT,0,etype,ftype1,"native",MPI_INFO_NULL);
}
if(rank ==2){
MPI_File_set_view(OUT,0,etype, ftype2,"native",MPI_INFO_NULL);
}
for(i=1;i<=4;++i){
for(j=1;j<=8;++j){
value[i-1][j-1]=10*i+j;
}
}
count=0;
MPI_File_write(OUT,&value[rank][0],1,MPI_ROW,&state);
MPI_Get_count(&state,MPI_ROW,&x);
count=count +x;
MPI_File_write(OUT,&value[rank+1][0],1,MPI_ROW,&state);
MPI_Get_count(&state,MPI_ROW,&x);
count=count +x;
} else{
MPI_File_write(OUT,&value[rank+1][0],1,MPI_ROW,&state);
MPI_Get_count(&state,MPI_ROW,&count);
MPI_File_close(&OUT);
MPI_Finalize();
}
10.1 Descrieti functiile MPI din acest program utilizate pentru lucrul cu fisiere
MPI_File_write()- записать фиксированный блок данных в файл начиная с текущей позиции.
int MPI_File_write( MPI_Filefh, ROMIO_CONST void*buf, intcount, MPI_Datatype
datatype, MPI_Status*status)
fh - имя файла для записи
buf - начальный адрес буфера памяти
count - количество элементов в буфере
datatype - тип данных каждого элемента буфера
int MPI_File_open(
MPI_Commcomm,
char*filename,
intamode,
MPI_Infoinfo,
MPI_File*mpi_fh
);
MPI_FILE_OPEN opens the file identified by the file name filename on all processes in the
comm communicator group.
comm -
коммуникатор
filename - имя файла
amode - режим доступа к файлу
info - информация об объекте
mpi_fh - дескриптор файла. A file handleis an opaque object created by MPI_FILE_OPEN and
freed by MPI_FILE_CLOSE. All operations on an open file reference the file through the file
handle.
int MPI_File_set_view(
MPI_Filempi_fh,
MPI_Offsetdisp,
MPI_Datatypeetype,
MPI_Datatypefiletype,
char*datarep,
MPI_Infoinfo
);
Подпрограмма MPI_FILE_SET_VIEWизменяет вид данных файла для процесса.
mpi_fh - дескриптор файла
disp - смещение
etype - элементарный тип данных (дескриптор)
filetype -тип файла (дескриптор)
datarep - представление данных (строка)
info -информационный объект (дескриптор)
MPI_File_close- MPI_File_close first synchronizes file state, then closes the file associated with
fh.MPI_File_close is a collective routine. The user is responsible for ensuring that all outstanding
requests associated with fhhave completed before calling MPI_File_close.
Бонус
int MPI_Get_count(MPI_Statusstatus, MPI_Datatype datatype, int *count )
Через параметр count возвращает длину сообщения. Обычно вызывается после MPI_Probe.
• status информация о сообщении
• datatype тип принимаемых элементов
• выходной параметр count - число элементов сообщения
Производные типы MPI не являются в полном смысле типами данных, как это понимается в
языках программирования. Они не могут использоваться ни в каких других операциях, кроме
коммуникационных. Производные типы MPI следует понимать как описатели расположения
в памяти элементов базовых типов. Производный тип MPI представляет собой скрытый
(opaque) объект, который специфицирует две вещи: последовательность базовых типов и
последовательность смещений. Последовательность таких пар определяется как
отображение (карта) типа.
int MPI_Type_contiguous(int count, MPI_Datatype oldtype, MPI_Datatype *newtype)
Самый простой конструктор типа MPI_Type_contiguousсоздает новый тип, элементы
которого состоят из указанного числа элементов базового типа, занимающих смежные
области памяти.
Конструктор типа MPI_Type_struct- самый универсальный из всех конструкторов типа.
Создаваемый им тип является структурой, состоящей из произвольного числа блоков,
каждый из которых может содержать произвольное число элементов одного из базовых типов
и может быть смещен на произвольное число байтов от начала размещения структуры.
int MPI_Type_struct(int count, int *array_of_blocklengths, MPI_Aint *array_of_displacements,
MPI_Datatype *array_of_types, MPI_Datatype *newtype)
Функция MPI_Type_sizeопределяет "чистый" размер элемента некоторого типа (за вычетом
пустых промежутков).
Любой тип данных в MPI имеет две характеристики: протяженность и размер, выраженные в
байтах:
5. Новый билет
5.1 Вычисляется общее количество процессов, сгенерированных узлами кластера.