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

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:

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:

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();
}