MPI编程及性能优化
第1節(jié) MPI簡(jiǎn)介
1.1 MPI及其歷史
與OpenMP相似,消息傳遞接口(Message Passing Interface,簡(jiǎn)稱MPI)是一種編程接口標(biāo)準(zhǔn),而不是一種具體的編程語言。該標(biāo)準(zhǔn)是由消息傳遞接口論壇(Message Passing Interface Forum,簡(jiǎn)稱MPIF)發(fā)起討論并進(jìn)行規(guī)范化的。
MPI標(biāo)準(zhǔn)從1992年開始起草,1994年發(fā)布第一個(gè)版本MPI-1(MPI v1.0,進(jìn)而發(fā)展出1.1和1.2版),到1997年發(fā)布第二個(gè)版本MPI-2(MPI v2.0)。MPI標(biāo)準(zhǔn)如今已經(jīng)成為事實(shí)意義上的消息傳遞并行編程標(biāo)準(zhǔn),也是最為流行的并行編程接口。
由于MPI提供了統(tǒng)一的接口,該標(biāo)準(zhǔn)受到各種并行平臺(tái)上的廣泛支持,這也使得MPI程序具有良好的可移植性。目前,MPI支持多種編程語言,包括Fortran77,Fortran90以及C/C++;同時(shí),MPI支持多種操作系統(tǒng),包括大多數(shù)的類UNIX系統(tǒng)以及Windows系統(tǒng)(Windows 2000、Windows XP等);MPI還支持多核(Multicore)、對(duì)稱多處理機(jī)(SMP)、集群(Cluster)等各種硬件平臺(tái)。。
1.2?典型MPI實(shí)現(xiàn)簡(jiǎn)介
1.MPICH
MPICH是影響最大、用戶最多的MPI實(shí)現(xiàn)。
MPICH的特點(diǎn)在于:
??????? 開放源碼;
??????? 與MPI標(biāo)準(zhǔn)同步發(fā)展;
??????? 支持多程序多數(shù)據(jù)(Multiple Program Multiple Data,MPMD)編程和異構(gòu)集群系統(tǒng);
??????? 支持C/C++、Fortran 77 和Fortran 90的綁定;對(duì)Fortran的支持提供了頭文件mpif.h和模塊兩種方式;
??????? 支持類Unix和Windows NT平臺(tái);
??????? 支持環(huán)境非常廣泛,包括多核、SMP、集群和大規(guī)模并行計(jì)算系統(tǒng);
除此之外,MPICH軟件包中還集成了并行程序設(shè)計(jì)環(huán)境組件,包括并行性能可視化分析工具和性能測(cè)試工具等。
2.Intel MPI
Intel MPI是由Intel公司推出的符合MPI-2標(biāo)準(zhǔn)的MPI實(shí)現(xiàn)。其最新版本是3.0版,突出的特色在于提供了靈活的多架構(gòu)支持。
Intel MPI提供了名為Direct Access Programming Library (DAPL)的中間層來支持多架構(gòu),兼容多種網(wǎng)絡(luò)硬件及協(xié)議,優(yōu)化網(wǎng)絡(luò)互聯(lián)。Intel MPI庫及DAPL互聯(lián)結(jié)構(gòu)可用圖7.1.1清晰地表示出來。
圖7.1 Intel MPI庫及其基于 DAPL 的互聯(lián)結(jié)構(gòu)
從圖7.1可以看出,Intel MPI透明地支持TCP/IP、共享內(nèi)存,并基于DAPL有效支持多種高性能互聯(lián)系統(tǒng), Intel MPI提供更好的線程安全機(jī)制,多線程的MPI程序并不限制MPI的使用。
1.3 MPI程序特點(diǎn)
MPI程序是基于消息傳遞的并行程序。消息傳遞指的是并行執(zhí)行的各個(gè)進(jìn)程具有自己獨(dú)立的堆棧和代碼段,作為互不相關(guān)的多個(gè)程序獨(dú)立執(zhí)行,進(jìn)程之間的信息交互完全通過顯式地調(diào)用通信函數(shù)來完成。
基于消息傳遞的并行程序可以劃分為單程序多數(shù)據(jù)(Single Program Multiple Data,簡(jiǎn)稱SPMD)和多程序多數(shù)據(jù)MPMD兩種形式。SPMD使用一個(gè)程序來處理多個(gè)不同的數(shù)據(jù)集以達(dá)到并行的目的。并行執(zhí)行的不同程序?qū)嵗幱谕耆珜?duì)等的位置。相應(yīng)的,MPMD程序使用不同的程序處理多個(gè)數(shù)據(jù)集,合作求解同一個(gè)問題。
SPMD是MPI程序中最常用的并行模型。圖7.2為SPMD執(zhí)行模型的示意圖,其中表示了一個(gè)典型的SPMD程序,同樣的程序prog_a運(yùn)行在不同的處理核上,處理了不同的數(shù)據(jù)集。
圖 7.2 SPMD執(zhí)行模型
| ? | |
| ? |
圖7.5則給出了三種典型MPMD程序的執(zhí)行模型。
(a)是一個(gè)管理者(Master)/工人(Worker)類型的MPMD程序
(b)為另外一種類型的MPMD程序:聯(lián)合數(shù)據(jù)分析程序。在大部分的時(shí)間內(nèi),不同的程序各自獨(dú)立的完成自己的任務(wù),并在特定的時(shí)候交換數(shù)據(jù)。
(c)是流式的MPMD程序,程序運(yùn)行由prog_a、prog_b和prog_c組成,這三個(gè)程序的執(zhí)行過程就好像工廠里的流水線一樣。
| ? | |
| ? |
圖 7.5 MPMD執(zhí)行模型
通過學(xué)習(xí)本小節(jié)介紹的MPI程序的特點(diǎn),以及SPMD和MPMD的多種執(zhí)行模型,讀者就可以在以后的開發(fā)過程中靈活地設(shè)計(jì)不同的MPI并行程序。
PI-2提出的高級(jí)功能將在第7.6節(jié)中將做簡(jiǎn)要說明。
第2節(jié) MPI編程基礎(chǔ)
2.1?簡(jiǎn)單的MPI程序示例
首先,我們來看一個(gè)簡(jiǎn)單的MPI程序?qū)嵗H缤覀儗W(xué)習(xí)各種語言的第一個(gè)程序一樣,對(duì)于MPI的第一個(gè)程序同樣是"Hello Word"。
/* Case 1 hellow.c */
#include <stdio.h>
#include "mpi.h"
int main( int argc, char *argv[] ) {
int rank;
int size;
??? MPI_Init( argc, argv?);
??? MPI_Comm_rank(MPI_COMM_WORLD, &rank);
??? MPI_Comm_size(MPI_COMM_WORLD, &size);
??? printf( "Hello world from process %d of %d\n", rank, size );
??? MPI_Finalize();
??? return 0;
}
根據(jù)上一節(jié)的介紹,我們使用如下命令編譯和鏈接這個(gè)程序:
mpicc –o hellow hellow.c
運(yùn)行這個(gè)例子可以在可執(zhí)行文件的目錄中執(zhí)行mpiexec –np 4 ./hellow。運(yùn)行結(jié)果如下:
Hello world from process 0 of 4
Hello world from process 1 of 4
Hello world from process 2 of 4
Hello world from process 3 of 4
這個(gè)程序在MPI程序運(yùn)行的每個(gè)進(jìn)程中分別打印各自的MPI進(jìn)程號(hào)(0~3)和總進(jìn)程數(shù)(4)。
?????? 值得注意的是,由于四個(gè)進(jìn)程是并行執(zhí)行,所以即使輸出的順序有變化也是正常的,程序中并沒有限制哪個(gè)進(jìn)程在前,哪個(gè)進(jìn)程在后。
2.2 MPI程序的四個(gè)基本函數(shù)
1.MPI_Init和MPI_Finalize
MPI_Init用來初始化MPI執(zhí)行環(huán)境,建立多個(gè)MPI進(jìn)程之間的聯(lián)系,為后續(xù)通信做準(zhǔn)備。而MPI_Finalize則是結(jié)束MPI執(zhí)行環(huán)境。
如同OpenMP定義并行區(qū)一樣,這兩個(gè)函數(shù)就是用來定義MPI程序的并行區(qū)的。也就是說,除了檢測(cè)是否初始化的函數(shù)之外,不應(yīng)該在這兩個(gè)函數(shù)定義的區(qū)域之外調(diào)用其他MPI函數(shù)。
2.MPI_Comm_rank
第7.1節(jié)介紹過SPMD的程序形式,給出的例子中需要通過進(jìn)程標(biāo)識(shí)和總數(shù)來分配數(shù)據(jù)。MPI_Comm_rank就是來標(biāo)識(shí)各個(gè)MPI進(jìn)程的,告訴調(diào)用該函數(shù)的進(jìn)程“我是誰?”。MPI_Comm_rank返回整型的錯(cuò)誤值,需要提供兩個(gè)函數(shù)參數(shù):
???????? MPI_Comm類型的通信域,標(biāo)識(shí)參與計(jì)算的MPI進(jìn)程組。
???????? 整型指針,返回進(jìn)程在相應(yīng)進(jìn)程組中的進(jìn)程號(hào)。進(jìn)程號(hào)從0開始編號(hào)。
3.MPI_Comm_size
本函數(shù)則用來標(biāo)識(shí)相應(yīng)進(jìn)程組中有多少個(gè)進(jìn)程。
2.3 MPI的點(diǎn)對(duì)點(diǎn)通信
點(diǎn)對(duì)點(diǎn)通信是MPI編程的基礎(chǔ)。本節(jié)我們將重點(diǎn)介紹其中兩個(gè)最重要的MPI函數(shù)MPI_Send和MPI_Recv。
| int MPI_SEND(buf, count, datatype, dest, tag, comm); |
輸入?yún)?shù)包括:
???????? buf,發(fā)送緩沖區(qū)的起始地址,可以是各種數(shù)組或結(jié)構(gòu)的指針。
???????? count,整型,發(fā)送的數(shù)據(jù)個(gè)數(shù),應(yīng)為非負(fù)整數(shù)。
???????? datatype,發(fā)送數(shù)據(jù)的數(shù)據(jù)類型,這個(gè)參數(shù)將在后續(xù)節(jié)中詳細(xì)介紹。
???????? dest,整型,目的進(jìn)程號(hào)。
???????? tag,整型,消息標(biāo)志,后續(xù)節(jié)中會(huì)做進(jìn)一步介紹。
???????? comm,MPI進(jìn)程組所在的通信域,留待后續(xù)節(jié)進(jìn)一步介紹。
該函數(shù)沒有輸出參數(shù),返回錯(cuò)誤碼。
這個(gè)函數(shù)的含義是向通信域comm中的dest進(jìn)程發(fā)送數(shù)據(jù)。消息數(shù)據(jù)存放在buf中,類型是datatype,個(gè)數(shù)是count個(gè)。這個(gè)消息的標(biāo)志是tag,用以和本進(jìn)程向同一目的進(jìn)程發(fā)送的其它消息區(qū)別開來。
| int MPI_RECV(buf,count,datatype,source,tag,comm,status); |
n???????? status,MPI_Status結(jié)構(gòu)指針,返回狀態(tài)信息。
MPI_Status的結(jié)構(gòu)定義在mpi.h當(dāng)中可以找到。
| /* The order of these elements must match that in mpif.h */ typedef struct MPI_Status { ??? int count; ??? int cancelled; ??? int MPI_SOURCE; ??? int MPI_TAG; ??? int MPI_ERROR; } MPI_Status; |
?
| int MPI_Get_count(?MPI_Status *status, MPI_Datatype datatype, int *count); |
??????? count,是實(shí)際接收到的給定數(shù)據(jù)類型的數(shù)據(jù)項(xiàng)數(shù)
2.4?消息管理7要素
MPI最重要的功能莫過于消息傳遞。正如我們先前看到一樣,MPI_Send和MPI_Recv負(fù)責(zé)在兩個(gè)進(jìn)程間發(fā)送和接收消息。總結(jié)起來,點(diǎn)對(duì)點(diǎn)消息通信的參數(shù)主要是由以下7個(gè)參數(shù)組成:
(1)??? 發(fā)送或者接收緩沖區(qū)buf;
(2)??? 數(shù)據(jù)數(shù)量count;
(3)??? 數(shù)據(jù)類型datatype;
(4)??? 目標(biāo)進(jìn)程或者源進(jìn)程destination/source;
(5)??? 消息標(biāo)簽tag;
(6)??? 通信域comm;.
(7)??? 消息狀態(tài)status,只在接收的函數(shù)中出現(xiàn)。
1.消息數(shù)據(jù)類型
在消息緩沖的三個(gè)變量中,最值得注意的是datatype,消息數(shù)據(jù)類型。
為什么需要定義消息數(shù)據(jù)類型?主要的理由有兩個(gè):一是支持異構(gòu)平臺(tái)計(jì)算的互操作性,二是允許方便地將非連續(xù)內(nèi)存區(qū)中的數(shù)據(jù),具有不同數(shù)據(jù)類型的內(nèi)容組成消息。MPI程序有嚴(yán)格的數(shù)據(jù)類型匹配要求。類型匹配包涵了兩個(gè)層面的內(nèi)容:一是宿主語言的類型(C或者Fortran數(shù)據(jù)類型)和通信操作所指定的類型相匹配;二是發(fā)送方和接收方的類型匹配。MPI用預(yù)定義的基本數(shù)據(jù)類型和導(dǎo)出數(shù)據(jù)類型來滿足上述要求。
(1)????基本數(shù)據(jù)類型
如前所述,我們需要發(fā)送和接收連續(xù)的數(shù)據(jù),MPI提供了預(yù)定義的數(shù)據(jù)類型供程序員使用。
表7.3.1 MPI預(yù)定義數(shù)據(jù)類型與C數(shù)據(jù)類型的對(duì)應(yīng)關(guān)系
| MPI預(yù)定義數(shù)據(jù)類型 | 相應(yīng)的C數(shù)據(jù)類型 |
| MPI_CHAR | signed char |
| MPI_SHORT | signed short int |
| MPI_INT | signed int |
| MPI_LONG | signed long int |
| MPI_UNSIGNED_CHAR | unsigned char |
| MPI_UNSIGNED_SHORT | unsigned short int |
| MPI_UNSIGNED | unsigned int |
| MPI_UNSIGNED_LONG | unsigned long int |
| MPI_FLOAT | float |
| MPI_DOUBLE | double |
| MPI_LONG_DOUBLE | long double |
| MPI_BYTE | 無對(duì)應(yīng)類型 |
| MPI_PACKED | 無對(duì)應(yīng)類型 |
對(duì)于初學(xué)者來說,應(yīng)盡可能保證發(fā)送和接收的數(shù)據(jù)類型完全一致。
(2)????導(dǎo)出數(shù)據(jù)類型
除了這些基本數(shù)據(jù)類型之外,MPI還允許通過導(dǎo)出數(shù)據(jù)類型,將不連續(xù)的,甚至是不同類型的數(shù)據(jù)元素組合在一起形成新的數(shù)據(jù)類型。我們稱這種由用戶定義的數(shù)據(jù)類型為導(dǎo)出數(shù)據(jù)類型。
歸納起來類型匹配規(guī)則可以概括為:
??????? 有類型數(shù)據(jù)的通信,發(fā)送方和接收方均使用相同的數(shù)據(jù)類型;
??????? 無類型數(shù)據(jù)的通信,發(fā)送方和接收方均以MPI_BYTE作為數(shù)據(jù)類型;
??????? 打包數(shù)據(jù)的通信,發(fā)送方和接收方均使用MPI_PACKED。
2.?通信域
一個(gè)通信域(comm)包含一個(gè)進(jìn)程組(process group)及其上下文(context)。進(jìn)程組是進(jìn)程的有限有序集。通信域限定了消息傳遞的進(jìn)程范圍。
MPI實(shí)現(xiàn)已經(jīng)預(yù)先定義了兩個(gè)進(jìn)程組:MPI_COMM_SELF,只包含各個(gè)進(jìn)程自己的進(jìn)程組;MPI_COMM_WORLD,包含本次啟動(dòng)的所有MPI進(jìn)程的進(jìn)程組。同時(shí),MPI還為通信子提供了各種管理函數(shù),其中包括:
(1)??? 通信域比較int MPI_Comm_compare(comm1, comm2, result):如comm1,comm2為相同句柄,則result為MPI_Ident;如果僅僅是各進(jìn)程組的成員和序列號(hào)都相同,則result為MPI_Congruent;如果二者的組成員相同但序號(hào)不同則結(jié)果為MPI_Similar;否則,結(jié)果為MPI_Unequal。
(2)??? 通信域拷貝int MPI_Comm_dup(comm, newcom):對(duì)comm進(jìn)行復(fù)制得到新的通信域newcomm。
(3)??? 通信域分裂int MPI_Comm_split(comm, color, key, newcomm):本函數(shù)要求comm進(jìn)程組中的每個(gè)進(jìn)程都要執(zhí)行,每個(gè)進(jìn)程指定一個(gè)color(整型),此調(diào)用首先將具有相同color值的進(jìn)程形成一個(gè)新的進(jìn)程組,新產(chǎn)生的通信域與這些進(jìn)程組一一對(duì)應(yīng)。新通信域中各個(gè)進(jìn)程的順序編號(hào)根據(jù)key(整型)的大小決定,即key越小,則相應(yīng)進(jìn)程在新通信域中的順序編號(hào)也越小,若一個(gè)進(jìn)程中的key相同,則根據(jù)這兩個(gè)進(jìn)程在原來通信域中順序號(hào)決定新的進(jìn)程號(hào)。一個(gè)進(jìn)程可能提供color值為MPI_Undefined,此種情況下,其newcomm返回MPI_COMM_NULL。
(4)??? 通信域銷毀int MPI_Comm_free(comm):釋放給定通信域。
上述函數(shù)都返回錯(cuò)誤碼。
?
2.5?統(tǒng)計(jì)時(shí)間
MPI提供了兩個(gè)時(shí)間函數(shù)MPI_Wtime和MPI_Wtick。其中,MPI_Wtime函數(shù)返回一個(gè)雙精度數(shù),標(biāo)識(shí)從過去的某點(diǎn)的時(shí)間到當(dāng)前時(shí)間所消耗的時(shí)間秒數(shù)。而函數(shù)MPI_Wtick則返回MPI_Wtime結(jié)果的精度。
2.6?錯(cuò)誤管理
MPI在錯(cuò)誤管理方面提供了豐富的接口函數(shù),這里我們介紹其中最簡(jiǎn)單的部分接口。
n???????? 用status.MPI_ERROR來獲取錯(cuò)誤碼。
n???????? MPI終止MPI程序執(zhí)行的函數(shù)MPI_Abort。
| int MPI_Abort(MPI_Comm comm, int errorcode) |
它使comm通信域的所有進(jìn)程退出,返回errorcode給調(diào)用的環(huán)境。通信域comm中的任一進(jìn)程調(diào)用此函數(shù)都能夠使該通信域內(nèi)所有的進(jìn)程結(jié)束運(yùn)行。
第3節(jié) MPI群集通信
除了前面介紹的點(diǎn)到點(diǎn)通信之外,MPI還提供了群集通信。所謂群集通信,包含了一對(duì)多,多對(duì)一和多對(duì)多的進(jìn)程通信模式。它的最大的特點(diǎn)就是多個(gè)進(jìn)程參與通信,下面我們將要介紹在MPI中常用的幾個(gè)群集通信函數(shù)。
3.1?同步
本函數(shù)接口是:int MPI_Barrier(MPI_Comm comm)。
這個(gè)函數(shù)像一道路障。在操作中,通信子comm中的所有進(jìn)程相互同步,即它們相互等待,直到所有進(jìn)程都執(zhí)行了他們各自的MPI_Barrier函數(shù),然后再各自接著開始執(zhí)行后續(xù)的代碼。同步函數(shù)是并行程序中控制執(zhí)行順序的有效手段。
3.2?廣播
廣播顧名思義,就是一對(duì)多的傳送消息。它的作用是從一個(gè)root進(jìn)程向組內(nèi)所有其他的進(jìn)程發(fā)送一條消息。它的接口形式是:
int MPI_Bcast( void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm )
圖7.13給出了廣播操作的示意。
圖7.13?廣播操作示意圖圖
3.3?聚集
聚集函數(shù)MPI_Gather是一個(gè)多對(duì)一的通信函數(shù)。其接口為:
int MPI_Gather(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
?? ??????????void *recvbuf, int recvcnt, MPI_Datatype recvtype,
???????????? int root, MPI_Comm comm)
root進(jìn)程接收該通信組每一個(gè)成員進(jìn)程(包括root自已)發(fā)送的消息。這n個(gè)消息的連接按進(jìn)程號(hào)排列存放在root進(jìn)程的接收緩沖中。每個(gè)發(fā)送緩沖由三元組(sendbuf, sendcnt, sendtype)標(biāo)識(shí)。所有非root進(jìn)程忽略接收緩沖,對(duì)root進(jìn)程發(fā)送緩沖由三元組(recvbuf, recvcnt, recvtype)標(biāo)識(shí)。圖7.14給出聚集操作的示意。
| ? |
圖7.14?聚集操作示意圖
3.4?播撒
int MPI_Scatter(void *sendbuf, int sendcnt, MPI_Datatype sendtype,
???????????? void *recvbuf, int recvcnt, MPI_Datatype recvtype, int root,
???????????? MPI_Comm comm)
播撒函數(shù)MPI_Scatter是一對(duì)多的傳遞消息。但是它和廣播不同,root進(jìn)程向各個(gè)進(jìn)程傳遞的消息是可以不同的。Scatter實(shí)際上執(zhí)行的是與Gather相反的操作。
3.5擴(kuò)展的聚集和播撒操作
MPI_Allgather的作用是每一個(gè)進(jìn)程都收集到其他所有進(jìn)程的消息,它相當(dāng)于每一個(gè)進(jìn)程都執(zhí)行了MPI_Gather執(zhí)行完了MPI_Gather之后,所有的進(jìn)程的接收緩沖區(qū)的內(nèi)容都是相同的,也就是說每個(gè)進(jìn)程給所有進(jìn)程都發(fā)送了一個(gè)相同的消息,所以名為allgather。本函數(shù)的接口是:
int MPI_Allgather(void *sendbuf, int sendcount, MPI_Datatype sendtype,
?????????????? void *recvbuf, int recvcount, MPI_Datatype recvtype,
?????????????? MPI_Comm comm)
圖7.15給出了擴(kuò)展的聚集和播撒操作的示意。
圖7.15?擴(kuò)展的聚集和播撒操作示意圖
3.6全局交換
MPI_Allgather每個(gè)進(jìn)程發(fā)一個(gè)相同的消息給所有的進(jìn)程,而MPI_Alltoall散發(fā)給不同進(jìn)程的消息是不同的。因此,它的發(fā)送緩沖區(qū)也是一個(gè)數(shù)組。MPI_Alltoall的每個(gè)進(jìn)程可以向每個(gè)接收者發(fā)送數(shù)目不同的數(shù)據(jù),第i個(gè)進(jìn)程發(fā)送的第j塊數(shù)據(jù)將被第j個(gè)進(jìn)程接收并存放在其接收消息緩沖區(qū)recvbuf的第i塊,每個(gè)進(jìn)程的sendcount和sendtype的類型必須和所有其他進(jìn)程的recvcount和recvtype相同,這也意謂著在每個(gè)進(jìn)程和根進(jìn)程之間發(fā)送的數(shù)據(jù)量必須和接收的數(shù)據(jù)量相等。函數(shù)接口為:
int MPI_Alltoall(void *sendbuf, int sendcount, MPI_Datatype sendtype,
????????????? void *recvbuf, int recvcount, MPI_Datatype recvtype,
????????????? MPI_Comm comm)
全局交換的操作示意圖為圖7.4.4。
圖7.4.4?全局交換操作示意圖
3.7規(guī)約與掃描
MPI提供了兩種類型的聚合操作:歸約(reduction)和掃描(scan)。
1.歸約
int MPI_Reduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype,
????????????? MPI_Op op, int root, MPI_Comm comm)
這里每個(gè)進(jìn)程的待處理數(shù)據(jù)存放在sendbuf中,可以是標(biāo)量也可以是向量。所有進(jìn)程將這些值通過輸入的操作子op計(jì)算為最終結(jié)果并將它存入root進(jìn)程的recvbuf。數(shù)據(jù)項(xiàng)的數(shù)據(jù)類型在Datatype域中定義。具體的歸約操作包括:
???????? MPI_MAX 求最大值
???????? MPI_MIN 求最小值
???????? MPI_SUM 求和
???????? MPI_PROD 求積
???????? MPI_LAND 邏輯與
???????? MPI_BAND 按位與
???????? MPI_LOR 邏輯或
???????? MPI_BOR 按位或
???????? MPI_LXOR 邏輯異或
???????? MPI_BXOR 按位異或
???????? MPI_MAXLOC 最大值且相應(yīng)位置
???????? MPI_MINLOC 最小值且相應(yīng)位置
規(guī)約操作的數(shù)據(jù)類型組合如表7.4.1所示。
表7.4.1 規(guī)約操作與相應(yīng)類型的對(duì)應(yīng)關(guān)系
| 操作 | 允許的數(shù)據(jù)類型 |
| MPI_MAX,MPI_MIN | C整數(shù),Fortran整數(shù),浮點(diǎn)數(shù) |
| MPI_SUM,MPI_PROD | C整數(shù),Fortran整數(shù),浮點(diǎn)數(shù),復(fù)數(shù) |
| MPI_LAND,MPI_LOR,MPI_XLOR | C整數(shù),邏輯型 |
| MPI_BAND,MPI_BOR,MPI_BXOR | C整數(shù),Fortran整數(shù),字節(jié)型 |
?
在MPI中,針對(duì)規(guī)約操作,所有的MPI預(yù)定義的操作都是可結(jié)合的,也是可交換的。同時(shí),用戶可以指定自定義的函數(shù)操作,這些操作是也要可結(jié)合的,但可以不是可交換的。
2.掃描
int MPI_Scan(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype,
??????????? MPI_Op op, MPI_Comm comm)
MPI_Scan常用于對(duì)分布于組中的數(shù)據(jù)作前置歸約操作。此操作將序列號(hào)為0,···,i(包括i)的進(jìn)程發(fā)送緩沖區(qū)的歸約結(jié)果存入序列號(hào)為i?的進(jìn)程接收消息緩沖區(qū)中。這種操作支持的數(shù)據(jù)類型、操作以及對(duì)發(fā)送及接收緩沖區(qū)的限制和規(guī)約相同。與規(guī)約相比,掃描Scan操作省去了Root域,因?yàn)閽呙枋菍⒉糠种到M合成n個(gè)最終值,并存放在n個(gè)進(jìn)程的recvbuf中。具體的掃描操作由Op域定義。
MPI的歸約和掃描操作允許每個(gè)進(jìn)程貢獻(xiàn)向量值,而不只是標(biāo)量值。向量的長(zhǎng)度由Count定義。MPI也支持用戶自定義的歸約操作。
第4節(jié) MPI性能分析與優(yōu)化舉例
4.1?選取計(jì)算粒度
當(dāng)通信的成為并行程序性能瓶頸的時(shí)候,一般來說選取較高的計(jì)算粒度可以降低進(jìn)程間的通信開銷。例如,用7個(gè)進(jìn)程完成A、B、C 3個(gè)不相關(guān)的任務(wù),如果B的計(jì)算量為A的2倍,而C的計(jì)算量為A的4倍。
一種并行執(zhí)行的策略是采用任務(wù)內(nèi)并行的方式,如圖7.16(a)所示,這種方案中對(duì)于每一個(gè)任務(wù)都在7個(gè)進(jìn)程上并行執(zhí)行,所以每執(zhí)行一個(gè)任務(wù)需要進(jìn)行一次數(shù)據(jù)分配,和一次數(shù)據(jù)收集。而采用任務(wù)間并行的模式,即更大粒度的并行分配方式,只需要一次數(shù)據(jù)分配和一次數(shù)據(jù)收集,節(jié)約了兩次集合通信(如圖7.16(b)所示)。
?
|
4.2聚合消息
一種減少通信次數(shù)的方法就是將小的消息聚合起來一次發(fā)送,這種優(yōu)化稱為消息聚合。如果零碎的消息很多,則通過消息聚合可以得到很大的性能提高。
4.3解決負(fù)載均衡問題
在并行計(jì)算中,如果各個(gè)處理器(核)上的工作需要的完成時(shí)間不同,則會(huì)使先完成的處理器等待未完成的處理器(核),浪費(fèi)了計(jì)算資源。若這種情況如果比較嚴(yán)重,就應(yīng)該采用策略來使各處理器負(fù)載盡量平衡。一般采用的策略有兩種,一種為靜態(tài)負(fù)載平衡,一種為動(dòng)態(tài)負(fù)載平衡。前者適用于計(jì)算前可以準(zhǔn)確知道總的負(fù)載,而且這些負(fù)載容易平均劃分給各個(gè)進(jìn)程的情況。而對(duì)于事先不知道負(fù)載總數(shù),或者總負(fù)載不易平均劃分的情況,則可能需要采用動(dòng)態(tài)負(fù)載劃分來解決。
稠密的矩陣與向量乘法運(yùn)算是一個(gè)靜態(tài)負(fù)載平衡的例子,假設(shè)矩陣為N×M階,而有p個(gè)相同處理器可以用于計(jì)算,按行分解每個(gè)處理器分得或行,若干按列分解每個(gè)處理器分得或列,如圖7.19所示。當(dāng)然還可以按矩形塊分解矩陣,這時(shí)要根據(jù)具體矩形塊的大小進(jìn)行。
動(dòng)態(tài)負(fù)載平衡我們采用三角矩陣與向量的乘法為例。存在一個(gè)管理節(jié)點(diǎn),將矩陣未完成的行發(fā)送給工作節(jié)點(diǎn),當(dāng)工作節(jié)點(diǎn)完成任務(wù)后主動(dòng)向管理節(jié)點(diǎn)索要任務(wù),當(dāng)管理節(jié)點(diǎn)上沒有未完成任務(wù)時(shí),向所有進(jìn)程發(fā)送終止信號(hào),如圖7.20所示。這是通過主從模式,有效維護(hù)任務(wù)池,實(shí)現(xiàn)動(dòng)態(tài)負(fù)載平衡的例子。
圖7.19 矩陣向量乘靜態(tài)負(fù)載平衡示意圖
圖7.20? 動(dòng)態(tài)負(fù)載平衡示意圖
from:?http://jpck.zju.edu.cn/eln/200805131515180671/page.jsp?cosid=1423&JSPFILE=page&LISTFILE=list&CHAPFILE=listchapter&PATH=200805131515180671&ROOTID=6380&NODEID=6403&DOCID=8717
總結(jié)
以上是生活随笔為你收集整理的MPI编程及性能优化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用MFC制作程序启动logo
- 下一篇: Windows系统下搭建MPI环境