2017-11-28 1 views
0

Ich versuche, die Berechnung der Norm2 eines Vektors (variable Größe) zu parallelisieren. Mein Ansatz war, zuerst den Vektor unter den Prozessoren zu streuen, das Quadrat und die Summe der einzelnen Untervektoren zu berechnen und dann die Reslut zu reduzieren und die Quadratwurzel anzuwenden.How to Scatter dann Reduce mit MPI und C++

Hier ist mein Code:

#include <mpi.h> 
#include <vector> 
#include <iostream> 
#include <cmath> 

double SquareSum(std::vector<double> & v) { 

double res; 

for (std::vector<double>::iterator it = v.begin(); it != v.end(); it++){ 
    if (*it){ 
     res += (*it)*(*it); 
    } 
    else{ 
     it++; 
    } 
} 

return res; 
} 




int main(int argc, char *argv[]){ 

std::vector<double> numbers; 
double val; 
while (std::cin >> val) numbers.push_back(val); 



MPI_Init(&argc,&argv); 

int rank, size; 

MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
MPI_Comm_size(MPI_COMM_WORLD, &size); 

unsigned numbers_count = numbers.size(); 

MPI_Bcast(&numbers_count, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD); 

unsigned local_share = numbers_count/size; // local_share is the floor function of numbers.size()/number of process 


if (numbers_count % size > 0){ 
    ++local_share; // if size is not a multiple of numbers.size() add 1 to local_share in order to make it "fit" 
} 

if (rank == 0){ 
numbers.resize(local_share*size); //resize numbers by adding null empty spot if necessary 
} 

//std::cout << "I'm" << rank << std::endl; 
std::vector<double> local(local_share); 

MPI_Scatter(&numbers, local_share, MPI_DOUBLE, &local, local_share, MPI_DOUBLE, 0, MPI_COMM_WORLD); 

double par_sum = SquareSum(local); 

double sum = 0; 


MPI_Reduce(&par_sum, &sum, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); 

if (rank == 0){ 

    std::cout << "norm : " << std::sqrt(sum); 
} 
MPI_Finalize(); 
return 0; 
} 

Wenn ich versuche, das Programm Ich habe diesen Fehler auszuführen:

„mpiexec diesen Prozess Rang bemerkte 2 mit PID 9823 auf Knoten Laptop auf Signal verlassen 11 (Segmentierungsfehler). "

Ich vermute, es gibt ein Problem mit der Streuung, aber ich kann nicht herausfinden, was.

Danke für die Hilfe

+1

'& number' und' & local' sind die Adressen der Kontrollstrukturen der Vektorobjekte, nicht die Daten, die sie enthalten. Probieren Sie stattdessen '& numbers [0]' und '& local [0]' aus. –

+0

Ich ändere den Code und ich habe den gleichen Fehler. Aber ich habe etwas recherchiert und könnte auf einen Mangel an Speicher zurückzuführen sein. (so etwas wie addind swap) – LaGranf

Antwort

0

Neben dem Kommentar von @Hristo Iliev:

Die Größe numbers ist nicht ein Vielfaches der Größe wahrscheinlich. Dann wird local_sharenumbers_count % size+1. Es wird als die Größe des Teils verwendet, den jeder Prozess durch MPI_Scatter() erreicht. Als Ergebnis muss der gestreute Vektor eine Größe von (numbers_count % size+1)*size haben. Da der bereitgestellte Vektor numbers wahrscheinlich zu klein ist, versucht das Programm, Elemente außerhalb des Bereichs zu betreten, was undefiniertes Verhalten wie einen Segmentierungsfehler auslöst.

Zwei Lösungen:

  • Push-back Nullen bis numbers.size()%size==0. Es modifiziert den Vektor, der für zukünftige Anwendungen nicht praktisch und ziemlich hässlich ist.
  • Verwenden Sie MPI_Scatterv()!
+0

Also habe ich nichts geändert, aber aus irgendeinem Grund funktioniert es jetzt. Ich werde eine Implementierung mit MPI_Scatterv() versuchen. Ich weiß, dass die Größe wahrscheinlich kein Vielfaches der Größe ist, aber die Division von zwei vorzeichenlosen a, b Variablen ist äquivalent zu floor (a/b). Dies ist nicht offensichtlich, es ist wahr, ich werde es als Kommentar in meinem Code hinzufügen. Danke für Ihre Hilfe. – LaGranf

+0

Gern geschehen! Es wird ein undefiniertes Verhalten genannt, weil das Problem unbemerkt bleiben kann oder das Ergebnis des Programms fehlerhaft sein kann oder das Problem an einem schmerzhaften Tod sterben kann, wie z. B. Segmentierungsfehler: Das Problem kann später auftreten. Auch wenn a/b ist Boden (a/b), (a/b + 1) * b ist wahrscheinlich größer als a! (11/10 + 1) * 10 = 20. Wenn Sie MPI_Scatterv() mit korrekten Zählungen und Verschiebungen verwenden, wird das Problem gelöst! – francis