2011-11-18 37 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)。

让我知道。