Ошибка сбоя сегментации MPI при использовании очень большого массива - PullRequest
0 голосов
/ 18 ноября 2011

Я пытаюсь написать программу MPI на C ++, чтобы суммировать значения очень большого массива. Приведенный ниже код хорошо работает с размером массива до 1 миллиона, но когда я пытаюсь выполнить с 10 миллионами элементов или более, я получаю ошибку сигментации. Кто-то может мне помочь? Спасибо

#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;

}

Ответы [ 2 ]

1 голос
/ 18 ноября 2011

Первая настоящая ошибка, которую я обнаружил, была такая:

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 - это массив, и попытались заставить ваш вызов работать, добавив оператор address-of в ваш вызов MPI_Scatterv. Исходный массив, вероятно, вызвал segfaults в какой-то момент, так как он был выделен стеком, и вы исчерпали пространство стека с этими монстрами (размер стека по умолчанию в системах Linux составляет порядка мегабайт iirc, что в точности соответствует этому предположению - проверьте это с помощью ulimit -s ).

Изменение на ::std::vector<int> привело к тому, что вместо этого фактические данные были помещены в кучу, которая имеет гораздо больший максимальный размер (и в 64-разрядных системах можно ожидать, что физической памяти будет не хватать раньше). Вы уже реализовали решение вашей конкретной проблемы несколькими строчками ранее:

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

Здесь вы получаете доступ к элементу и затем берете его адрес (обратите внимание, что [] связывает более жесткие , чем &). Хорошо. до тех пор, пока вы не измените базовый vector. Если вы просто примените это решение к предыдущему вызову, вы можете решить эту проблему довольно легко:

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

В любом случае, за исключением двух vector объектов, ваш код выглядит так, как будто он был написан для старого стандарта C, а не для C ++ - например, вы можете рассмотреть такие вещи, как new Семейство операторов вместо malloc.h, вы можете поместить объявления переменных в соответствие с их определениями (даже внутри for заголовков цикла !), упростив вашу жизнь с помощью ostream cout вместо printf ...

0 голосов
/ 29 ноября 2011

Программа мне кажется C, так как вы не используете никаких средств C ++ или каких-либо заголовков (которые были бы cstdio , без .h ).

В любом случае, не могли бы вы заменить распределение массива A [очень большое число] стандартным распределением?Если вы хотите C, malloc , в противном случае, new .Затем опубликуйте результаты.

Кажется, это проблема с выделением кучи (http://c -faq.com / fantasticprob / biglocal.html).

Дайте мне знать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...