Previous ToC Next

10. HPL 書き直し (2009/9/2 書きかけ)

別のところに書いたような事情で、 HPL を書き直してます。とりあえず MPI とか並列化は後回しで、どういうメモリレイアウトやチューニングをするか、 を1ノードの短いプログラムで調べています。

普通に Top500 で使われている HPL は、行列のデータ格納の順序が Column Major (列優先)というもので、 が変わるものが連続アド レスに入ります。これは、ピボット探索ではメモリフットプリントが最小にな るし、また昔からある普通の縦ブロックガウスでキャッシュ(昔ならディスクで ない主記憶自体))を有効に使うという話であれば、これを逆転させて Row Major (行優先)にする、というのは全くありえない話です。

が、行列乗算にアクセラレータを使い、また そのためのブロック化に Gustavson の再帰的ブロッキングとかを使うと話が変わってきます。まず、行 列乗算の効率を上げるために right-looking にするので、ここに関しては縦長 の行列と横長の行の積となり、行優先でも列優先でも同じです。再帰的パネル 分解では縦長の行列と小さな正方行列の積(結果は縦長)となるので、これは列 優先のほうが若干得ですが、行列サイズが極端に小さい(幅がキャッシュライン サイズ以下になる)場合でなければ大きな性能差はでないでしょう。

right-looking の場合には、右側に残っている部分正方行列全体に対して、部 分ピボットの結果でてくる行交換を行う必要があります。この部分は列優先で は非常に不利で、どうやってもキャッシュラインの殆どが無駄になります。

さて、では、ピボット探索と行交換の両方を高速にするのは不可能か、という と、縦方向に再帰分解をしているわけなので、適当なサイズのところで転置 すればよいはずです。転置のための余計なメモリアクセスが発生するわけです が、

というのを同時に満足できれば、メインメモリからは行列半分を読み出して半 分を格納、となります。また、転置はその領域を更新する行列乗算の直後 に起こるので、行列乗算ルーチンが結果をキャッシュに残していれば(これは、 moventpd を使わない、ということでもありますが)、高い性能が期待できます。 ということで、まだ GRAPE-DR を使っていないしシングルコアのコードですが、 転置を行うものを書いてみました。これは、8列になったところで転置します。 また、最大のブロックサイズは 64 です。N=2K で、 Athlon 64 X2 4050e で のプロファイルの結果が以下です。実際の実行時間は 1.8秒だったので、下の 時間速度はあまり正確ではありませんが、相対値には意味があるかな?という 程度です。

 Each sample counts as 0.01 seconds.
   %   cumulative   self              self     total           
  time   seconds   seconds    calls  ms/call  ms/call  name    
  86.41      1.27     1.27                             dgemm_kernel
   2.72      1.31     0.04      256     0.16     0.16  transpose_coltorow
   2.04      1.34     0.03                             dgemm_otcopy
   1.36      1.36     0.02     8192     0.00     0.00  swaprows
   1.36      1.38     0.02        1    20.00    20.00  copymats
   0.68      1.39     0.01     4096     0.00     0.00  vvmulandsub
   0.68      1.40     0.01     1024     0.01     0.01  column_decomposition
   0.68      1.41     0.01      256     0.04     0.04  solve_triangle
   0.68      1.42     0.01      256     0.04     0.04  transpose_rowtocol
   0.68      1.43     0.01      193     0.05     0.05  matmul_for_small_nk
   0.68      1.44     0.01        1    10.00    10.00  backward_sub
   0.68      1.45     0.01                             dgemm_beta
   0.68      1.46     0.01                             dgemm_nn
   0.68      1.47     0.01                             dgemm_oncopy
 
copymats は初期の行列をコピーする関数で、ソルバの時間にははいりません。 dgemm 以外で無視できない時間を占めるのは

 transpose_coltorow   列優先から行優先に戻す
 swaprows             行交換
 vvmulandsub          ベクトル同士の外積 
 column_decomposition 再帰の最後のパネル分解
 solve_triangle       3角行列の求解
 transpose_rowtocol   行優先から列優先に転置
 matmul_for_small_nk  行優先の状態での縦長な行列と小さな行列の乗算
といった辺りです。参考のために、 single core での STREAM の実行結果は

 Function      Rate (MB/s)   RMS time     Min time     Max time
 Copy:        4096.5704       0.0500       0.0500       0.0504
 Scale:       2506.7073       0.0818       0.0817       0.0829
 Add:         3410.3011       0.0901       0.0901       0.0901
 Triad:       3247.1131       0.0946       0.0946       0.0947
というところです。これは、moventpd イントリンシックを使ったもので、 Triad では

        for (j=0; j<N/2; j++)
            //      a[j] = b[j]+scalar*c[j];
            __builtin_ia32_movntpd((double*)&av[j], bv[j]+ss*cv[j]);
というようなコードです。Scale が極端に遅いですが、まあ 3-4GB/s がメモ リの実力です。

まず、一番上の行列転置 transpose_coltorow ですが、行列全体は 32MBで、 そのうち半分が転置に関係するので 16MB、これを 0.04 sec でなんとかして いるので速度は 400MB/s で、話にならないほど遅いので明らかに工夫が必要 です。swaprows は交換のためにには 2回読んで書く必要があり、それでも 半分の時間でおわっているのでまあよいような気がします。

上のテストで転置に使ったのは

 void transpose_coltorow(int n, double a[][RDIM],int m, double at[][n],
                        int istart)
 {
     int i,j;
     for(i=istart;i<n;i++)
        for(j=0;j<m;j++)
            a[i][j] = at[j][i];
 }
という全くなんの芸もないコードです。こんなのでは駄目に決まっているので、 色々改良してみます。まずはブロック化です。一旦、 m x m の正方行列に転 置しながらコピーして、それを連続アクセスでコピー、としてみます。

 void transpose_coltorow(int n, double a[][RDIM],int m, double at[][n],
                        int istart)
 {
     int i,j,k;
     double atmp[m][m];
     for(i=istart;i<n;i+=m){
        for(j=0;j<m;j++){
            for(k=0;k<m;k++){
                atmp[k][j]  =at[j][i+k];
            }
        }
        for(k=0;k<m;k++){
            for(j=0;j<m;j++){
                a[i+k][j] = atmp[k][j];
            }
        }
     }
 }
