2011-11-18 2 views
0

매우 큰 배열의 값을 합산하기 위해 C++로 MPI 프로그램을 작성하려고합니다. 아래 코드는 배열 크기가 최대 1 백만까지는 잘 작동하지만 1 천만 개 이상의 요소로 실행하려고하면 음조 오류가 발생합니다. 누군가 나를 도울 수 있니? 감사합니다매우 큰 배열을 사용할 때 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

내가 찾은 첫 번째 실제 오류가이 줄을이었다

그 인수에 void*을 예상하는 함수에 ::std::vector<int>의 주소를 전달
MPI_Scatterv(&vett,sendcounts,displs,MPI_LONG,&c,1,MPI_LONG,0,MPI_COMM_WORLD); 

. 모든 포인터 유형 (예 : ::std::vector<int>*)을 void*으로 변환하면 암시 적 변환이 허용되므로이 시점에서 컴파일 오류가 발생하지 않습니다. 그러나 MPI_Scatterv은 첫 번째 인수가 송신 버퍼의 주소가 될 것으로 예상하며 MPI는 정상 배열로 간주합니다.

vett이 배열이고 MPI_Scatterv 호출에서 주소 연산자를 추가하여 전화를 받으려고했던 주석 처리 된 섹션에서 코드를 최근에 변경 한 것 같습니다. 원래 배열은 아마도 스택 할당 이후에 어떤 지점에서 segfault를 발생 시켰고 그 괴물과 스택 공간을 다 썼습니다 (리눅스 시스템의 기본 스택 크기는이 가정에 정확히 맞는 메가 바이트 단위의 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합니다)를. 이것은 O.K입니다. 단, 기본으로 제공되는 vector을 수정하지 않는 한 방금 이전 호출에 해당 솔루션을 적용하면, 당신은 아주 쉽게이 문제를 해결할 수 :

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

을 어떤 경우에는, 그것은 기존의 C 표준 용으로 작성된 것처럼 두 vector 객체에 대해, 코드가 보인다 제외하고, 예를 들어 malloc.h이 아닌 대신에 변수 선언을 넣을 수 있습니다 (심지어 for loop headers!도 포함)! printf 대신 ostreamcout을 사용하여 일상 생활을 편하게 만듭니다. ..

+0

죄송합니다. 원본 프로그램이 다릅니다. 내 코드의 원래 버전으로 질문을 업데이 트 ... 불행히도 내가 클러스터 에서이 프로그램을 실행하기 때문에 나는 컴파일 오류가 컴파일러의 버전을 모르겠다 새 연산자를 사용하려고하면 사용. 그래서 .. 벡터없이 이러한 배열을 어떻게 관리 할 수 ​​있습니까? – Giovanni

+0

'vector'를 사용하여 코드를 컴파일 할 수 있다면 아마 새로운 연산자에 접근 할 수 있습니다 .... 두 배열의 크기 대 스택 한도를 보았습니까? –

+0

"vector.h"를 #include하면 "No such file or directory"오류가 발생합니다. 대학의 클러스터에서 프로그램을 실행하기 때문에 스택 제한을 알지 못합니다. 컴퓨터의 세부 정보가 너무 많습니다. – Giovanni

0

당신이 어떤 것을 사용하지 않으므로 프로그램이 나에게 보인다. C++ 기능 또는 임의의 헤더 (cstdio, .h없이).

어쨌든 배열 할당 [A very huge]을 표준 할당으로 대체 할 수 있습니까? C를 원하면 malloc, 그렇지 않으면 . 그런 다음 결과를 게시하십시오.

이것은 힙 할당 문제 (http://c-faq.com/strangeprob/biglocal.html) 인 것 같습니다.

알려주세요.