Content

Lösungsvorschlag

$shell> gcc -Wall dgemm_macro.c
$shell> ./a.out
A =
    1.0000     2.0000     3.0000     4.0000     5.0000     6.0000     7.0000     8.0000     9.0000    10.0000    11.0000    12.0000 
   13.0000    14.0000    15.0000    16.0000    17.0000    18.0000    19.0000    20.0000    21.0000    22.0000    23.0000    24.0000 
   25.0000    26.0000    27.0000    28.0000    29.0000    30.0000    31.0000    32.0000    33.0000    34.0000    35.0000    36.0000 
   37.0000    38.0000    39.0000    40.0000    41.0000    42.0000    43.0000    44.0000    45.0000    46.0000    47.0000    48.0000 
   49.0000    50.0000    51.0000    52.0000    53.0000    54.0000    55.0000    56.0000    57.0000    58.0000    59.0000    60.0000 
   61.0000    62.0000    63.0000    64.0000    65.0000    66.0000    67.0000    68.0000    69.0000    70.0000    71.0000    72.0000 
   73.0000    74.0000    75.0000    76.0000    77.0000    78.0000    79.0000    80.0000    81.0000    82.0000    83.0000    84.0000 
   85.0000    86.0000    87.0000    88.0000    89.0000    90.0000    91.0000    92.0000    93.0000    94.0000    95.0000    96.0000 


B =
    1.0000     2.0000     3.0000     4.0000     5.0000     6.0000     7.0000 
    8.0000     9.0000    10.0000    11.0000    12.0000    13.0000    14.0000 
   15.0000    16.0000    17.0000    18.0000    19.0000    20.0000    21.0000 
   22.0000    23.0000    24.0000    25.0000    26.0000    27.0000    28.0000 
   29.0000    30.0000    31.0000    32.0000    33.0000    34.0000    35.0000 
   36.0000    37.0000    38.0000    39.0000    40.0000    41.0000    42.0000 
   43.0000    44.0000    45.0000    46.0000    47.0000    48.0000    49.0000 
   50.0000    51.0000    52.0000    53.0000    54.0000    55.0000    56.0000 
   57.0000    58.0000    59.0000    60.0000    61.0000    62.0000    63.0000 
   64.0000    65.0000    66.0000    67.0000    68.0000    69.0000    70.0000 
   71.0000    72.0000    73.0000    74.0000    75.0000    76.0000    77.0000 
   78.0000    79.0000    80.0000    81.0000    82.0000    83.0000    84.0000 


C =
    1.0000     2.0000     3.0000     4.0000     5.0000     6.0000     7.0000 
    8.0000     9.0000    10.0000    11.0000    12.0000    13.0000    14.0000 
   15.0000    16.0000    17.0000    18.0000    19.0000    20.0000    21.0000 
   22.0000    23.0000    24.0000    25.0000    26.0000    27.0000    28.0000 
   29.0000    30.0000    31.0000    32.0000    33.0000    34.0000    35.0000 
   36.0000    37.0000    38.0000    39.0000    40.0000    41.0000    42.0000 
   43.0000    44.0000    45.0000    46.0000    47.0000    48.0000    49.0000 
   50.0000    51.0000    52.0000    53.0000    54.0000    55.0000    56.0000 


2.000000*C + 2.000000*A*B =
 4732.0000  4844.0000  4956.0000  5068.0000  5180.0000  5292.0000  5404.0000 
12546.0000 12898.0000 13250.0000 13602.0000 13954.0000 14306.0000 14658.0000 
20360.0000 20952.0000 21544.0000 22136.0000 22728.0000 23320.0000 23912.0000 
28174.0000 29006.0000 29838.0000 30670.0000 31502.0000 32334.0000 33166.0000 
35988.0000 37060.0000 38132.0000 39204.0000 40276.0000 41348.0000 42420.0000 
43802.0000 45114.0000 46426.0000 47738.0000 49050.0000 50362.0000 51674.0000 
51616.0000 53168.0000 54720.0000 56272.0000 57824.0000 59376.0000 60928.0000 
59430.0000 61222.0000 63014.0000 64806.0000 66598.0000 68390.0000 70182.0000 


C_ref =
 4732.0000  4844.0000  4956.0000  5068.0000  5180.0000  5292.0000  5404.0000 
12546.0000 12898.0000 13250.0000 13602.0000 13954.0000 14306.0000 14658.0000 
20360.0000 20952.0000 21544.0000 22136.0000 22728.0000 23320.0000 23912.0000 
28174.0000 29006.0000 29838.0000 30670.0000 31502.0000 32334.0000 33166.0000 
35988.0000 37060.0000 38132.0000 39204.0000 40276.0000 41348.0000 42420.0000 
43802.0000 45114.0000 46426.0000 47738.0000 49050.0000 50362.0000 51674.0000 
51616.0000 53168.0000 54720.0000 56272.0000 57824.0000 59376.0000 60928.0000 
59430.0000 61222.0000 63014.0000 64806.0000 66598.0000 68390.0000 70182.0000 
$shell> 
#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");
}

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

