本文引自百度文庫
一、實驗內容
1、采用MPI_Send 和MPI_Recv 編寫代碼來實現包括MPI_Bcast、MPI_Alltoall、MPI_Gather、MPI_Scatter 等MPI 群集通信函數的功能。
2、給出抽象的並行算法描述、程序源代碼及運行時性能加速圖表。
二、抽象並行算法描述
ⅰ、MPI_Bcast算法描述:
輸入:並行處理器個數ProcessNumber
輸出:所有進程收到來自Root進程的消息
Procedure MPI_Bcast_a
Begin
對所有處理器同時執行如下的算法:
(1)if 進程為Root進程
(1.1)將message寫入消息緩沖
(1.2)for index=0 to size-1 do
向index發送相同的message消息
end for
(2)進程不是Root進程
(2.1)接收消息
End
2、MPI_Alltoall算法描述:
輸入:並行處理器個數ProcessNumber
輸出:所有進程收到來自其他進程不同的消息
Procedure MPI_Alltoall_a
Begin
對所有處理器同時執行如下的算法:
(1)將message寫入消息緩沖
(2)for index=0 to size-1 do
分別向index發送不同的message消息
end for
(3)for source=0 to size-1 do
接收來自source的message消息
end for
End
3、MPI_Gather算法描述:
輸入:並行處理器個數ProcessNumber
輸出: Root進程從通信域Comm的所有進程接收消息
Procedure MPI_Gather_a
Begin
對所有處理器同時執行如下的算法:
(1)if 進程為Root進程
(1.1)for source=0 to size-1 do
接收來自source的message消息
end for
(2)向Root進程發送自己的消息
End
4、MPI_Scatter算法描述:
輸入:並行處理器個數ProcessNumber
輸出:向所有進程發送不同的消息
Procedure MPI_Scatter_a
Begin
對所有處理器同時執行如下的算法:
(1)if 進程為Root進程
(1.1)將message寫入消息緩沖
(1.2)for index=0 to size-1 do
向index發送不同的message消息
end for
(2)進程不是Root進程
(2.1)接收消息
End
三、程序源代碼
#include "mpi.h" /*MPI head file*/
#include <stdio.h>
#include <string.h>
#define ProNum 4
void MPI_Bcast_a(int rank,int size,int tag){ //
int index;
char message[100];
MPI_Status status;
if (rank==0){
strcpy(message,"Hello,the message is from process root!\n ");
for(index=0;index<size;index++){
MPI_Send(message,strlen(message), MPI_CHAR, index, tag, MPI_COMM_WORLD); /*sending data to node#1*/
}
printf("There are %d processes in the group.\n",size);
}
else{
MPI_Recv(message,100, MPI_CHAR, 0, tag, MPI_COMM_WORLD, &status);
printf("Process %d received %s\n",rank,message);
}
}
void MPI_Alltoall_a(int rank,int size,int tag){ //
int index,source;
char message[100];
char buffers[ProNum][100];//if buffers *[100],there will be errors.
char buffer[10];
MPI_Status status;
strcpy(message,"Hello,the message is from process ");
//message="Hello,the message is from process ";
snprintf(buffer,10,"%d",rank);
strcat(message,buffer);
for(index=0;index<size;index++){
MPI_Send(message,strlen(message), MPI_CHAR, index, tag, MPI_COMM_WORLD); /*sending data to node#1*/
}
printf("There are %d processes in the group.\n",size);
for(source=0;source<size;source++){
MPI_Recv(buffers[source],100, MPI_CHAR,source, tag, MPI_COMM_WORLD, &status);
printf("Process %d received %s\n",rank,buffers[source]);
}
}
void MPI_Gather_a(int rank,int size,int tag){ //
int index,source;
char message[100];
char buffers[ProNum][100];//
char buffer[10];
MPI_Status status;
strcpy(message,"Hello,the message is from process ");
//message="Hello,the message is from process ";
snprintf(buffer,10,"%d",rank);
strcat(message,buffer);
MPI_Send(message,strlen(message), MPI_CHAR, 0, tag, MPI_COMM_WORLD); /*sending data to node#1*/
printf("There are %d processes in the group.\n",size);
if(rank==0){
for(source=0;source<size;source++){
MPI_Recv(buffers[source],100, MPI_CHAR,source, tag, MPI_COMM_WORLD, &status);
printf("Process %d received %s\n",rank,buffers[source]);
}
}
}
void MPI_Scatter_a(int rank,int size,int tag){ //
int index,source;
char message[100];
//char buffers[ProNum][100];//if buffers *[100],there will be errors.
char buffer[10];
MPI_Status status;
strcpy(message,"Hello,the message is to process ");
//message="Hello,the message is from process ";
if(rank==0){
for(index=0;index<size;index++){
snprintf(buffer,10,"%d",index);
strcat(message,buffer);
MPI_Send(message,strlen(message), MPI_CHAR, index, tag, MPI_COMM_WORLD); /*sending data to node#1*/
}
}
printf("There are %d processes in the group.\n",size);
MPI_Recv(message,100, MPI_CHAR,0, tag, MPI_COMM_WORLD, &status);
printf("Process %d received %s\n",rank,message);
}
int main( int argc, char** argv )
{
int rank, size,index, tag=1;
int senddata,recvdata;
MPI_Status status;
MPI_Init(&argc, &argv); /*initializing */
MPI_Comm_rank(MPI_COMM_WORLD, &rank); /*Process#*/
MPI_Comm_size(MPI_COMM_WORLD, &size); /*Total processes#*/
MPI_Bcast_a(rank,size,tag);
MPI_Alltoall_a(rank,size,tag);
MPI_Gather_a(rank,size,tag);
MPI_Scatter_a(rank,size,tag);
MPI_Finalize(); /*quit from MPI world*/
return (0);
}
四、實驗結果對比
實驗進行了相關數據的對比,主要將數據分為兩組進行對比(1)在曙光4000A上的自編寫的函數(2)在曙光4000A上使用系統自帶的函數。
實驗結果數據如下表:
(1)MPI_Bcast:
運行時間(s) 處理器個數 |
Real time |
user CPU time |
system CPU time |
|||
MPI_Bcast |
實驗程序 |
MPI_Bcast |
實驗程序 |
MPI_Bcast |
實驗程序 |
|
2 |
|
0.403 |
|
0.041 |
|
0.078 |
4 |
|
0.618 |
|
0.071 |
|
0.112 |
8 |
|
1.224 |
|
0.123 |
|
0.187 |
16 |
|
1.876 |
|
0.205 |
|
0.361 |
32 |
|
3.618 |
|
0.390 |
|
0.722 |
64 |
|
6.804 |
|
0.702 |
|
1.175 |
表1 MPI_Bcast運行性能
(2)MPI_Alltoall:
運行時間(s) 處理器個數 |
Real time |
user CPU time |
system CPU time |
|||
MPI_Alltoall |
實驗程序 |
MPI_Alltoall |
實驗程序 |
MPI_Alltoall |
實驗程序 |
|
2 |
|
0.439 |
|
0.050 |
|
0.072 |
4 |
|
0.630 |
|
0.066 |
|
0.107 |
8 |
|
1.151 |
|
0.109 |
|
0.198 |
16 |
|
1.998 |
|
0.233 |
|
0.353 |
32 |
|
7.323 |
|
0.439 |
|
0.674 |
64 |
|
17.233 |
|
0.881 |
|
1.441 |
表2 MPI_Alltoall運行性能
(3)MPI_Gather:
運行時間(s) 處理器個數 |
Real time |
user CPU time |
system CPU time |
|||
MPI_Gather |
實驗程序 |
MPI_Gather |
實驗程序 |
MPI_Gather |
實驗程序 |
|
2 |
|
|
|
|
|
|
4 |
|
|
|
|
|
|
8 |
|
|
|
|
|
|
16 |
|
|
|
|
|
|
32 |
|
|
|
|
|
|
64 |
|
|
|
|
|
|
表3 MPI_Gather運行性能
(4)MPI_Scatter:
運行時間(s) 處理器個數 |
Real time |
user CPU time |
system CPU time |
|||
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
4 |
|
|
|
|
|
|
8 |
|
|
|
|
|
|
16 |
|
|
|
|
|
|
32 |
|
|
|
|
|
|
64 |
|
|
|
|
|
|
表4 MPI_Scatter運行性能
五、實驗結果
上圖為測試輸出時所產生結果圖,表明各個線程所接收數據並且輸出的相應過程,在數據字段填充的是各個發送端ID信息,用於驗證信息是否發送正確。爭對該程序如果信息發送正確那么在輸出報文的get * Process data:* 兩處應該是相同的。
圖1 MPI_Bcast接收信息顯示
圖2 MPI_Alltoall接收信息顯示
圖3 MPI_Gather接收信息顯示
圖4 MPI_Scatter接收信息顯示
六、程序運行時性能加速圖表
圖5 兩種情況下MPI_Bcast時間花費對比圖
圖6 兩種情況下MPI_Alltoall時間花費對比圖
圖7 兩種情況下MPI_Gather時間花費對比圖
圖8 兩種情況下MPI_Scatter時間花費對比圖
七、實驗分析
經過上述實驗得出的結論有以下幾點(1)曙光4000A平台上運行程序的速度很高;(2)自編寫函數性能低於系統自帶函數,但是在自編寫的Alltoall函數測試中,線程數目低於8時,自編寫Alltoall函數花費時間小於系統自帶的Alltoall函數的測試時間。