Re: Matrix multiplication performance

Michael Lehn <[email protected]>
Newsgroups gmane.comp.lib.boost.ublas
Message-ID <[email protected]>
Thanks, for pointing this out.  You are right.

When stripping out too many special cases from the micro-kernels regarding matrix C (like C is
row/col major, aligned/not-aligned) and alpha=1 I also removed the case for beta=0.  At the moment
I regenerate the websites … and the tar-files

 


On 02 Feb 2016, at 16:32, Karl Rupp <[email protected]> wrote:

> Hi guys,
> 
> I'm sorry to interrupt your performance tuning fun, but please note that the kernel does not work correctly. To verify, consider the case that beta is equal to zero and that C initially consists of NaNs (which may happen in practice if you start if a freshly malloc'ed buffer)...
> 
> Best regards,
> Karli
> 
> 
> 
> 
> On 01/30/2016 05:48 PM, Michael Lehn wrote:
>> Here the same in slightly more general form
>> 
>> template <typename Index>
>> typename std::enable_if<std::is_convertible<Index, std::int64_t>::value
>>                      && BlockSize<double>::MR==4
>>                      && BlockSize<double>::NR==12
>>                      && BlockSize<double>::align==32,
>>          void>::type
>> ugemm(Index kc, double alpha,
>>       const double *A, const double *B,
>>       double beta,
>>       double *C, Index incRowC, Index incColC)
>> {
>>     static const Index MR = BlockSize<double>::MR;
>>     static const Index NR = BlockSize<double>::NR/4;
>>     typedef double vx __attribute__((vector_size (4*sizeof(double))));
>> 
>>     A = (const double*) __builtin_assume_aligned (A, 32);
>>     B = (const double*) __builtin_assume_aligned (B, 32);
>> 
>>     vx P[MR*NR] = {};
>> 
>>     for (Index l=0; l<kc; ++l) {
>>         const vx *b = (const vx *)B;
>> 
>>         for (Index i=0; i<MR; ++i) {
>>             for (Index j=0; j<NR; ++j) {
>>                 P[i*NR+j] += A[i]*b[j];
>>             }
>>         }
>>         A += MR;
>>         B += NR*4;
>>     }
>> 
>>     if (alpha!=double(1)) {
>>         for (Index i=0; i<MR; ++i) {
>>             for (Index j=0; j<NR; ++j) {
>>                 P[i*NR+j] *= alpha;
>>             }
>>         }
>>     }
>> 
>>     for (Index i=0; i<MR; ++i) {
>>         for (Index j=0; j<NR; ++j) {
>>             const double *p = (const double *) &P[i*NR+j];
>>             for (Index j1=0; j1<4; ++j1) {
>>                 C[i*incRowC+(j*4+j1)*incColC] *= beta;
>>                 C[i*incRowC+(j*4+j1)*incColC] += p[j1];
>>             }
>>         }
>>     }
>> }
>> 
>> On 30 Jan 2016, at 13:49, Michael Lehn <[email protected]> wrote:
>> 
>>> Ok, and this version for MR=4, NR=12 even beats the asm kernel on Haswell:
>>> 
>>> //-- Micro Kernel --------------------------------------------------------------
>>> template <typename Index>
>>> typename std::enable_if<std::is_convertible<Index, std::int64_t>::value
>>>                     && BlockSize<double>::MR==4
>>>                     && BlockSize<double>::NR==12
>>>                     && BlockSize<double>::align==32,
>>>         void>::type
>>> ugemm(Index kc, double alpha,
>>>      const double *A, const double *B,
>>>      double beta,
>>>      double *C, Index incRowC, Index incColC)
>>> {
>>>    static const Index MR = BlockSize<double>::MR;
>>>    static const Index NR = BlockSize<double>::NR;
>>>    typedef double vx __attribute__((vector_size (4*sizeof(double))));
>>> 
>>>    A = (const double*) __builtin_assume_aligned (A, 32);
>>>    B = (const double*) __builtin_assume_aligned (B, 32);
>>> 
>>>    vx P0_03 = {}; vx P0_47 = {}; vx P0_811 = {};
>>>    vx P1_03 = {}; vx P1_47 = {}; vx P1_811 = {};
>>>    vx P2_03 = {}; vx P2_47 = {}; vx P2_811 = {};
>>>    vx P3_03 = {}; vx P3_47 = {}; vx P3_811 = {};
>>> 
>>>    for (Index l=0; l<kc; ++l) {
>>>        const vx *b = (const vx *)B;
>>> 
>>>        P0_03 += A[0]*b[0]; P0_47 += A[0]*b[1]; P0_811 += A[0]*b[2];
>>>        P1_03 += A[1]*b[0]; P1_47 += A[1]*b[1]; P1_811 += A[1]*b[2];
>>>        P2_03 += A[2]*b[0]; P2_47 += A[2]*b[1]; P2_811 += A[2]*b[2];
>>>        P3_03 += A[3]*b[0]; P3_47 += A[3]*b[1]; P3_811 += A[3]*b[2];
>>>        A += MR;
>>>        B += NR;
>>>    }
>>> 
>>>    P0_03 *= alpha;  P0_47 *= alpha; P0_811 *= alpha;
>>>    P1_03 *= alpha;  P1_47 *= alpha; P1_811 *= alpha;
>>>    P2_03 *= alpha;  P2_47 *= alpha; P2_811 *= alpha;
>>>    P3_03 *= alpha;  P3_47 *= alpha; P3_811 *= alpha;
>>> 
>>>    if (beta!=double(1)) {
>>>        for (Index i=0; i<MR; ++i) {
>>>            for (Index j=0; j<NR; ++j) {
>>>                C[i*incRowC+j*incColC] *= beta;
>>>            }
>>>        }
>>>    }
>>> 
>>>    const double *p = (const double *) &P0_03;
>>>    C[0*incRowC+0*incColC] += p[0];
>>>    C[0*incRowC+1*incColC] += p[1];
>>>    C[0*incRowC+2*incColC] += p[2];
>>>    C[0*incRowC+3*incColC] += p[3];
>>> 
>>>    p = (const double *) &P0_47;
>>>    C[0*incRowC+4*incColC] += p[0];
>>>    C[0*incRowC+5*incColC] += p[1];
>>>    C[0*incRowC+6*incColC] += p[2];
>>>    C[0*incRowC+7*incColC] += p[3];
>>> 
>>>    p = (const double *) &P0_811;
>>>    C[0*incRowC+8*incColC] += p[0];
>>>    C[0*incRowC+9*incColC] += p[1];
>>>    C[0*incRowC+10*incColC] += p[2];
>>>    C[0*incRowC+11*incColC] += p[3];
>>> 
>>>    p = (const double *) &P1_03;
>>>    C[1*incRowC+0*incColC] += p[0];
>>>    C[1*incRowC+1*incColC] += p[1];
>>>    C[1*incRowC+2*incColC] += p[2];
>>>    C[1*incRowC+3*incColC] += p[3];
>>> 
>>>    p = (const double *) &P1_47;
>>>    C[1*incRowC+4*incColC] += p[0];
>>>    C[1*incRowC+5*incColC] += p[1];
>>>    C[1*incRowC+6*incColC] += p[2];
>>>    C[1*incRowC+7*incColC] += p[3];
>>> 
>>>    p = (const double *) &P1_811;
>>>    C[1*incRowC+8*incColC] += p[0];
>>>    C[1*incRowC+9*incColC] += p[1];
>>>    C[1*incRowC+10*incColC] += p[2];
>>>    C[1*incRowC+11*incColC] += p[3];
>>> 
>>>    p = (const double *) &P2_03;
>>>    C[2*incRowC+0*incColC] += p[0];
>>>    C[2*incRowC+1*incColC] += p[1];
>>>    C[2*incRowC+2*incColC] += p[2];
>>>    C[2*incRowC+3*incColC] += p[3];
>>> 
>>>    p = (const double *) &P2_47;
>>>    C[2*incRowC+4*incColC] += p[0];
>>>    C[2*incRowC+5*incColC] += p[1];
>>>    C[2*incRowC+6*incColC] += p[2];
>>>    C[2*incRowC+7*incColC] += p[3];
>>> 
>>>    p = (const double *) &P2_811;
>>>    C[2*incRowC+8*incColC] += p[0];
>>>    C[2*incRowC+9*incColC] += p[1];
>>>    C[2*incRowC+10*incColC] += p[2];
>>>    C[2*incRowC+11*incColC] += p[3];
>>> 
>>>    p = (const double *) &P3_03;
>>>    C[3*incRowC+0*incColC] += p[0];
>>>    C[3*incRowC+1*incColC] += p[1];
>>>    C[3*incRowC+2*incColC] += p[2];
>>>    C[3*incRowC+3*incColC] += p[3];
>>> 
>>>    p = (const double *) &P3_47;
>>>    C[3*incRowC+4*incColC] += p[0];
>>>    C[3*incRowC+5*incColC] += p[1];
>>>    C[3*incRowC+6*incColC] += p[2];
>>>    C[3*incRowC+7*incColC] += p[3];
>>> 
>>>    p = (const double *) &P3_811;
>>>    C[3*incRowC+8*incColC] += p[0];
>>>    C[3*incRowC+9*incColC] += p[1];
>>>    C[3*incRowC+10*incColC] += p[2];
>>>    C[3*incRowC+11*incColC] += p[3];
>>> 
>>> }
>> 
>> _______________________________________________
>> ublas mailing list
>> [email protected]
>> http://lists.boost.org/mailman/listinfo.cgi/ublas
>> Sent to: [email protected]
>> 
> 
> _______________________________________________
> ublas mailing list
> [email protected]
> http://lists.boost.org/mailman/listinfo.cgi/ublas
> Sent to: [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.