void
dgecopy(int m, int n,
        const double *X, int incRowX, int incColX,
        double *Y, int incRowY, int incColY)
{
    int i, j;

    for (i=0; i<m; ++i) {
        for (j=0; j<n; ++j) {
            Y[i*incRowY+j*incColY] = X[i*incRowX+j*incColX];
        }
    }
}

void
dgescal(int m, int n, double alpha,
        double *X, int incRowX, int incColX)
{
    int i, j;

    for (j=0; j<n; ++j) {
        for (i=0; i<m; ++i) {
            X[i*incRowX+j*incColX] *= alpha;
        }
    }
}

void
dgeaxpy(int m, int n, double alpha,
        const double *X, int incRowX, int incColX,
        double *Y, int incRowY, int incColY)
{
    int i, j;

    if (alpha==0 || m==0 || n==0) {
        return;
    }
    for (j=0; j<n; ++j) {
        for (i=0; i<m; ++i) {
            Y[i*incRowY+j*incColY] += alpha*X[i*incRowX+j*incColX];
        }
    }
}

void
dgemm_ilj(int m, int n, int k,
          double alpha,
          const double *A, int incRowA, int incColA,
          const double *B, int incRowB, int incColB,
          double beta,
          double *C, int incRowC, int incColC)
{
    int i, j, l;

    for (i=0; i<m; ++i) {
        for (l=0; l<k; ++l) {
            for (j=0; j<n; ++j) {
                if (l==0) {
                    C[i*incRowC+j*incColC] *= beta;
                }
                C[i*incRowC+j*incColC] += alpha*A[i*incRowA+l*incColA]
                                               *B[l*incRowB+j*incColB];
            }
        }
    }
}

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

#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 m, int k, const double *A, int incRowA, int incColA, double *p)
{
    int i, i0, j, l, nu;
    int mp = (m+DGEMM_MR-1) / DGEMM_MR;

    for (j=0; j<k; ++j) {
        for (l=0; l<mp; ++l) {
            for (i0=0; i0<DGEMM_MR; ++i0) {
                i     = l*DGEMM_MR + i0;
                nu    = l*DGEMM_MR*k + j*DGEMM_MR + i0;
                p[nu] = (i<m) ? A[i*incRowA+j*incColA]
                              : 0;
            }
        }
    }
}

void
dpack_B(int k, int n, const double *B, int incRowB, int incColB, double *p)
{
    int i, j, j0, l, nu;
    int np = (n+DGEMM_NR-1) / DGEMM_NR;

    for (l=0; l<np; ++l) {
        for (j0=0; j0<DGEMM_NR; ++j0) {
            j = l*DGEMM_NR + j0;
            for (i=0; i<k; ++i) {
                nu    = l*DGEMM_NR*k + i*DGEMM_NR + j0;
                p[nu] = (j<n) ? B[i*incRowB+j*incColB]
                              : 0;
            }
        }
    }
}

void
dgemm_micro(int k,
            double alpha,
            const double *A,
            const double *B,
            double beta,
            double *C, int incRowC, int incColC)
{
    int    i, j, l;
    double AB[DGEMM_MR*DGEMM_NR];

    for (l=0; l<DGEMM_MR*DGEMM_NR; ++l) {
        AB[l] = 0;
    }
    for (l=0; l<k; ++l) {
        for (j=0; j<DGEMM_NR; ++j) {
            for (i=0; i<DGEMM_MR; ++i) {
                AB[i+j*DGEMM_MR] += A[i+l*DGEMM_MR]*B[j+l*DGEMM_NR];
            }
        }
    }
    if (beta==0) {
        for (j=0; j<DGEMM_NR; ++j) {
            for (i=0; i<DGEMM_MR; ++i) {
                C[i*incRowC+j*incColC] = alpha*AB[i+j*DGEMM_MR];
            }
        }
    } else {
        for (j=0; j<DGEMM_NR; ++j) {
            for (i=0; i<DGEMM_MR; ++i) {
                C[i*incRowC+j*incColC] = beta*C[i*incRowC+j*incColC]
                                       + alpha*AB[i+j*DGEMM_MR];
            }
        }
    }
}

