- •Параллельные методы решения задач линейной алгебры
- •Программная реализация (MPI) – порядок по логике вызовов!
- •void ProcessInitialization (double* &pMatrix, double* &pVector,
- •// осталось распределить между процессами Size строк матрицы А
- •14void RandomDataInitialization(double* pMatrix, double* pVector, int
- •// будет выполняться каждым процессом для сбора результата
- •// вывод результатов с других процессов
- •24// освобождение памяти на всех процессах
- •25 Замечания
void ProcessInitialization (double* &pMatrix, double* &pVector,
12double* &pResult, double* &pProcRows, double* &pProcResult, int &Size, int &RowNum)
{
int RestRows;// число строк, которые нужно распределить int i;
if (ProcRank == 0)
{
printf("\nEnter size of matrix A (> p): "); scanf("%d", &Size);
// можно добавить проверку и цикл do-while
}
// рассылка значения Size всем процессам MPI_Bcast(&Size, 1, MPI_INT, 0, MPI_COMM_WORLD);
// осталось распределить между процессами Size строк матрицы А
13RestRows = Size;
for (i=0; i<ProcRank; i++)
{ RestRows = RestRows-RestRows/(ProcNum-i);}
// число строк на процесс
RowNum = RestRows/(ProcNum-ProcRank); pVector = new double [Size];
pResult = new double [Size];
pProcRows = new double [RowNum*Size];//элементы строк А для процесса pProcResult = new double [RowNum];
if (ProcRank == 0)
{
pMatrix = new double [Size*Size]; // случайное заполнение А и b
RandomDataInitialization(pMatrix, pVector, Size);
}}
14void RandomDataInitialization(double* pMatrix, double* pVector, int
Size)
{
int i, j;
srand(unsigned(clock()));// инициализация датчика случайных чисел for (i=0; i<Size; i++)
{
pVector[i] = rand()/double(1000); for (j=0; j<Size; j++)
pMatrix[i*Size+j] = rand()/double(1000);
}
}
15 |
void DataDistribution(double* pMatrix, double* pProcRows, double* pVector, |
int Size, int RowNum) |
{
int *pSendNum;//число элементов, отправляемых процессу
int *pSendInd;//индекс первого отправляемого процессу элемента int RestRows=Size;
// рассылка вектора b всем процессам
MPI_Bcast(pVector, Size, MPI_DOUBLE, 0, MPI_COMM_WORLD);
//подготовка к распределению строк матрицы А по процессам pSendInd = new int [ProcNum];//номера по процессам pSendNum = new int [ProcNum];// количества по процессам
RowNum = Size/ProcNum;// повторно определение числа строк
// определение отсылаемых строк для каждого процесса pSendNum[0] = RowNum*Size;
pSendInd[0] = 0;
16for (int i=1; i<ProcNum; i++)
{
RestRows = RestRows - RowNum;
RowNum = RestRows/(ProcNum-i);// нужно если нет кратности pSendNum[i] = RowNum*Size; //число элементов
pSendInd[i] = pSendInd[i-1]+pSendNum[i-1];//номер через смещение
}
// функция для отправления процессам разного числа элементов
MPI_Scatterv(pMatrix , pSendNum, pSendInd, MPI_DOUBLE, pProcRows,
pSendNum[ProcRank], MPI_DOUBLE, 0, MPI_COMM_WORLD);
// освобождение памяти delete [] pSendNum; delete [] pSendInd;
}
17 |
Функция MPI_Scatterv |
|||
|
int MPI_Scatterv(void* sendbuf, int *sendcounts, int *displs, |
|||
|
MPI_Datatype sendtype, void* recvbuf, int recvcount, |
|||
|
MPI_Datatype recvtype, int root, MPI_Comm comm) |
|||
|
sendbuf - |
адрес начала буфера посылки |
||
|
(используется только в процессе-отправителе root); |
|||
|
sendcounts |
- |
целочисленный массив |
|
|
(размер равен числу процессов в группе), |
|||
|
содержащий число элементов, посылаемых каждому процессу; |
|||
|
displs |
- |
целочисленный массив |
|
|
(размер равен числу процессов в группе), |
|||
|
i-ое значение определяет смещение относительно |
|||
|
начала sendbuf для данных, посылаемых процессу i; |
|||
|
sendtype |
- |
тип посылаемых элементов; |
|
|
recvbuf |
- |
адрес начала буфера приема; |
|
|
recvcount |
- |
число получаемых элементов; |
|
|
recvtype |
|
- |
тип получаемых элементов; |
|
root |
- |
номер процесса-отправителя; |
|
|
comm |
- |
коммуникатор. |
|
18
// будет выполняться каждым процессом
void ParallelResultCalculation(double* pProcRows, double* pVector, double* pProcResult, int Size, int RowNum)
{
int i, j;
for (i=0; i<RowNum; i++)
{
pProcResult[i] = 0;
for (j=0; j<Size; j++)
pProcResult[i] += pProcRows[i*Size+j]*pVector[j];
}
}
// будет выполняться каждым процессом для сбора результата
19void ResultReplication(double* pProcResult, double* pResult, int
Size, int RowNum)
{
int i;
int *pReceiveNum; //число получаемых элементов
int *pReceiveInd; //индекс элемента в векторе-результате int RestRows=Size;//число нераспределенных элементов
// временные массивы
pReceiveNum = new int [ProcNum];//количества по процессам pReceiveInd = new int [ProcNum];// номера по процессам
// определение частей (блоков элементов) вектора-результата pReceiveInd[0] = 0;
pReceiveNum[0] = Size/ProcNum;
20for (i=1; i<ProcNum; i++)
{
RestRows = RestRows - pReceiveNum[i-1]; pReceiveNum[i] = RestRows/(ProcNum-i); pReceiveInd[i] = pReceiveInd[i-1]+pReceiveNum[i-1];
}
// функция для сбора данных(для результата) на всех процессах группы
MPI_Allgatherv(pProcResult, pReceiveNum[ProcRank], MPI_DOUBLE,
pResult, pReceiveNum, pReceiveInd, MPI_DOUBLE, MPI_COMM_WORLD);
// освобождение памяти
delete [] pReceiveNum;
delete [] pReceiveInd;
}
21 |
Функция MPI_Allgatherv |
int MPI_Allgatherv(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount,MPI_Datatype recvtype, MPI_Comm comm) sendbuf - адрес начала буфера посылки;
sendcount - число посылаемых элементов; sendtype - тип посылаемых элементов; recvbuf - адрес начала буфера приема;
recvcount - число получаемых элементов (от каждого процесса); recvtype - тип получаемых элементов;
comm - коммуникатор.
Получателями являются все процессы группы.
Данные, посланные процессом i из своего буфера sendbuf, помещаются в i-ю порцию буфера recvbuf каждого процесса.
После завершения операции содержимое буферов приема recvbuf у
всех процессов одинаково.
|
// проверка результатов |
|
void TestDistribution(double* pMatrix, double* pVector, double* pProcRows, |
22 |
int Size, int RowNum, double* pResult, double t1, double t2) |
{
if (ProcRank == 0)
{
printf("\nInitial Matrix: \n");
PrintMatrix(pMatrix, Size, Size);//самостоятельно printf("\nInitial Vector: \n"); PrintVector(pVector, Size);//самостоятельно printf("\n\nResult Vector: \n");
PrintVector(pResult, Size);
PrintTime(t1,t2);//самостоятельно
}
MPI_Barrier(MPI_COMM_WORLD);// все ждут процесс 0