これの結果は

  0.65      1.52     0.01      256     0.04     0.04  transpose_coltorow
というところで、測定精度があまりありませんが遅くなってはいません。後半 のコピーで、 moventpd を使ってみると

            v2df * atp = (v2df*) atmp[k];
            for(j=0;j<m;j+=2)
                __builtin_ia32_movntpd(a[i+k]+j, atp[j/2]);
 
という感じです。これは速いか、というと、

  0.00      1.51     0.00      256     0.00     0.00  transpose_coltorow
となって確かに速いのですが、全体の実行時間は必ずしも短くはなりません。 これは、moventpd では代入した結果がキャッシュに残らないのですが、実際に は代入した結果はそのあとすぐに使うので、どうせまたキャッシュにはいって くるからです。これは行列優先から列優先への転置でも同じで、movntpd を使 うとこの関数自体は速くなったように見えるのですが、プログラム全体として はあまり変化しません。 rdtsc 命令を使って実行時間を直接測定して見ると、 実は movntpd 命令を使わないほうが 30% 程度短く、転送速度(上り下り合計) では 2.7GB/s 程度でていました。 (0.09words/clk 程度)

部分的にはキャッシュ内の移動ですんでいるはず、と思うとまだ遅いので、内 側のループを 4 重にアンロールしてみます。

 void transpose_coltorow(int n, double a[][RDIM],int m, double at[][n],
                        int istart)
 {
     int i,j,k;
     double atmp[m][m];
     for(i=istart;i<n;i+=m){
        for(j=0;j<m;j++){
            double * atj = at[j]+i;
            for(k=0;k<m;k+=4){
                atmp[k][j]  =atj[k];
                atmp[k+1][j]  =atj[k+1];
                atmp[k+2][j]  =atj[k+2];
                atmp[k+3][j]  =atj[k+3];
            }
        }
        for(k=0;k<m;k++){
            double * aik = a[i+k];
            for(j=0;j<m;j+=4){
                aik[j] = atmp[k][j];
                aik[j+1] = atmp[k][j+1];
                aik[j+2] = atmp[k][j+2];
                aik[j+3] = atmp[k][j+3];
            }
        }
     }
 }
 
これで 0.115words/clk 程度まで。アンロール、と考えてみると、この関数 は呼ぶ時の m の値はいつも同じなので、最内側は展開するべきでしょう。そ うすると、

 void transpose_coltorow8(int n, double a[][RDIM], double at[][n],
                        int istart)
 {
     int i,j,k;
     const int m=8;
     double atmp[m][m];
     for(i=istart;i<n;i+=m){
        for(j=0;j<m;j++){
            double * atj = at[j]+i;
            atmp[0][j]  =atj[0];
            atmp[1][j]  =atj[1];
            atmp[2][j]  =atj[2];
            atmp[3][j]  =atj[3];
            atmp[4][j]  =atj[4];
            atmp[5][j]  =atj[5];
            atmp[6][j]  =atj[6];
            atmp[7][j]  =atj[7];
        }
        for(k=0;k<m;k++){
            v2df * atp = (v2df*) atmp[k];
            v2df * ap = (v2df*) a[i+k];
            *(ap)=*(atp);
            *(ap+1)=*(atp+1);
            *(ap+2)=*(atp+2);
            *(ap+3)=*(atp+3);
        }
     }
 }
とより簡潔で高速なコードになり、0.13word/clk、4.4GB/s となってまあよい かも、というところです。キャッシュにはいっているはずの割には遅いのが気 になります。

次は行交換です。

 void swaprows(int n, double a[n][RDIM], int row1, int row2,
              int cstart, int cend)
 {
     /* WARNING: works only for row1 % 4 = 0 and RDIM >= n+4*/
     
     int j;
     if (row1 != row2){
        int jmax = (cend+1-cstart)/2;
        v2df *a1, *a2, tmp, tmp1;
        a1 = (v2df*)(a[row1]+cstart);
        a2 = (v2df*)(a[row2]+cstart);
        for(j=0;j<jmax;j+=2){
            tmp = a1[j];
            tmp1 = a1[j+1];
            a1[j]=a2[j];
            a1[j+1]=a2[j+1];
            a2[j]=tmp;
            a2[j+1]=tmp1;
            __builtin_prefetch(a1+j+16,1,0);
            __builtin_prefetch(a2+j+16,1,0);
        }
     }
 }
  
2重にアンロールし、 SSE を使い、プリフェッチもいれています。プリフェッ チをいれると、大体 0.07words/clock、2語の上り下りの合計としては 4.7GB/s となって、まあよいところです。プリフェッチなしだと 0.55words/clock 程度ですが、それなりにプリフェッチの効果はあります。

swaprows の後で正規化をする scalerow もみておきます。

 void scalerow( int n, double a[n][RDIM], double scale,
                int row, int cstart, int cend)
 {
     int j;
     for(j=cstart;j<cend;j++) a[row][j]*= scale;
 }
こんなのですね。

いじった後は

 void scalerow( int n, double a[n][RDIM], double scale,
               int row, int cstart, int cend)
 {
     int j;
     int jmax = (cend+1-cstart)/2;
     v2df *a1 = (v2df*)(a[row]+cstart);
     v2df ss = (v2df){scale,scale};
     for(j=0;j<jmax;j+=2){
        __builtin_prefetch(a1+j+16,1,0);
        a1[j] *= ss;
        a1[j+1]*= ss;
     }
 }
 
こんな感じで、 0.16words/cycle、5.4GB/s です。 これは、いじる前は 0.08words/cycle 程度だったので、SSE2 とプリフェッチの利用に非常に 大きな効果があります。

但し、scale と swap を一体化すれば余計な主記憶アクセスを減らせるので、 そっちも検討するべきですね。

GRAPE-DR のようなアクセラレータを使うシステムでは、Linpack Benchmark では行列乗算を速くするだけでは十分ではなく、主記憶全体をなめることに なる、つまり のあらゆる操作について、主記憶の理論バンド幅に 可能な限り近い速度がでる形にコードを書き直す必要があります。