void
dgemm_macro(int m, int n, int k,
            double alpha,
            const double *A,
            const double *B,
            double beta,
            double *C, int incRowC, int incColC)
{
    double C_[DGEMM_MR*DGEMM_NR];
    int i, j;

    const int MR = DGEMM_MR;
    const int NR = DGEMM_NR;

    for (j=0; j<n; j+=NR) {
        int nr = (j+NR<n) ? NR
                          : n - j;

        for (i=0; i<m; i+=MR) {
            int mr = (i+MR<m) ? MR
                              : m - i;

            if (mr==MR && nr==NR) {
                dgemm_micro(k, alpha,
                            &A[i*k], &B[j*k],
                            beta,
                            &C[i*incRowC+j*incColC], incRowC, incColC);
            } else {
                dgemm_micro(k, alpha,
                            &A[i*k], &B[j*k],
                            0.,
                            C_, 1, MR);
                dgescal(mr, nr, beta,
                        &C[i*incRowC+j*incColC], incRowC, incColC);
                dgeaxpy(mr, nr, 1., C_, 1, MR,
                        &C[i*incRowC+j*incColC], incRowC, incColC);
            }
        }
    }
}

//------------------------------------------------------------------------------
#ifndef DIM_M
#define DIM_M 8
#endif

#ifndef DIM_N
#define DIM_N 7
#endif

#ifndef DIM_K
#define DIM_K 12
#endif

#ifndef ALPHA
#define ALPHA 2
#endif

#ifndef BETA
#define BETA 2
#endif

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

#ifndef ROWMAJOR_B
#define INCROW_B 1
#define INCCOL_B DIM_K
#else
#define INCROW_B DIM_N
#define INCCOL_B 1
#endif

#ifndef ROWMAJOR_C
#define INCROW_C 1
#define INCCOL_C DIM_M
#else
#define INCROW_C DIM_N
#define INCCOL_C 1
#endif

double A[DIM_M*DIM_K];
double B[DIM_K*DIM_N];

double A_[DGEMM_MC*DGEMM_KC];
double B_[DGEMM_KC*DGEMM_NC];

double C[DIM_M*DIM_N];
double C_ref[DIM_M*DIM_N];

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

int
main()
{
    initGeMatrix(DIM_M, DIM_K, A, INCROW_A, INCCOL_A);
    initGeMatrix(DIM_K, DIM_N, B, INCROW_B, INCCOL_B);
    initGeMatrix(DIM_M, DIM_N, C, INCROW_C, INCCOL_C);
    dgecopy(DIM_M, DIM_N,
            C, INCROW_C, INCCOL_C,
            C_ref, INCROW_C, INCCOL_C);

    // pack block from A
    dpack_A(MIN(DIM_M, DGEMM_MC), MIN(DIM_K, DGEMM_KC),
            A, INCROW_A, INCCOL_A, A_);

    // pack block from B
    dpack_B(MIN(DIM_K, DGEMM_KC), MIN(DIM_N, DGEMM_NC),
            B, INCROW_B, INCCOL_B, B_);

    printf("A =\n");
    printGeMatrix(DIM_M, DIM_K, A, INCROW_A, INCCOL_A);
    printf("B =\n");
    printGeMatrix(DIM_K, DIM_N, B, INCROW_B, INCCOL_B);
    printf("C =\n");
    printGeMatrix(DIM_M, DIM_N, C, INCROW_C, INCCOL_C);

    // pack block from A
    dpack_A(MIN(DIM_M, DGEMM_MC), MIN(DIM_K, DGEMM_KC),
            A, INCROW_A, INCCOL_A, A_);

    // pack block from B
    dpack_B(MIN(DIM_K, DGEMM_KC), MIN(DIM_N, DGEMM_NC),
            B, INCROW_B, INCCOL_B, B_);

    // multiply with macro-kernel
    dgemm_macro(MIN(DIM_M, DGEMM_MC),
                MIN(DIM_N, DGEMM_NC),
                MIN(DIM_K, DGEMM_KC),
                (double)ALPHA,
                A_, B_,
                (double)BETA,
                C, INCROW_C, INCCOL_C);

    printf("%lf*C + %lf*A*B =\n", (double)ALPHA, (double)BETA);
    printGeMatrix(DIM_M, DIM_N, C, INCROW_C, INCCOL_C);

    printf("C_ref =\n");
    dgemm_ilj(MIN(DIM_M, DGEMM_MC),
              MIN(DIM_N, DGEMM_NC),
              MIN(DIM_K, DGEMM_KC),
              (double)ALPHA,
              A, INCROW_A, INCCOL_A,
              B, INCROW_B, INCCOL_B,
              (double)BETA,
              C_ref, INCROW_C, INCCOL_C);
    printGeMatrix(DIM_M, DIM_N, C_ref, INCROW_C, INCCOL_C);

    return 0;
}