2011-11-18 62 views
0

我想用C++編寫一個MPI程序來總結一個非常大的數組值。 下面的代碼可以很好地處理數組維度高達100萬,但是當我嘗試使用1000萬或更多元素執行時,我會收到一個信號錯誤。有人可以幫助我嗎?由於使用非常大的數組時MPI分段錯誤錯誤

#include <stdio.h> 
#include "mpi.h" 

int main(int argc, char *argv[]) { 
    double t0, t1, time; //variabili per il calcolo del tempo 
int nprocs, myrank; 
    int root=0; 
long temp, sumtot, i, resto, svStartPos, dim, intNum; 

//Dimensione del vettore contenente i valori da sommare 
const long A_MAX=10000000; 

MPI_Init(&argc, &argv); 
MPI_Comm_size(MPI_COMM_WORLD, &nprocs); 
MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 


    long vett[A_MAX]; 
long parsum[B_MAX]; 

long c=-1; 
int displs[nprocs]; 
int sendcounts[nprocs]; 

//printf("B_MAX: %ld\n", B_MAX); 

//Inviamo (int)(A_MAX/nprocs) elementi tramite una scatter, resto è il 
//numero di elementi restanti che verranno inviati tramite la scatterv 
resto= A_MAX % nprocs; 
//printf("Resto: %d\n", resto); 

//Posizione da cui iniziare lo Scatterv 
svStartPos = A_MAX - resto; 
//printf("svStartPos: %d\n", svStartPos); 

// numero di elementi per processore senza tener conto del resto 
dim= (A_MAX-resto)/nprocs; 
//printf("dim: %d\n", dim); 

//Il processore 0 inizializza il vettore totale, del quale vogliamo 
//calcolare la somma 
if (myrank==0){ 
    for (i=0; i<A_MAX; i++) 
     vett[i]=1; 
} 

//Ciascun processore inizializza il vettore locale del quale calcoleremo la 
//somma parziale dei suoi elementi. tale somma parziale verrà utilizzata 
//nell'operazione di reduce 
for (i=0; i<B_MAX; i++) 
    parsum[i]=-1; 

//Ciascun processore inizializza i vettori sendcounts e displs necessari per 
//l'operazione di scatterv 
for (i=0; i<nprocs; i++){ 
    if (i<A_MAX-svStartPos){ 
     //Se il rank del processore è compreso tra 0 e resto ... 
     sendcounts[i]=1;   //...verrà inviato 1 elemento di vett... 
     displs[i]= svStartPos+i; //...di posizione svStartPos+i 
    } 
    else { 
     //se il rank del processore è > resto ... 
     sendcounts[i]=0;   //...non verrà inviato alcun elemento 
     displs[i]= A_MAX;   
    } 
} 

root = 0; //Il processore master 

sumtot = 0; //Valore della domma totale degli elementi di vett 
temp = 0; //valore temporaneo delle somme parziali 

MPI_Barrier(MPI_COMM_WORLD); 

if (A_MAX>=nprocs){ 
    MPI_Scatter(&vett[dim*myrank], dim, MPI_LONG, &parsum, dim, MPI_LONG, 0, MPI_COMM_WORLD); 
    printf("Processore: %d - Scatter\n", myrank); 
} 

//La scatterv viene effettuata solo dai processori che hanno il rank 
//0<myrank<resto 
if (sendcounts[myrank]==1){  
    MPI_Scatterv(&vett,sendcounts,displs,MPI_LONG,&c,1,MPI_LONG,0,MPI_COMM_WORLD); 
    parsum[B_MAX-1]=c; 
    printf("Processore: %d - effettuo la Scatterv\n", myrank); 
} 

MPI_Barrier(MPI_COMM_WORLD); 

if(myrank==0){ 
    t0 = MPI_Wtime(); //inizio conteggio tempo 
} 

for(i=0; i<B_MAX; i++){ 
    if (parsum[i]!=-1)  
     temp = temp + parsum[i]; //somma degli elementi 
} 
printf("Processore: %d - Somma parziale: %ld\n", myrank, temp); 

MPI_Barrier(MPI_COMM_WORLD); 

//il risultato di somma di ogni processore viene mandato al root che somma 
//i risultati parziali 
MPI_Reduce(&temp,&sumtot,1,MPI_LONG,MPI_SUM,root,MPI_COMM_WORLD); 

MPI_Barrier(MPI_COMM_WORLD); 

if(myrank==0){ 
    t1 = MPI_Wtime(); //stop al tempo 

    //calcolo e stampa del tempo trascorso 
    time = 1.e6 * (t1-t0); 
    printf("NumProcessori: %d Somma: %ld Tempo: %f\n", nprocs, sumtot, time); 

    //verifica del valore somma. Se è corretto sumtot è pari a 0. 
    sumtot = sumtot - A_MAX; 
    printf("Verifica: %ld\n", sumtot); 
} 

MPI_Finalize(); 

return 0; 

}