ここまでで、行列乗算や3角行列の求解、つまり BLAS3 の用語でいうと DGEMM と DTRSM 以外についてはかなり高速なコードになっています。 DTRSM につい ては DGEMM に変換し、変換できないところも再帰的に DGEMM を取り出すアク セラレータ専用のアルゴリズムを使うとして、 DGEMM 自体はどうか、という のが以下の表です。シングルコアの K8 アーキテクチャなので2演算/クロック が最大で、 K=64 だと十分な性能になっていますが K=8 ではかなり低いこと がわかります。

    M     N   K             ops/clock
    2040    8   8           0.42988 
    2032   16  16           0.815346
    2024    8   8           0.435265
    2016   32  32           1.20451
    2008    8   8           0.428314
    2000   16  16           0.822711
    1992    8   8           0.434964
    1984 1985  64           1.70924
メモリバンド幅としてはどういうことになるかというと、 N=K=8 では 2 語読み 出して1語格納するのに対して 16 演算ですから、 0.08語、1.35GB/s となっ て、同じようなアクセスである STREAM ADD の 4 割程度しかでていません。 これはかなり大きな問題です。というのは、再帰的ブロッキングでは、各ブロッ クサイズでメモリアクセスは基本的には行列全体(細かいことをいうと 1/4)に なり、階層のレベル数、つまり最大ブロックサイズの対数回全体をなめるから です。もちろん、ここで K が大きいところではアクセラレータを 使うので、そっちのチューニングが問題ですが、 K が小さいところで主記憶 のバンド幅がでていない、ということは、そこに大きなオーバーヘッドがある、 ということになります。

今回 GotoBLAS 1.26 を使っていますが、中身をいじるのはやりたくないので このような小さい行列の時だけ書き下してみます。今までの例の中で同じよう なアクセスパターンなのは行列転置ですが、この場合には単純に、転置しなが ら正方行列に書いて、それを連続アクセスでコピー、というのでよい性能がで ました。従って、同じようなアプローチを考えてみます。

 void matmul_for_nk8(int n1, double a[][n1],
                         int n2, double b[][n2],
                         int n3, double c[][n3],
                         int m,
                         int n)
 {
     int i,j,k;
     const int kk = 8;
     const int kh = kk/2;
     int nh = n/2;
     v2df bcopy[nh][kk];
     v2df acopy2[kk][kk];
     for(k=0;k<kk;k++)
        for(j=0;j<nh;j++)
                bcopy[j][k] = *((v2df*)(b[k]+j+j));
     for(i=0;i<m;i+=kk){
        for(k=0;k<kk;k++){
            __builtin_prefetch(a+i+k+16,0,0);
            __builtin_prefetch(c+i+k+16,1,0);
        }
        for (j=0;j<n;j++){
            double * ap = (double*)( a[i+j]);
            for (k=0;k<kk;k++){
                acopy2[j][k]=(v2df){ap[k],ap[k]};
            }
        }
        for(k=0;k<kk;k++){
            v2df * cp = (v2df*) (c[i+k]);
            v2df * ap = acopy2[k];
            for(j=0;j<nh;j++){
                v2df * bp = bcopy[j];
                cp[j] -= ap[0]*bp[0] + ap[1]*bp[1]
                    + ap[2]*bp[2]    + ap[3]*bp[3]
                    + ap[4]*bp[4]    + ap[5]*bp[5]
                    + ap[6]*bp[6]    + ap[7]*bp[7];
            }
        }
     }
 }
 
これ、 N=K=8 でないと動かない代物ですが、

    M     N   K             ops/clock
    2040    8   8           0.727034
    2008    8   8           0.730609
    1992    8   8           0.782853
で、元々の BLAS に比べると 1.7 倍ほど速くなり、メモリバンド幅の7割程度 は有効利用できていることがわかります。このコードでは、 b は転置しながら ローカルにコピーします。a は、 SSE2 の2要素ベクトルに同じものがはいる 形でふくらませたローカルコピーを作ります。これは、 SSE2 命令が無能でス カラとベクタの掛け算ができないことに対応するためです。 a は大きな行列 で、b は小さいので、bを膨らませて a はそのまま、ですめば無駄が少ないの ですが、行列の格納のしかたがそれはできないような順番になっています。

で、 a, c についてはプリフェッチをかけています。今回高速になっているの は主にこの効果ですね。実際の演算では、aの2要素(同じものがはいっている) とbの2要素をいっぺんに積算して、 c の2要素を求める、という形になってい ます。

a を膨らまさないで、SSE の2要素に同じ行のデータが入るようにして DOTD 命令で加算するほうが無駄が少なくて速いような気がしますが、 gcc 4.1.2 のイントリンシックには dotd はなさそうなので今回はそっちは使っていませ ん。

ここは、さらにいじましい高速化を考えると、どうせ次に転置するんだから 転置してから乗算するべきです。そうすると、もっと容易に高速化ができま す。

転置したあとの行列乗算も、幅が狭いだけに性能が重要です。この場合、基本 的にキャッシュに載っているはずなので、命令スケジューリングによるはずで す。 GotoBLAS の性能は、 n=k=2、 4 で 0.4、 0.7 ops/clock となっていて、 キャッシュだと思うとどうにも遅い、という感じです。 メモリバンド幅としては3語で 4、 8 演算ですから、5GB/s 程度です。L2 で ももっとでるはずなので、工夫の余地があります。

N=2048 の行列で、計算時間が大体 1.75 秒ですが、そのうち n=k=2 の行列の 計算時間が 5ms 程度です。これは小さいように見えるのですが、大きな行列 乗算が相対的に 100倍程度速くなると、行列サイズを10倍程度大きくしても無 視できないわけです。

というわけで、ここまでで、

以外は大体済んだ、ということになります。

Ci7 の機械を組んだので、そっちで実験(A64 と比較)をしています。

 Athlon, N=2K
 swaprows time=3.2801e+07
 scalerow time=1.42839e+07
 trans rtoc8 time=3.25526e+07
 trans ctor8 time=1.63445e+07
 Ci7 920 (3GHz), N=2K
 swaprows time=9.78e+06
 scalerow time=3.29607e+06
 trans rtoc8 time=1.42135e+07
 trans ctor8 time=6.05478e+06
 Ci7 920 (3GHz), N=8K
 swaprows time=1.79584e+08
 scalerow time=5.39146e+07
 trans rtoc8 time=2.53306e+08
 trans ctor8 time=1.1879e+08
 trans dgemm time=2.07928e+08
 trans nonrec cdec time=1.77051e+08
