Content

Cache-Optimiertes Matrix-Matrix Produkt

Wir werden folgende Block-Faktoren verwenden:

Mathe-Notation

Makro-Name

\(M_c\)

DGEMM_MC

\(N_c\)

DGEMM_NC

\(K_c\)

DGEMM_KC

\(M_r\)

DGEMM_MR

\(N_r\)

DGEMM_NR

In level3.c werden wir drei Varianten für die GEMM-Operation und zwei Pack-Funktionen hinzufügen. Wir beschreiben zunächst nur die GEMM-Operation etwas genauer:

Packen von Matrix-Blöcken aus \(A\)

Sei \(A\) ein Matrix-Block der Dimension \(m_c \times k_c\) mit \(m_c \leq M_c\) und \(k_c \leq K_c\). Weiter sei \(\overline{A}\) ein Puffer mit \(M_c \times K_c\) Elementen, die wir mit \(p_{0}, p_{1}, \dots, p_{M_c \cdot K_c-1}\) bezeichnen.

Den Block \(A\) betrachten wir auf unterschiedliche Weise:

Der Puffer soll nach folgendem Algorithmus mit \(M_r \cdot k_c \cdot m_p\) Elementen gefüllt werden:

In der nachfolgenden Testvorlage wird eine \(10\times 12\) Matrix \(A\) bezüglich \(M_c = 8\) und \(K_c = 10\) in vier Blöcke partitioniert. Diese sollen bezüglich \(M_r = 4\) wiederum in horizonatale Paneele unterteilt werden:

Das Programm ist stand-alone benötigt also nicht das Projekt der letzten Session.

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <sys/times.h>
#include <unistd.h>

//-- setup and print matrices --------------------------------------------------

void
initGeMatrix(int m, int n, double *A, int incRowA, int incColA)
{
    int i, j;

    for (i=0; i<m; ++i) {
        for (j=0; j<n; ++j) {
            A[i*incRowA+j*incColA] = i*n + j + 1;
        }
    }
}

void
printGeMatrix(int m, int n, const double *A, int incRowA, int incColA)
{
    int i, j;

    for (i=0; i<m; ++i) {
        for (j=0; j<n; ++j) {
            printf("%10.4lf ", A[i*incRowA+j*incColA]);
        }
        printf("\n");
    }
    printf("\n\n");
}

//------------------------------------------------------------------------------

#ifndef DGEMM_MC
#define DGEMM_MC 8
#endif

#ifndef DGEMM_NC
#define DGEMM_NC 9
#endif

#ifndef DGEMM_KC
#define DGEMM_KC 10
#endif

#ifndef DGEMM_MR
#define DGEMM_MR 4
#endif

#ifndef DGEMM_NR
#define DGEMM_NR 3
#endif



//------------------------------------------------------------------------------

void
dpack_A(int mc, int kc, const double *A, int incRowA, int incColA, double *p)
{
    int i, i0, j, l, nu;
    int mp = (m+DGEMM_MR-1) / DGEMM_MR;

    // ... your code here ...
}

//------------------------------------------------------------------------------

#ifndef DIM_M
#define DIM_M 10
#endif

#ifndef DIM_K
#define DIM_K 12
#endif

#ifndef ROWMAJOR
#define INCROW_A 1
#define INCCOL_A DIM_M
#else
#define INCROW_A DIM_K
#define INCCOL_A 1
#endif

#define MIN(X,Y) (X) < (Y) ? (X) : (Y)

double A[DIM_M*DIM_K];
double A_buffer[DGEMM_MC*DGEMM_KC];

int
main()
{
    initGeMatrix(DIM_M, DIM_K, A, INCROW_A, INCCOL_A);

    printf("A=\n");
    printGeMatrix(DIM_M, DIM_K, A, INCROW_A, INCCOL_A);

    printf("Nach packen von Block links oben\n");
    dpack_A(MIN(DIM_M, DGEMM_MC), MIN(DIM_K, DGEMM_KC),
            A, INCROW_A, INCCOL_A, A_buffer);

    printf("A_buffer=\n");
    printGeMatrix(1, DGEMM_MC*DGEMM_KC, A_buffer, 0, 1);

    printf("Nach packen von Block rechts oben\n");
    // ... your code here ...

    printf("A_buffer=\n");
    printGeMatrix(1, DGEMM_MC*DGEMM_KC, A_buffer, 0, 1);

    printf("Nach packen von Block links unten\n");
    // ... your code here ...

    printf("A_buffer=\n");
    printGeMatrix(1, DGEMM_MC*DGEMM_KC, A_buffer, 0, 1);

    printf("Nach packen von Block rechts unten\n");
    // ... your code here ...

    printf("A_buffer=\n");
    printGeMatrix(1, DGEMM_MC*DGEMM_KC, A_buffer, 0, 1);

    return 0;
}

Packen von Matrix-Blöcken aus \(B\)

Analog soll ein Block der Dimension \(k_c \times n_c\) mit \(k_c \leq K_c\) und \(n_c \leq N_c\) bezüglich \(N_r\) in vertikale Paneele partioniert und gepackt werden (inklusive Zero-Padding):