回答

0

我發現的第一個真正的錯誤是這行:

MPI_Scatterv(&vett,sendcounts,displs,MPI_LONG,&c,1,MPI_LONG,0,MPI_COMM_WORLD); 

哪一個::std::vector<int>的地址傳遞給需要的那個理着void*的功能。任何指針類型(如::std::vector<int>*)到void*的轉換均允許作爲隱式轉換,因此此時不存在編譯錯誤。但是,MPI_Scatterv預計它的第一個參數是發送緩衝區的地址,MPI預期這是一個普通數組。

我想你最近從註釋掉的部分更改了你的代碼,其中vett是一個數組,並試圖通過在你的MPI_Scatterv調用中添加地址 - 運算符來使你的呼叫工作。原始數組可能會在某些時候導致段錯誤,因爲它是堆棧分配的,並且您與這些怪物用完了堆棧空間(Linux系統上的默認堆棧大小爲兆字節iirc的數量級,這恰好符合該假設 - 用此測試ulimit -s)。

::std::vector<int>的更改導致將實際數據放置在堆上,而堆上的最大大小更大(並且在64位系統上,您可能預計會在更早時間耗盡物理內存)。實際上,你已經實現了一個解決您的特定問題的幾行前面:

MPI_Scatter(&vett[dim*myrank], dim, MPI_LONG, &parsum, dim, MPI_LONG, 0, MPI_COMM_WORLD); 

在這裏,您可以訪問一個元素,然後取它的地址(注意:[]binds tighter&)。還行吧。只要你不修改底層的vector。如果你只是應用該解決方案先前調用,你可以很容易地解決這個問題:

MPI_Scatterv(&vett[0],sendcounts,displs,MPI_LONG,&c,1,MPI_LONG,0,MPI_COMM_WORLD); 

在任何情況下,除了兩個vector對象,你的代碼看起來就像是舊C標準編寫的,而不是C++ - 例如,您可能會考慮查看諸如而不是malloc.h,您可以將變量聲明與其定義一致(即使在for loop headers!內),也可以使用ostreamcout而不是printf來緩解您的生活。 ..

+0

對不起,原來的程序是不同的。我更新了與我的代碼的原始版本的問題... 不幸的是,如果我嘗試使用新的操作符我有編譯錯誤,因爲我在羣集上運行此程序,我不知道哪個版本的compilator它使用。 所以..我如何管理這些陣列而不支持矢量? – Giovanni

+0

如果你可以使用'vector'編譯代碼,那麼你可能有權訪問新的操作符....你有沒有看看堆棧限制與你的兩個數組的大小......? –

+0

如果我嘗試#include「vector.h」我收到「沒有這樣的文件或目錄」錯誤。 我不知道棧的限制,因爲我在我的大學的集羣上運行程序,並且我沒有太多的機器細節.. – Giovanni

0

該程序似乎對我來說一個C,因爲你沒有使用任何C++工具或任何頭文件(本來是cstdio,沒有.h)。

無論如何,你可以用一個標準配置替換數組分配,一個[非常大的數字]嗎?如果你想C,malloc,否則,。然後發佈結果。

這似乎是一個堆分配問題(http://c-faq.com/strangeprob/biglocal.html)。

讓我知道。