メモリアクセスの総量はそれぞれ 64MB, 32 MB, 32 MB, 32MB なので、速度は
             A64 2.1GHz   Ci7 3GHz  Ci7 (N=8K)
 swaprows      4.1            19.6    18.1
 scalerow      4.7            29.1    37.9
 trans rtoc8   2.07           6.7     8.1
 trans ctor8   4.1            15.9    17.2
です。32K の場合、このへんで2秒くらいはまだかかる計算になります。主記 憶リミットであるので並列化には殆ど意味がないかな、という気もしますが、 まあ、 OMP でやってみると:

  N=8K, Ci7
  trans rtoc8 time=1.74734e+08
  N=4k
  trans rtoc8 time=4.94381e+07
  N=2k
  trans rtoc8 time=1.77795e+07
意外に効果があります。N=2k では若干遅くなりますが、 8K では 1.5 倍近く 速くなります。スレッドで書いたらもうちょっといいかもしれません。 こういうものの並列化の場合、起動オーバーヘッドとメモリバンド幅の極限性 能、キャッシュ効率の3つの要因があるので性能予測が困難ですが、今キャッ シュのことは無視すると、N が無限に大きい時の性能は 8k の時から10-15% 程度の向上で、 11GB/s 程度と推測できます。 col2row については、

  N=8K trans ctor8 time=8.79587e+07
  N=4k trans ctor8 time=3.00645e+07
で、これもそれなりに効果があることがわかります。特に N がもっと大きい ところを考えるので Open MP の起動オーバーヘッドは十分小さくなり、 結構よくなることが期待できます。まあ、この場合、OpenMP の並列化ループ は1000回くらいしか呼ばれていなくて、実行が 10マイクロ秒程度ですから OpenMP の起動オーバーヘッドはその程度あるわけです。ベクトル化に比べる とはるかにオーバーヘッドが大きく、利用が難しいもの、ということがわかり ます。

Ci7 (というか、Core 2 以降?)は、デフォルトでは勝手にに L2 に2ライン (128バイト)もってくる、というオプションがあるんだそうで、これは確かに Bios で有効になってたので、 1ライン単位での転置が遅いのはこれが原因 と思われます。

とはいえ、このオプションを BIOS で切ると

 Nswap=0 cpsec =  46.3909 wsec=14.1913
 swaprows time=1.80358e+08
 scalerow time=5.39611e+07
 trans rtoc8 time=1.93491e+08
 trans ctor8 time=1.01146e+08
 trans dgemm time=2.42105e+08
 trans nonrec cdec time=1.65904e+08
 trans vvmul time=5.65689e+07
 trans findp time=1.06555e+08
 
 Nswap=0 cpsec =  46.4709 wsec=13.9176
 swaprows time=1.81601e+08
 scalerow time=5.47325e+07
 trans rtoc8 time=1.86051e+08
 trans ctor8 time=8.86901e+07
 trans dgemm time=2.48892e+08
 trans nonrec cdec time=1.66319e+08
 trans vvmul time=5.68656e+07
 trans findp time=1.06808e+08
 
ON にすると
 Nswap=0 cpsec =  46.4349 wsec=46.4116
 swaprows time=1.79092e+08
 scalerow time=5.39498e+07
 trans rtoc8 time=1.90267e+08
 trans ctor8 time=1.01477e+08
 trans dgemm time=2.3238e+08
 trans nonrec cdec time=1.66845e+08
 trans vvmul time=5.69506e+07
 trans findp time=1.07196e+08
 
Nswap=0 cpsec = 46.7269 wsec=13.9467 swaprows time=1.80993e+08 scalerow time=5.44132e+07 trans rtoc8 time=1.88233e+08 trans ctor8 time=9.26843e+07 trans dgemm time=2.40648e+08 trans nonrec cdec time=1.65907e+08 trans vvmul time=5.64983e+07 trans findp time=1.06597e+08

全然変わらない。これは、プリフェッチが十分効いてない、ということだと思 われ、、、というか、コードをちゃんとみたら、あ、プリフェッチの入れかた が間違ってました、、、まあ、でも、直しても普通は変わらないと、、、Core i7 のメモリレイテンシは 200サイクル程度らしいので、20GB/s = 7B/cycle と すれば大雑把には 200語程度先読みをしていないといけないことになります。。

以下は細かい作業記録なのであんまり読んでも役に立たないです。

 Nswap=0 cpsec =  46.4469 wsec=14.2066
 swaprows time=1.82082e+08
 scalerow time=5.46414e+07
 trans rtoc8 time=1.89987e+08
 trans ctor8 time=9.16793e+07
 trans dgemm time=2.45399e+08
 trans nonrec cdec time=1.68357e+08
 trans vvmul time=5.64953e+07
 trans findp time=1.08689e+08
 solve tri u time=9.15278e+07
 solve tri   time=1.05368e+09
 matmul nk8  time=2.3478e+08
 matmul snk  time=3.00549e+08
nk8 は、256 MB アクセスのはず。snk も同じ。

16で転置すると

 Nswap=0 cpsec =  46.5109 wsec=13.6755
 swaprows time=1.80648e+08
 scalerow time=5.29178e+07
 trans rtoc8 time=0
 trans ctor8 time=9.17586e+07
 trans dgemm time=3.54391e+08
 trans nonrec cdec time=1.66416e+08
 trans vvmul time=5.67401e+07
 trans findp time=1.07049e+08
 solve tri u time=9.06005e+07
 solve tri   time=9.15348e+08
 matmul nk8  time=0
 matmul snk  time=2.97462e+08
転置のメモリアクセス: 512MB。これを 0.028 秒だと、16GB/s で結構速い。

