LCOV - code coverage report
Current view: top level - modules/linalg - igemm_arr.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 87 135 64.4 %
Date: 2024-05-13 05:06:06 Functions: 7 9 77.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*************************************************************************
       2             :  *
       3             :  *  Project
       4             :  *                         _____ _____  __  __ _____
       5             :  *                        / ____|  __ \|  \/  |  __ \
       6             :  *  ___  _ __   ___ _ __ | |  __| |__) | \  / | |__) |
       7             :  * / _ \| '_ \ / _ \ '_ \| | |_ |  ___/| |\/| |  ___/
       8             :  *| (_) | |_) |  __/ | | | |__| | |    | |  | | |
       9             :  * \___/| .__/ \___|_| |_|\_____|_|    |_|  |_|_|
      10             :  *      | |
      11             :  *      |_|
      12             :  *
      13             :  * Copyright (C) Akiel Aries, <akiel@akiel.org>, et al.
      14             :  *
      15             :  * This software is licensed as described in the file LICENSE, which
      16             :  * you should have received as part of this distribution. The terms
      17             :  * among other details are referenced in the official documentation
      18             :  * seen here : https://akielaries.github.io/openGPMP/ along with
      19             :  * important files seen in this project.
      20             :  *
      21             :  * You may opt to use, copy, modify, merge, publish, distribute
      22             :  * and/or sell copies of the Software, and permit persons to whom
      23             :  * the Software is furnished to do so, under the terms of the
      24             :  * LICENSE file. As this is an Open Source effort, all implementations
      25             :  * must be of the same methodology.
      26             :  *
      27             :  *
      28             :  *
      29             :  * This software is distributed on an AS IS basis, WITHOUT
      30             :  * WARRANTY OF ANY KIND, either express or implied.
      31             :  *
      32             :  ************************************************************************/
      33             : 
      34             : /** Integer type GEneral Matrix-Matrix product */
      35             : #include <cmath>
      36             : #include <limits>
      37             : #include <openGPMP/linalg/_igemm.hpp>
      38             : #include <stddef.h>
      39             : #include <stdio.h>
      40             : #include <stdlib.h>
      41             : #include <time.h>
      42             : 
      43             : // MATRIX BUFFERS
      44             : int gpmp::linalg::IGEMM::IGEMM_BUFF_A[BLOCK_SZ_M * BLOCK_SZ_K];
      45             : int gpmp::linalg::IGEMM::IGEMM_BUFF_B[BLOCK_SZ_K * BLOCK_SZ_N];
      46             : int gpmp::linalg::IGEMM::IGEMM_BUFF_C[BLOCK_SZ_MR * BLOCK_SZ_NR];
      47             : 
      48             : // pack micro panels of size BLOCK_SZ_MR rows by k columns from A without
      49             : // padding
      50         768 : void gpmp::linalg::IGEMM::pack_micro_A(int k,
      51             :                                        const int *A,
      52             :                                        int incRowA,
      53             :                                        int incColA,
      54             :                                        int *buffer) {
      55             :     int i, j;
      56             : 
      57      262912 :     for (j = 0; j < k; ++j) {
      58     1310720 :         for (i = 0; i < BLOCK_SZ_MR; ++i) {
      59     1048576 :             buffer[i] = A[i * incRowA];
      60             :         }
      61      262144 :         buffer += BLOCK_SZ_MR;
      62      262144 :         A += incColA;
      63             :     }
      64         768 : }
      65             : 
      66             : // packs panels from A with padding if needed
      67           9 : void gpmp::linalg::IGEMM::pack_buffer_A(int mc,
      68             :                                         int kc,
      69             :                                         const int *A,
      70             :                                         int incRowA,
      71             :                                         int incColA,
      72             :                                         int *buffer) {
      73           9 :     int mp = mc / BLOCK_SZ_MR;
      74           9 :     int _mr = mc % BLOCK_SZ_MR;
      75             : 
      76             :     int i, j;
      77             : 
      78         777 :     for (i = 0; i < mp; ++i) {
      79         768 :         pack_micro_A(kc, A, incRowA, incColA, buffer);
      80         768 :         buffer += kc * BLOCK_SZ_MR;
      81         768 :         A += BLOCK_SZ_MR * incRowA;
      82             :     }
      83           9 :     if (_mr > 0) {
      84           0 :         for (j = 0; j < kc; ++j) {
      85           0 :             for (i = 0; i < _mr; ++i) {
      86           0 :                 buffer[i] = A[i * incRowA];
      87             :             }
      88           0 :             for (i = _mr; i < BLOCK_SZ_MR; ++i) {
      89           0 :                 buffer[i] = 0;
      90             :             }
      91           0 :             buffer += BLOCK_SZ_MR;
      92           0 :             A += incColA;
      93             :         }
      94             :     }
      95           9 : }
      96             : 
      97             : // packing complete panels from B of size BLOCK_SZ_NR by k columns
      98         768 : void gpmp::linalg::IGEMM::pack_micro_B(int k,
      99             :                                        const int *B,
     100             :                                        int incRowB,
     101             :                                        int incColB,
     102             :                                        int *buffer) {
     103             :     int i, j;
     104             : 
     105      262912 :     for (i = 0; i < k; ++i) {
     106     1310720 :         for (j = 0; j < BLOCK_SZ_NR; ++j) {
     107     1048576 :             buffer[j] = B[j * incColB];
     108             :         }
     109      262144 :         buffer += BLOCK_SZ_NR;
     110      262144 :         B += incRowB;
     111             :     }
     112         768 : }
     113             : 
     114             : // packing panels from B with padding if needed
     115           3 : void gpmp::linalg::IGEMM::pack_buffer_B(int kc,
     116             :                                         int nc,
     117             :                                         const int *B,
     118             :                                         int incRowB,
     119             :                                         int incColB,
     120             :                                         int *buffer) {
     121           3 :     int np = nc / BLOCK_SZ_NR;
     122           3 :     int _nr = nc % BLOCK_SZ_NR;
     123             : 
     124             :     int i, j;
     125             : 
     126         771 :     for (j = 0; j < np; ++j) {
     127         768 :         pack_micro_B(kc, B, incRowB, incColB, buffer);
     128         768 :         buffer += kc * BLOCK_SZ_NR;
     129         768 :         B += BLOCK_SZ_NR * incColB;
     130             :     }
     131           3 :     if (_nr > 0) {
     132           0 :         for (i = 0; i < kc; ++i) {
     133           0 :             for (j = 0; j < _nr; ++j) {
     134           0 :                 buffer[j] = B[j * incColB];
     135             :             }
     136           0 :             for (j = _nr; j < BLOCK_SZ_NR; ++j) {
     137           0 :                 buffer[j] = 0;
     138             :             }
     139           0 :             buffer += BLOCK_SZ_NR;
     140           0 :             B += incRowB;
     141             :         }
     142             :     }
     143           3 : }
     144             : 
     145             : // micro kernel that multiplies panels from A and B
     146      196608 : void gpmp::linalg::IGEMM::igemm_micro_kernel(int kc,
     147             :                                              int alpha,
     148             :                                              const int *A,
     149             :                                              const int *B,
     150             :                                              int beta,
     151             :                                              int *C,
     152             :                                              int incRowC,
     153             :                                              int incColC) {
     154             :     int AB[BLOCK_SZ_MR * BLOCK_SZ_NR];
     155             : 
     156             :     int i, j, l;
     157             : 
     158             :     // Compute AB = A*B
     159     3342336 :     for (l = 0; l < BLOCK_SZ_MR * BLOCK_SZ_NR; ++l) {
     160     3145728 :         AB[l] = 0;
     161             :     }
     162    67305472 :     for (l = 0; l < kc; ++l) {
     163   335544320 :         for (j = 0; j < BLOCK_SZ_NR; ++j) {
     164  1342177280 :             for (i = 0; i < BLOCK_SZ_MR; ++i) {
     165  1073741824 :                 AB[i + j * BLOCK_SZ_MR] += A[i] * B[j];
     166             :             }
     167             :         }
     168    67108864 :         A += BLOCK_SZ_MR;
     169    67108864 :         B += BLOCK_SZ_NR;
     170             :     }
     171             : 
     172             :     // Update C <- beta*C
     173      196608 :     if (beta == 0) {
     174      327680 :         for (j = 0; j < BLOCK_SZ_NR; ++j) {
     175     1310720 :             for (i = 0; i < BLOCK_SZ_MR; ++i) {
     176     1048576 :                 C[i * incRowC + j * incColC] = 0;
     177             :             }
     178             :         }
     179      131072 :     } else if (beta != 1) {
     180           0 :         for (j = 0; j < BLOCK_SZ_NR; ++j) {
     181           0 :             for (i = 0; i < BLOCK_SZ_MR; ++i) {
     182           0 :                 C[i * incRowC + j * incColC] *= beta;
     183             :             }
     184             :         }
     185             :     }
     186             : 
     187             :     // Update C <- C + alpha*AB (note: the case alpha==0 was already treated
     188             :     // in
     189             :     //                                  the above layer igemm_nn)
     190      196608 :     if (alpha == 1) {
     191      983040 :         for (j = 0; j < BLOCK_SZ_NR; ++j) {
     192     3932160 :             for (i = 0; i < BLOCK_SZ_MR; ++i) {
     193     3145728 :                 C[i * incRowC + j * incColC] += AB[i + j * BLOCK_SZ_MR];
     194             :             }
     195             :         }
     196             :     }
     197             : 
     198             :     else {
     199           0 :         for (j = 0; j < BLOCK_SZ_NR; ++j) {
     200           0 :             for (i = 0; i < BLOCK_SZ_MR; ++i) {
     201           0 :                 C[i * incRowC + j * incColC] += alpha * AB[i + j * BLOCK_SZ_MR];
     202             :             }
     203             :         }
     204             :     }
     205      196608 : }
     206             : 
     207             : // Compute Y += alpha*X (int precision AX + Y)
     208           0 : void gpmp::linalg::IGEMM::igeaxpy(int m,
     209             :                                   int n,
     210             :                                   int alpha,
     211             :                                   const int *X,
     212             :                                   int incRowX,
     213             :                                   int incColX,
     214             :                                   int *Y,
     215             :                                   int incRowY,
     216             :                                   int incColY) {
     217             :     int i, j;
     218             : 
     219           0 :     if (alpha != 1) {
     220           0 :         for (j = 0; j < n; ++j) {
     221           0 :             for (i = 0; i < m; ++i) {
     222           0 :                 Y[i * incRowY + j * incColY] +=
     223           0 :                     alpha * X[i * incRowX + j * incColX];
     224             :             }
     225             :         }
     226             :     }
     227             : 
     228             :     else {
     229           0 :         for (j = 0; j < n; ++j) {
     230           0 :             for (i = 0; i < m; ++i) {
     231           0 :                 Y[i * incRowY + j * incColY] += X[i * incRowX + j * incColX];
     232             :             }
     233             :         }
     234             :     }
     235           0 : }
     236             : 
     237             : //  Compute X *= alpha (scale elements)
     238           0 : void gpmp::linalg::IGEMM::igescal(int m,
     239             :                                   int n,
     240             :                                   int alpha,
     241             :                                   int *X,
     242             :                                   int incRowX,
     243             :                                   int incColX) {
     244             :     int i, j;
     245             : 
     246           0 :     if (alpha != 0) {
     247           0 :         for (j = 0; j < n; ++j) {
     248           0 :             for (i = 0; i < m; ++i) {
     249           0 :                 X[i * incRowX + j * incColX] *= alpha;
     250             :             }
     251             :         }
     252             :     }
     253             : 
     254             :     else {
     255           0 :         for (j = 0; j < n; ++j) {
     256           0 :             for (i = 0; i < m; ++i) {
     257           0 :                 X[i * incRowX + j * incColX] = 0;
     258             :             }
     259             :         }
     260             :     }
     261           0 : }
     262             : 
     263             : // Macro Kernel for the multiplication of blocks of A and B.  We assume that
     264             : // these blocks were previously packed to buffers IGEMM_BUFF_A and IGEMM_BUFF_B.
     265           9 : void gpmp::linalg::IGEMM::igemm_macro_kernel(int mc,
     266             :                                              int nc,
     267             :                                              int kc,
     268             :                                              int alpha,
     269             :                                              int beta,
     270             :                                              int *C,
     271             :                                              int incRowC,
     272             :                                              int incColC) {
     273             : 
     274           9 :     int mp = (mc + BLOCK_SZ_MR - 1) / BLOCK_SZ_MR;
     275           9 :     int np = (nc + BLOCK_SZ_NR - 1) / BLOCK_SZ_NR;
     276             : 
     277           9 :     int _mr = mc % BLOCK_SZ_MR;
     278           9 :     int _nr = nc % BLOCK_SZ_NR;
     279             : 
     280             :     int mr, nr;
     281             :     int i, j;
     282             : 
     283        2313 :     for (j = 0; j < np; ++j) {
     284        2304 :         nr = (j != np - 1 || _nr == 0) ? BLOCK_SZ_NR : _nr;
     285             : 
     286      198912 :         for (i = 0; i < mp; ++i) {
     287      196608 :             mr = (i != mp - 1 || _mr == 0) ? BLOCK_SZ_MR : _mr;
     288             : 
     289      196608 :             if (mr == BLOCK_SZ_MR && nr == BLOCK_SZ_NR) {
     290      196608 :                 igemm_micro_kernel(
     291             :                     kc,
     292             :                     alpha,
     293      196608 :                     &IGEMM_BUFF_A[i * kc * BLOCK_SZ_MR],
     294      196608 :                     &IGEMM_BUFF_B[j * kc * BLOCK_SZ_NR],
     295             :                     beta,
     296      196608 :                     &C[i * BLOCK_SZ_MR * incRowC + j * BLOCK_SZ_NR * incColC],
     297             :                     incRowC,
     298             :                     incColC);
     299             :             } else {
     300           0 :                 igemm_micro_kernel(kc,
     301             :                                    alpha,
     302           0 :                                    &IGEMM_BUFF_A[i * kc * BLOCK_SZ_MR],
     303           0 :                                    &IGEMM_BUFF_B[j * kc * BLOCK_SZ_NR],
     304             :                                    0,
     305             :                                    IGEMM_BUFF_C,
     306             :                                    1,
     307             :                                    BLOCK_SZ_MR);
     308           0 :                 igescal(
     309             :                     mr,
     310             :                     nr,
     311             :                     beta,
     312           0 :                     &C[i * BLOCK_SZ_MR * incRowC + j * BLOCK_SZ_NR * incColC],
     313             :                     incRowC,
     314             :                     incColC);
     315           0 :                 igeaxpy(
     316             :                     mr,
     317             :                     nr,
     318             :                     1.0,
     319             :                     IGEMM_BUFF_C,
     320             :                     1,
     321             :                     BLOCK_SZ_MR,
     322           0 :                     &C[i * BLOCK_SZ_MR * incRowC + j * BLOCK_SZ_NR * incColC],
     323             :                     incRowC,
     324             :                     incColC);
     325             :             }
     326             :         }
     327             :     }
     328           9 : }
     329             : 
     330             : // Main IGEMM entrypoint, compute C <- beta*C + alpha*A*B
     331           1 : void gpmp::linalg::IGEMM::igemm_nn(int m,
     332             :                                    int n,
     333             :                                    int k,
     334             :                                    int alpha,
     335             :                                    const int *A,
     336             :                                    int incRowA,
     337             :                                    int incColA,
     338             :                                    const int *B,
     339             :                                    int incRowB,
     340             :                                    int incColB,
     341             :                                    int beta,
     342             :                                    int *C,
     343             :                                    int incRowC,
     344             :                                    int incColC) {
     345           1 :     int mb = (m + BLOCK_SZ_M - 1) / BLOCK_SZ_M;
     346           1 :     int nb = (n + BLOCK_SZ_N - 1) / BLOCK_SZ_N;
     347           1 :     int kb = (k + BLOCK_SZ_K - 1) / BLOCK_SZ_K;
     348             : 
     349           1 :     int _mc = m % BLOCK_SZ_M;
     350           1 :     int _nc = n % BLOCK_SZ_N;
     351           1 :     int _kc = k % BLOCK_SZ_K;
     352             : 
     353             :     int mc, nc, kc;
     354             :     int i, j, l;
     355             : 
     356             :     int _beta;
     357             : 
     358           1 :     if (alpha == 0 || k == 0) {
     359           0 :         igescal(m, n, beta, C, incRowC, incColC);
     360           0 :         return;
     361             :     }
     362             : 
     363           2 :     for (j = 0; j < nb; ++j) {
     364           1 :         nc = (j != nb - 1 || _nc == 0) ? BLOCK_SZ_N : _nc;
     365             : 
     366           4 :         for (l = 0; l < kb; ++l) {
     367           3 :             kc = (l != kb - 1 || _kc == 0) ? BLOCK_SZ_K : _kc;
     368           3 :             _beta = (l == 0) ? beta : 1.0;
     369             : 
     370           3 :             pack_buffer_B(
     371             :                 kc,
     372             :                 nc,
     373           3 :                 &B[l * BLOCK_SZ_K * incRowB + j * BLOCK_SZ_N * incColB],
     374             :                 incRowB,
     375             :                 incColB,
     376             :                 IGEMM_BUFF_B);
     377             : 
     378          12 :             for (i = 0; i < mb; ++i) {
     379           9 :                 mc = (i != mb - 1 || _mc == 0) ? BLOCK_SZ_M : _mc;
     380             : 
     381           9 :                 pack_buffer_A(
     382             :                     mc,
     383             :                     kc,
     384           9 :                     &A[i * BLOCK_SZ_M * incRowA + l * BLOCK_SZ_K * incColA],
     385             :                     incRowA,
     386             :                     incColA,
     387             :                     IGEMM_BUFF_A);
     388             : 
     389           9 :                 igemm_macro_kernel(
     390             :                     mc,
     391             :                     nc,
     392             :                     kc,
     393             :                     alpha,
     394             :                     _beta,
     395           9 :                     &C[i * BLOCK_SZ_M * incRowC + j * BLOCK_SZ_N * incColC],
     396             :                     incRowC,
     397             :                     incColC);
     398             :             }
     399             :         }
     400             :     }
     401             : }

Generated by: LCOV version 1.14