Content |
Verteilte Matrizen
Die Klasse hpc::mpi::GeMatrix soll eine \(M \times N\) Matrix darstellen, deren Elemente blockweise auf mehreren Rechen-Knoten liegen koennen. Dabei sollen die Knoten als \(m \times n\) Gitter zweidimensional organisiert sein, so dass sich folgende Partionierung ergibt:
\[B = \left(\begin{array}{c|c|c|c} B_{0,0} & B_{0,1} & \dots & B_{0,n-1} \\ \hline \vdots & & & \vdots \\ \hline B_{m-1,0} & B_{0,1} & \dots & B_{m-1,n-1} \end{array}\right)\]Die Partitionierung sei dabei quasi-äquidistant, so dass alle inneren Blöcke die gleiche Anzahl an Zeilen bzw. Spalten besitzen.
Durch diese Abstraktion sollen technische Details bezüglich MPI sinnvoll versteckt werden. Sei zum Beispiel
-
A vom Typ hpc::matvec::GeMatrix also eine lokale Matrix und
-
B vom Typ hpc::mpi::GeMatrix eine verteilte Matrix,
dann sollen die Scatter und Gather Operationen durch die Funktionsaufrufe
gecopy(A, B); // Scatter gecopy(B, A); // Gather
ausgeführt werden.
Die Klasse hpc::mpi::Grid
Da der Funktionsaufruf keinen MPI-Kommunikator benötigt, muss diese Information in der Matrix-Klasse hpc::mpi::GeMatrix verkapselt enthalten sein. Dazu soll die Klasse hpc::mpi::Grid dienen. Die Deklaration der Klasse sei als
#ifndef HPC_MPI_GRID_H #define HPC_MPI_GRID_H 1 #include <mpi.h> namespace hpc { namespace mpi { struct Grid { Grid(); int numNodeRows, numNodeCols; int nodeRow, nodeCol; int nof_processes, rank; MPI_Comm comm; }; } } // namespaces mpi, hpc #endif // HPC_MPI_GRID_H
vorgegeben.
Aufgabe
Implementiert die Klasse hpc::mpi::Grid. Im Konstruktor soll (analog zur Session 22) mit MPI_Cart_create der Kommunikator comm für ein zweidimensionales Grid angelegt werden. Die weiteren Attribute sollen anschliessend folgende Werte enthalten:
-
numNodeRows, numNodeCols die Anzahl der Zeilen und Spalten des Grids.
-
nodeRow, nodeCol die Zeile und Spalte des Prozesses im Grid.
Die Klasse hpc::mpi::GeMatrix
Eine verteilte Matrix vom Typ hpc::mpi::GeMatrix speichert den lokalen Matrix-Block in einer Matrix vom Typ hpc::matvec::GeMatrix. Informationen bezüglich der Partitionierung können durch folgende Methoden berechnet werden:
-
getRowOffset(r, c) berechnet den globalen Zeilen-Index des Blockes \(A_{r,c}\),
-
getColOffset(r, c) berechnet den globalen Spalten-Index des Blockes \(A_{r,c}\),
-
getNumRows(r, c) berechnet die Zeilenanzahl des Blockes \(A_{r,c}\),
-
getNumCols(r, c) berechnet den Spaltenanzahl des Blockes \(A_{r,c}\),
Aufgabe
Als Vorlage für eine Implementierung soll folgende Vorlage benutzt werden:
#ifndef HPC_MPI_GEMATRIX_H #define HPC_MPI_GEMATRIX_H 1 #include <cassert> #include <mpi.h> #include <hpc/matvec/gematrix.h> #include <hpc/matvec/isgematrix.h> namespace hpc { namespace mpi { template <typename T, typename I> struct GeMatrix { typedef T ElementType; typedef I Index; using StorageOrder = hpc::matvec::StorageOrder; GeMatrix(Index numRows, Index numCols, Grid grid); Index getRowOffset(Index nodeRow) const; Index getColOffset(Index nodeCol) const; Index getNumRows(Index nodeRow) const; Index getNumCols(Index nodeCol) const; Index numRows, numCols; Grid grid; hpc::matvec::GeMatrix<T,I> buffer; }; } } // namespaces mpi, hpc #endif // HPC_MPI_GEMATRIX_H
Aufgabe: Scatter/Gather
Analog zu Session 22 kann nun die Scatter und Gather Operation umgesetzt werden. Bei einem Scatter sollen die Bloecke eine \(M \times N\) Matrix vom Typ hpc::matvec::GeMatrix an die lokalen Matrix-Bloecke einer verteilten Matrix vom Type hpc::mpi::GeMatrix gesendet werden. Beim Gather soll dies umgekehrt werden.
Im Gegensatz zur Session 22 soll dies aber durch folgende Funktionen veranlasst werden:
#ifndef HPC_MPI_COPY_H #define HPC_MPI_COPY_H 1 #include <cassert> #include <mpi.h> #include <hpc/matvec/gematrix.h> #include <hpc/matvec/isgematrix.h> #include <hpc/matvec/copy.h> #include <hpc/mpi/gematrix.h> #include <hpc/mpi/matrix.h> namespace hpc { namespace mpi { // scatter template <typename T, typename Index> void copy(const hpc::matvec::GeMatrix<T, Index> &A, GeMatrix<T, Index> &B) { /* ... */ } // gather template <typename T, typename Index> void copy(const GeMatrix<T, Index> &A, hpc::matvec::GeMatrix<T, Index> &B) { /* ... */ } } } // namespaces mpi, hpc #endif // HPC_MPI_COPY_H
Vorlage zum Testen
#include <hpc/matvec/print.h> #include <hpc/mpi/grid.h> #include <hpc/mpi/gematrix.h> #include <hpc/mpi/copy.h> #include <mpi.h> #include <cstdio> int main(int argc, char** argv) { MPI_Init(&argc, &argv); typedef std::size_t Index; hpc::mpi::Grid grid; Index numRows = 10; Index numCols = 10; hpc::matvec::GeMatrix<double, Index> A(numRows, numCols); hpc::matvec::GeMatrix<double, Index> B(numRows, numCols); hpc::mpi::GeMatrix<double, Index> dA(numRows, numCols, grid); if (grid.nodeRow==0 && grid.nodeCol==0) { for (Index i=0; i<numRows; ++i) { for (Index j=0; j<numCols; ++j) { A(i,j) = i + j*numRows; } } } if (grid.nodeRow==0 && grid.nodeCol==0) { hpc::matvec::print(A, "A"); } // scatter hpc::mpi::copy(A, dA); // gather hpc::mpi::copy(dA, B); if (grid.nodeRow==0 && grid.nodeCol==0) { hpc::matvec::print(B, "B"); } MPI_Finalize(); }