matmul snk は 256MB を 0.1 秒で遅い。演算速度は 8k x 8k /4 * 32 =0.54e9 くらいなので、 5Gflops

 OMP_NUM_THREADS=2, snk を OMP で。 
  
 Emax=  4.007e-10
 Nswap=0 cpsec =  46.0989 wsec=23.3147
 swaprows time=1.80596e+08
 scalerow time=5.2993e+07
 trans rtoc8 time=0
 trans ctor8 time=8.32039e+07
 trans dgemm time=1.84467e+19
 trans nonrec cdec time=1.66061e+08
 trans vvmul time=5.74618e+07
 trans findp time=1.06753e+08
 solve tri u time=9.12501e+07
 solve tri   time=1.06944e+09
 matmul nk8  time=0
 matmul snk  time=1.55114e+08
 
なんだか素晴らしい効果がある。

m=8 で転置に戻すと

 Emax=  8.745e-10
 Nswap=0 cpsec =  46.1349 wsec=23.2356
 swaprows time=1.79216e+08
 scalerow time=5.33178e+07
 trans rtoc8 time=1.6885e+08
 trans ctor8 time=8.19126e+07
 trans dgemm time=1.95553e+08
 trans nonrec cdec time=1.66091e+08
 trans vvmul time=5.65165e+07
 trans findp time=1.06811e+08
 solve tri u time=1.84467e+19
 solve tri   time=1.07682e+09
 matmul nk8  time=1.27066e+08
 matmul snk  time=1.52946e+08
 
 
Nthreads=1, N=16384

 Emax=  1.076e-06
 Nswap=0 cpsec =  417.914 wsec=160.704
 swaprows time=7.40931e+08 ops/cycle=0.181147
 scalerow time=3.47836e+08 ops/cycle=0.385864
 trans rtoc8 time=1.84467e+19 ops/cycle=7.27596e-12
 trans ctor8 time=1.84467e+19 ops/cycle=7.27596e-12
 trans mmul  time=1.35821e+09 ops/cycle=1.48229
 trans nonrec cdec time=1.84467e+19 ops/cycle=7.27596e-12
 trans vvmul time=2.23035e+08 ops/cycle=0.60178
 trans findp time=1.84467e+19 ops/cycle=7.27596e-12
 solve tri u time=1.81516e+08 ops/cycle=9.02621e-05
 solve tri   time=1.84467e+19 ops/cycle=8.88178e-16
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=1.19488e+09 ops/cycle=1.79724
 trans mmul8 time=7.07553e+08 ops/cycle=1.51754
 trans mmul4 time=4.08479e+08 ops/cycle=1.31432
 
 Nt=4
 Nswap=0 cpsec =  420.382 wsec=118.056
 swaprows time=1.84467e+19 ops/cycle=7.27596e-12
 scalerow time=3.48263e+08 ops/cycle=0.385392
 trans rtoc8 time=6.80027e+08 ops/cycle=0.197371
 trans ctor8 time=3.0702e+08 ops/cycle=0.437162
 trans mmul  time=1.37626e+09 ops/cycle=1.46285
 trans nonrec cdec time=6.41575e+08 ops/cycle=0.2092
 trans vvmul time=2.21756e+08 ops/cycle=0.605251
 trans findp time=4.15484e+08 ops/cycle=0.323039
 solve tri u time=1.81714e+08 ops/cycle=9.01635e-05
 solve tri   time=5.17148e+09 ops/cycle=3.16814e-06
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=6.14184e+08 ops/cycle=3.49649
 trans mmul8 time=7.25474e+08 ops/cycle=1.48006
 trans mmul4 time=4.0895e+08 ops/cycle=1.3128
 
Nt=2, N=16384, NB=2048 相当いじったあと

 Emax=  1.471e-07
 Nswap=0 cpsec =  440.624 wsec=222.468
 swaprows time=8.39751e+08 ops/cycle=0.15983
 scalerow time=4.17531e+08 ops/cycle=0.321456
 trans rtoc8 time=1.02016e+09 ops/cycle=0.131565
 trans ctor8 time=5.5054e+08 ops/cycle=0.243793
 trans mmul  time=1.35954e+09 ops/cycle=1.48085
 trans nonrec cdec time=6.41812e+08 ops/cycle=0.209123
 trans vvmul time=2.22362e+08 ops/cycle=0.603601
 trans findp time=4.15344e+08 ops/cycle=0.323148
 solve tri u time=1.41841e+10 ops/cycle=1.1551e-06
 solve tri   time=8.92199e+10 ops/cycle=1.83636e-07
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=1.19747e+09 ops/cycle=1.79335
 trans mmul8 time=7.08126e+08 ops/cycle=1.51631
 trans mmul4 time=4.09517e+08 ops/cycle=1.31099
 DGEMM       time=4.85794e+11 ops/cycle=6.03555
 
再帰的な DTRSM は実装した。

GotoBLAS 2 1.01 に変更

 Enter n, seed, nb:N=20480 Seed=1 NB=512
 read/set mat end
 copy mat end
 Emax=  3.087e-07
 Nswap=0 cpsec =  585.725 wsec=146.726
 swaprows time=1.1845e+09 ops/cycle=0.17705
 scalerow time=6.05163e+08 ops/cycle=0.346543
 trans rtoc8 time=1.3443e+09 ops/cycle=0.156003
 trans ctor8 time=8.0741e+08 ops/cycle=0.259738
 trans mmul  time=2.41859e+09 ops/cycle=1.30065
 trans nonrec cdec time=1.02126e+09 ops/cycle=0.205349
 trans vvmul time=3.63753e+08 ops/cycle=0.576532
 trans findp time=6.51132e+08 ops/cycle=0.322078
 solve tri u time=7.77699e+08 ops/cycle=2.63341e-05
 solve tri   time=1.6045e+10 ops/cycle=1.27641e-06
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=1.94126e+09 ops/cycle=1.72849
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=6.3223e+08 ops/cycle=1.32683
 DGEMM       time=3.67084e+11 ops/cycle=15.6003
 
