Re: Matrix multiplication performance

palik imre <[email protected]>
Newsgroups gmane.comp.lib.boost.ublas
Message-ID <[email protected]>
According to https://gcc.gnu.org/projects/cxx1z.html , no SIMD support in gcc.

I'll give OpenMP a try.  But right now I think gcc SIMD vectors have some advantages over it.  Off course, I don't know how well they are supported by icc & clang, but they should also be cpu architecture independent, and work out of the box.  I mean adding the OpenMP flag when compiling a single-threaded program feels a bit weird.



Again, could anybody try the various vectorised kernels on non-x86 arch?


On Monday, 1 February 2016, 15:06, Nasos Iliopoulos <[email protected]> wrote:
Have you tried to use openmp 4.0 SIMD, so we don't have to deal with CPU 
architecture details? Also we can check the status of c++17 SIMD for 
various compilers?

Also please check this out:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4454.pdf


On 01/30/2016 11:48 AM, 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.