Enter n, seed, nb:N=16384 Seed=1 NB=2048

 read/set mat end
 copy mat end
 Emax=  3.090e-08
 Nswap=0 cpsec =  329.265 wsec=82.7602
 swaprows time=8.37005e+08 ops/cycle=0.160355
 scalerow time=4.17547e+08 ops/cycle=0.321443
 trans rtoc8 time=7.71399e+08 ops/cycle=0.173993
 trans ctor8 time=5.27207e+08 ops/cycle=0.254582
 trans mmul  time=1.59757e+09 ops/cycle=1.2602
 trans nonrec cdec time=6.5203e+08 ops/cycle=0.205846
 trans vvmul time=2.29239e+08 ops/cycle=0.585492
 trans findp time=4.16039e+08 ops/cycle=0.322609
 solve tri u time=5.49025e+09 ops/cycle=2.9842e-06
 solve tri   time=3.42907e+10 ops/cycle=4.77797e-07
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=1.23869e+09 ops/cycle=1.73368
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=4.10097e+08 ops/cycle=1.30913
 DGEMM       time=1.76038e+11 ops/cycle=16.6556
 
swaprows and scalerow OMP化

 <cfcafs03:/home/makino/src/linsol>
 Enter n, seed, nb:N=16384 Seed=1 NB=128
 read/set mat end
 copy mat end
 Emax=  4.767e-09
 Nswap=0 cpsec =  306.351 wsec=76.7172
 swaprows time=8.07664e+08 ops/cycle=0.16618
 scalerow time=3.58689e+08 ops/cycle=0.37419
 trans rtoc8 time=7.92825e+08 ops/cycle=0.16929
 trans ctor8 time=5.24754e+08 ops/cycle=0.255773
 trans mmul  time=1.59751e+09 ops/cycle=1.26025
 trans nonrec cdec time=6.50838e+08 ops/cycle=0.206223
 trans vvmul time=2.30045e+08 ops/cycle=0.583441
 trans findp time=4.15841e+08 ops/cycle=0.322762
 solve tri u time=1.21474e+08 ops/cycle=0.000134877
 solve tri   time=3.71787e+09 ops/cycle=4.40683e-06
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=1.25042e+09 ops/cycle=1.71741
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=4.09244e+08 ops/cycle=1.31186
 DGEMM       time=1.95923e+11 ops/cycle=14.9652
 
Core i7 に最適化された GotoBLAS は結構速いので、色々普通にやってあまり 問題ない。

 Enter n, seed, nb:N=20480 Seed=1 NB=2048
 read/set mat end
 copy mat end
 Emax=  6.227e-08
 Nswap=0 cpsec =  623.027 wsec=156.475
 swaprows time=1.34135e+09 ops/cycle=0.156346
 scalerow time=6.46645e+08 ops/cycle=0.324313
 trans rtoc8 time=1.26259e+09 ops/cycle=0.1661
 trans ctor8 time=7.75399e+08 ops/cycle=0.270461
 trans mmul  time=2.43097e+09 ops/cycle=1.29402
 trans nonrec cdec time=9.99599e+08 ops/cycle=0.209799
 trans vvmul time=3.49642e+08 ops/cycle=0.5998
 trans findp time=6.44818e+08 ops/cycle=0.325232
 solve tri u time=6.86921e+09 ops/cycle=2.98142e-06
 solve tri   time=5.42023e+10 ops/cycle=3.77844e-07
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=2.04036e+09 ops/cycle=1.64453
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=6.36945e+08 ops/cycle=1.31701
 DGEMM       time=3.48804e+11 ops/cycle=16.4179
20k の時:

 swap 0.5sec
 scale 0.24sec
 trans (r->c) 0.47sec
 trans (c->r) 0.29sec
 large DGEMM  131.2 sec
 
DGEMM の時間の測定のしかたが間違っていたので修正。 cblas_dgemm を全部 合計にする。

 Enter n, seed, nb:N=16384 Seed=1 NB=256
 read/set mat end
 copy mat end
 Emax=  3.875e-09
 Nswap=0 cpsec =  300.335 wsec=75.2046
 swaprows time=8.10285e+08 ops/cycle=0.165643
 scalerow time=3.71966e+08 ops/cycle=0.360833
 trans rtoc8 time=7.6822e+08 ops/cycle=0.174713
 trans ctor8 time=5.02146e+08 ops/cycle=0.267288
 trans mmul  time=1.56957e+09 ops/cycle=1.28269
 trans nonrec cdec time=6.43971e+08 ops/cycle=0.208422
 trans vvmul time=2.26705e+08 ops/cycle=0.592036
 trans findp time=4.13498e+08 ops/cycle=0.324591
 solve tri u time=2.58505e+08 ops/cycle=6.33798e-05
 solve tri   time=5.89804e+09 ops/cycle=2.77787e-06
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=1.24804e+09 ops/cycle=1.72069
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=4.10276e+08 ops/cycle=1.30856
 DGEMM       time=1.89628e+11 ops/cycle=15.462
DGEMM の分が71.2 秒なのでそれ以外が4秒

 swap 0.3sec
 scale 0.15sec
 trans (r->c) 0.3sec
 trans (c->r) 0.2sec
 mmul in trans 0.6sec
 nb=2          0.3sec
 small mmul r  0.5sec

 
 Enter n, seed, nb:N=20480 Seed=1 NB=256
 read/set mat end
 copy mat end
 Emax=  1.686e-07
 Nswap=0 cpsec =  582.388 wsec=145.805
 swaprows time=1.25323e+09 ops/cycle=0.167339
 scalerow time=5.8671e+08 ops/cycle=0.357443
 trans rtoc8 time=1.2708e+09 ops/cycle=0.165026
 trans ctor8 time=7.75856e+08 ops/cycle=0.270302
 trans mmul  time=2.42934e+09 ops/cycle=1.29489
 trans nonrec cdec time=1.00069e+09 ops/cycle=0.20957
 trans vvmul time=3.49502e+08 ops/cycle=0.60004
 trans findp time=6.44612e+08 ops/cycle=0.325335
 solve tri u time=3.28611e+08 ops/cycle=6.23229e-05
 solve tri   time=9.28552e+09 ops/cycle=2.20559e-06
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=2.02897e+09 ops/cycle=1.65377
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=6.36088e+08 ops/cycle=1.31878
 DGEMM       time=3.71893e+11 ops/cycle=15.3986
 
TIMETEST を外しても合計時間は殆ど (0.1秒も)変わらない。

まだ間違っていたのでもう一度修正。

 Enter n, seed, nb:N=16384 Seed=1 NB=256
 read/set mat end
 copy mat end
 Emax=  3.875e-09
 Nswap=0 cpsec =  300.427 wsec=75.2283
 swaprows time=8.10422e+08 ops/cycle=0.165615
 scalerow time=3.75172e+08 ops/cycle=0.35775
 trans rtoc8 time=7.66713e+08 ops/cycle=0.175056
 trans ctor8 time=5.03349e+08 ops/cycle=0.266649
 trans mmul  time=1.57006e+09 ops/cycle=1.28229
 trans nonrec cdec time=6.97766e+08 ops/cycle=0.192354
 trans vvmul time=2.26423e+08 ops/cycle=0.592773
 trans findp time=4.67333e+08 ops/cycle=0.287199
 solve tri u time=2.66089e+08 ops/cycle=6.15733e-05
 solve tri   time=5.89679e+09 ops/cycle=2.77846e-06
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=1.24246e+09 ops/cycle=1.72842
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=4.10345e+08 ops/cycle=1.30834
 DGEMM       time=1.93737e+11 ops/cycle=15.1341
 
DGEMM 72.6 sec.

残りは 2.5 sec なので、説明はできている。

 Enter n, seed, nb:N=32768 Seed=1 NB=2048
 a, awork offset size= 7f223c800000 7f243d000000 200800000 200800000 200800000
 size of size_t and off_t long= 8 8 8
 read/set mat end
 copy mat end
 Emax=  4.229e-07
 Nswap=0 cpsec =  2441.84 wsec=612.648
 swaprows time=3.30799e+09 ops/cycle=0.162295
 scalerow time=1.60583e+09 ops/cycle=0.334325
 trans rtoc8 time=4.15807e+09 ops/cycle=0.129115
 trans ctor8 time=2.23611e+09 ops/cycle=0.240091
 trans mmul  time=6.2654e+09 ops/cycle=1.28532
 trans nonrec cdec time=2.62081e+09 ops/cycle=0.204849
 trans vvmul time=9.41764e+08 ops/cycle=0.57007
 trans findp time=1.66965e+09 ops/cycle=0.321548
 solve tri u time=1.10225e+10 ops/cycle=2.97282e-06
 solve tri   time=1.42092e+11 ops/cycle=2.30611e-07
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=5.46641e+09 ops/cycle=1.5714
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=1.62096e+09 ops/cycle=1.32482
 DGEMM       time=1.60535e+12 ops/cycle=14.6113
 
DGEMM 603.4 sec 残り 9 sec

34 K なら 10秒ちょっと。

34K の時のパネル分解の計算量。 N, K で考える。行列要素数は で、要素当りの計算量は基本的に内積演算の平均の長さが なので、

42.56Gflops で 29 秒。

 Enter n, seed, nb:N=34816 Seed=1 NB=2048
 a, awork offset size= 7fb84f200000 7fba91a00000 242800000 242800000 242800000
 size of size_t and off_t long= 8 8 8
 read/set mat end
 copy mat end
 Emax=  5.044e-07
 Nswap=0 cpsec =  2912.46 wsec=730.613
 swaprows time=3.72683e+09 ops/cycle=0.162625
 scalerow time=1.96941e+09 ops/cycle=0.307745
 trans rtoc8 time=4.34275e+09 ops/cycle=0.139561
 trans ctor8 time=2.38512e+09 ops/cycle=0.254108
 trans mmul  time=6.94446e+09 ops/cycle=1.30912
 trans nonrec cdec time=2.903e+09 ops/cycle=0.208776
 trans vvmul time=1.02328e+09 ops/cycle=0.592288
 trans findp time=1.86832e+09 ops/cycle=0.324396
 solve tri u time=1.16829e+10 ops/cycle=2.98007e-06
 solve tri   time=1.60738e+11 ops/cycle=2.16601e-07
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=6.39244e+09 ops/cycle=1.51698
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=1.82715e+09 ops/cycle=1.32683
 DGEMM       time=1.91709e+12 ops/cycle=14.6758
 
どれだけ短くできるか、を考える。

   計算量の半分: K=1024  600Gflops 14倍
   計算量の 1/4 : K=512  300       7
   計算量の 1/8 : K=256  150       3.5
   計算量の 1/16 : K=128 75        1.75
 
 合計は: 0.21 
 
 Enter n, seed, nb:N=34816 Seed=1 NB=2048
 a, awork offset size= 7fae21c00000 7fb064400000 242800000 242800000 242800000
 size of size_t and off_t long= 8 8 8
 read/set mat end
 copy mat end
 Emax=  5.044e-07
 Nswap=0 cpsec =  2910.57 wsec=730.139
 swaprows time=3.72784e+09 ops/cycle=0.162581
 scalerow time=1.79725e+09 ops/cycle=0.337224
 trans rtoc8 time=4.34249e+09 ops/cycle=0.139569
 trans ctor8 time=2.40224e+09 ops/cycle=0.252296
 trans mmul  time=5.83755e+09 ops/cycle=1.55736
 trans nonrec cdec time=2.9062e+09 ops/cycle=0.208546
 trans vvmul time=1.02325e+09 ops/cycle=0.592304
 trans findp time=1.86805e+09 ops/cycle=0.324444
 solve tri u time=1.16613e+10 ops/cycle=2.9856e-06
 solve tri   time=1.6063e+11 ops/cycle=2.16747e-07
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=6.36856e+09 ops/cycle=1.52267
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=1.82159e+09 ops/cycle=1.33087
 DGEMM       time=1.91704e+12 ops/cycle=14.6762
 
NB=256 では

 Enter n, seed, nb:N=34816 Seed=1 NB=256
 a, awork offset size= 7fad35600000 7faf77e00000 242800000 242800000 242800000
 size of size_t and off_t long= 8 8 8
 read/set mat end
 copy mat end
 Emax=  9.244e-08
 Nswap=0 cpsec =  2797.93 wsec=700.362
 swaprows time=3.57559e+09 ops/cycle=0.169504
 scalerow time=1.71234e+09 ops/cycle=0.353947
 trans rtoc8 time=4.35866e+09 ops/cycle=0.139051
 trans ctor8 time=2.40053e+09 ops/cycle=0.252476
 trans mmul  time=5.83701e+09 ops/cycle=1.5575
 trans nonrec cdec time=2.90349e+09 ops/cycle=0.208741
 trans vvmul time=1.02339e+09 ops/cycle=0.592227
 trans findp time=1.8687e+09 ops/cycle=0.324331
 solve tri u time=5.74246e+08 ops/cycle=6.06291e-05
 solve tri   time=2.66881e+10 ops/cycle=1.30455e-06
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=6.3678e+09 ops/cycle=1.52286
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=1.8209e+09 ops/cycle=1.33138
 DGEMM       time=1.83881e+12 ops/cycle=15.3006
 
 swaprows time=3.57559e+09 ops/cycle=0.169504
 scalerow time=1.71234e+09 ops/cycle=0.353947
 trans rtoc8 time=4.35866e+09 ops/cycle=0.139051
 trans ctor8 time=2.40053e+09 ops/cycle=0.252476
 trans mmul  time=5.83701e+09 ops/cycle=1.5575
 trans nonrec cdec time=2.90349e+09 ops/cycle=0.208741
 trans vvmul time=1.02339e+09 ops/cycle=0.592227
 trans findp time=1.8687e+09 ops/cycle=0.324331
 matmul snk  time=6.3678e+09 ops/cycle=1.52286
 trans mmul4 time=1.8209e+09 ops/cycle=1.33138
 
このへんの細かいところを全部もうちょっとつめたい、というのが 残ったチューニングになる。

行列データ: 9.7GB (not GiB)。交換は read+write 18GB, scale 9.7GB、 trans rtoc, ctor それぞれ 9.7GB

trans mmul: K=16 の下。演算数としては、要素当り16演算なので、9.7G 演算、 時間2秒なので 4Gflops 程度しかでていない。メモリアクセスは、 K= 2, 4, 8 で3回、それぞれ行の下半分を半分読んで半分書く。なので、 15GB。2秒なので、 7.5GB/s。ここはもうちょっと速くならないか、という気 がする。そもそも、データサイズとして 34k の場合でも16行、4MB なので、 L3 キャッシュに全部はいっているんだと思うんだが、、、

あと、見た目でできそうなチューニング箇所は以下の通り。

現状の転置方式は、行列消去が進んでも n x 16 の配列にコピーする、という 形、つまり、上のほうに空きがある形にコピーするようになっている。これは コードが簡単だが、明らかに効率は悪い。配列のディメンションを変えて、 (n-i) x 16 の領域を連続アクセスできるようにすればいくらかは速くなるはず。

あと、転置前の nx16 の行列乗算がちょっとありえないほど遅い。 32k で、転置とこの乗算で合わせて4秒程度かかっていて、時間の大半である。 ここでは、実は乗算の結果を一旦メモリにストアしてから転置しているが、こ れは本当は無駄なので、乗算した結果を転置しながら直接ストアすれば ここのメモリアクセスを 60% にできるだけでなく、不連続ストアを減らすこ ともできる。

が、それ以前にここまでを GotoBLASにすると、

 Enter n, seed, nb:N=8192 Seed=1 NB=128
 read/set mat end
 copy mat end
 Emax=  6.833e-10
 Nswap=0 cpsec =  39.4825 wsec=9.88793 37.0658 Gflops
 swaprows time=2.04298e+08 ops/cycle=0.164242
 scalerow time=7.06527e+07 ops/cycle=0.474921
 trans rtoc8 time=1.43615e+08 ops/cycle=0.233642
 trans ctor8 time=1.37003e+08 ops/cycle=0.244917
 trans mmul  time=2.94734e+08 ops/cycle=1.7077
 trans nonrec cdec time=1.69648e+08 ops/cycle=0.197789
 trans vvmul time=5.64071e+07 ops/cycle=0.594862
 trans findp time=1.13391e+08 ops/cycle=0.295919
 solve tri u time=5.94506e+07 ops/cycle=0.000137795
 solve tri   time=9.13853e+08 ops/cycle=9.39969
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=54240 ops/cycle=9898.06
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=8.26731e+07 ops/cycle=1.62348
 trans mmul2 time=4.56105e+07 ops/cycle=1.47135
 DGEMM       time=2.50872e+10 ops/cycle=14.9516
変更前:

 N=8192 Seed=1 NB=128
 Emax=  1.902e-09
 Nswap=0 cpsec =  39.7945 wsec=9.97176 36.7542 Gflops
 swaprows time=2.03733e+08 ops/cycle=0.164698
 scalerow time=7.06972e+07 ops/cycle=0.474622
 trans rtoc8 time=1.4062e+08 ops/cycle=0.238617
 trans ctor8 time=1.36213e+08 ops/cycle=0.246337
 trans mmul  time=2.95006e+08 ops/cycle=1.70612
 trans nonrec cdec time=1.6697e+08 ops/cycle=0.20096
 trans vvmul time=5.64536e+07 ops/cycle=0.594372
 trans findp time=1.10669e+08 ops/cycle=0.303197
 solve tri u time=5.95494e+07 ops/cycle=0.000137566
 solve tri   time=9.09796e+08 ops/cycle=9.44161
 matmul nk8  time=0 ops/cycle=inf
 matmul snk  time=3.05898e+08 ops/cycle=1.75506
 trans mmul8 time=0 ops/cycle=inf
 trans mmul4 time=8.29545e+07 ops/cycle=1.61797
 trans mmul2 time=4.55855e+07 ops/cycle=1.47215
 DGEMM       time=2.50133e+10 ops/cycle=14.9958
元々は nx16 に3.05898e+08 サイクル。DGEMM の差はずっと小さいので、 これはこっちを使えばOKと思われる。

 DGEMM       time=2.50872e+10 ops/cycle=14.9516
 DGEMM       time=2.50133e+10 ops/cycle=14.9958

 HPL の速度は

 ============================================================================
 T/V                N    NB     P     Q               Time             Gflops
 ----------------------------------------------------------------------------
 WR00L2C2        4096   128     1     1               1.36          3.362e+01
 WR00L2C4        4096   128     1     1               1.35          3.401e+01
 WR00L2C2        8192   128     1     1              10.18          3.601e+01
 WR00L2C4        8192   128     1     1              10.10          3.631e+01
 ============================================================================
なので、 N=8192 の場合に、計算量が 1.5% 程度増加している(dtrsm の処理 のため)が時間は 2% 程度減少していることがわかる。
Previous ToC Next