2016/03/09

どこへ行こうというのかね?

MASM refference
x86/x64 SIMD命令一覧表 (SSE~AVX2)

・・・なんでこんなことを調べているのでしょうか・・・

visual studio expressを2015にしたんですよ。
んで、よくよく調べるとMASMってちゃんとVCに入ってるんですね。

というわけで今までMASM6.15でアセンブルしていたのを最新版でアセンブルしようと・・・したらできなかったという話です。

masm6では問題なくアセンブルできていたのに、その後継の14でできなくなるとは之如何に。

table1 sword 16384, 21407, 16384, 8867
movdqa xmm0,[table1]
というようなコードをアセンブルすると

エラー A2022 instruction operands must be the same size

と言われるという・・・
如何せん僕はwindowsのソフトをほとんど弄ったことがありません。
見たことがある(わかるわけではない)のも386のアセンブラぐらいというロートルなので、そもそもオペコードの意味が分からない・・・
とかいろいろグーグル先生に尋ねた結果、アドレスの書き方が良くない?らしいということが判明。
movdqa xmm0,xmmword ptr[table1]
というようにしたら治りました。

まぁ、あまり原因はわかっていないのですが。
_DATA SEGMENT PARA PUBLIC USE32 'DATA'とか書いてあるのが多少気になりますが、そもそも意味が分からない・・・

という話とは多分関係ないのですが、ひとまず、DGIndexをAVX2を有効にしてコンパイルすると
同一ソースで150MB/s→170MB/s@Haswell4.5GHzぐらいになりました。fpsは調べてませんが。
大体1割早くなった感じでしょうか。
AVX2>AVX=SSE2ぐらいで。

TIVTCも早くなったりするだろうか。
というわけで試してみたけど変わりませんでした。
そして別にコンパイラ最適かじゃなくて、Tdecimateの差分算出を並列処理させれば早くなるんじゃね?とか思って
ベクター化と並列化のメッセージ
を眺めている今日この頃。

深みにはまるだけな気がして仕方がない・・・


そして丸2日かけてコードを最適化した結果、前提条件が間違っていることが判明した。
時間がかかっているのはそこじゃなかった、という・・・

結局のところネックはメモリアクセスっぽいので、演算を並列化しても早くならないっぽい、という・・・多少疑問もありますが。
アクセス順を調整すればあるいは・・・いや、コンパイラ最適化かけてるからどうしようもないのか・・・?
よくわかりません。


後々のために参考になったサイトは下記
プログラミング言語 C の新機能 配列
OpenMPの使い方
ループの独立性

いや、結構頑張ったんですよ?


__asm
 {
  mov y, 2
yloop0:
  mov ecx, y0a
  mov edx, y1a
  cmp ecx, edx
  je xloop_pre0
  mov eax, y
  cmp eax, ecx
  jl xloop_pre0
  cmp eax, edx
  jle end_yloop0
xloop_pre0:
  mov esi, incl
  mov ebx, startx
  mov edi, mapp
  mov edx, mapn
  mov ecx, stopx
xloop0:
  movzx eax, BYTE PTR [edi+ebx]
  shl eax, 3
  add al, BYTE PTR [edx+ebx]
  jnz b10
  add ebx, esi
  cmp ebx, ecx
  jl xloop0
  jmp end_yloop0
b10:
  mov edx, curf
  mov edi, curpf
  movzx ecx, BYTE PTR[edx+ebx]
  movzx esi, BYTE PTR[edi+ebx]
  shl ecx, 2
  mov edx, curnf
  add ecx, esi
  mov edi, prvpf
  movzx esi, BYTE PTR[edx+ebx]
  movzx edx, BYTE PTR[edi+ebx]
  add ecx, esi 
  mov edi, prvnf
  movzx esi, BYTE PTR[edi+ebx]
  add edx, esi
  mov edi, edx
  add edx, edx
  sub edi, ecx
  add edx, edi
  jge b30
  neg edx
b30:
  cmp edx, 23
  jle p30
  test eax, 9
  jz p10
  add accumPc, edx
p10:
  cmp edx, 42
  jle p30
  test eax, 18
  jz p20
  add accumPm, edx
p20:
  test eax, 36
  jz p30
  add accumPml, edx
p30:
  mov edi, nxtpf
  mov esi, nxtnf
  movzx edx, BYTE PTR[edi+ebx]
  movzx edi, BYTE PTR[esi+ebx]
  add edx, edi
  mov esi, edx
  add edx, edx
  sub esi, ecx
  add edx, esi
  jge b20
  neg edx
b20:
  cmp edx, 23
  jle p60
  test eax, 9
  jz p40
  add accumNc, edx
p40:
  cmp edx, 42
  jle p60
  test eax, 18
  jz p50
  add accumNm, edx
p50:
  test eax, 36
  jz p60
  add accumNml, edx
p60:
  test eax, 56
  jz p120
  mov ecx, prvpf
  mov edi, prvppf
  movzx edx, BYTE PTR [ecx+ebx]
  movzx esi, BYTE PTR [edi+ebx]
  shl edx, 2
  mov ecx, prvnf
  add edx, esi
  mov edi, curpf
  movzx esi, BYTE PTR [ecx+ebx]
  movzx ecx, BYTE PTR [edi+ebx]
  add edx, esi
  mov edi, curf
  movzx esi, BYTE PTR [edi+ebx]
  add ecx, esi
  mov edi, ecx
  add ecx, ecx
  add ecx, edi
  sub edx, ecx
  jge b40
  neg edx
b40:
  cmp edx, 23
  jle p90
  test eax, 8
  jz p70
  add accumPc, edx
p70:
  cmp edx, 42
  jle p90
  test eax, 16
  jz p80
  add accumPm, edx
p80:
  test eax, 32
  jz p90
  add accumPml, edx
p90:
  mov edi, nxtpf
  mov esi, nxtppf
  movzx edx, BYTE PTR [edi+ebx]
  movzx edi, BYTE PTR [esi+ebx]
  shl edx, 2
  mov esi, nxtnf
  add edx, edi
  movzx edi, BYTE PTR [esi+ebx]
  add edx, edi
  sub edx, ecx
  jge b50
  neg edx
b50:
  cmp edx, 23
  jle p120
  test eax, 8
  jz p100
  add accumNc, edx
p100:
  cmp edx, 42
  jle p120
  test eax, 16
  jz p110
  add accumNm, edx
p110:
  test eax, 32
  jz p120
  add accumNml, edx
p120:
  mov esi, incl
  mov ecx, stopx
  mov edi, mapp
  add ebx, esi
  mov edx, mapn
  cmp ebx, ecx
  jl xloop0
end_yloop0:
  mov esi, Height
  mov eax, prvf_pitch
  mov ebx, curf_pitch
  mov ecx, nxtf_pitch
  mov edi, map_pitch
  sub esi, 2
  add y, 2
  add mapp, edi
  add prvpf, eax
  add curpf, ebx
  add prvnf, eax
  add curf, ebx
  add nxtpf, ecx
  add prvppf, eax
  add curnf, ebx
  add nxtnf, ecx
  add mapn, edi
  add nxtppf, ecx
  cmp y, esi
  jl yloop0
 }
}


というのを
{
int xsize = (stopx - startx) / incl;

//#pragma omp parallel for
//for (y = 2; y < Height - 2; y += 2){}
for (int jj = 1; jj < Height / 2 - 1; ++jj){
 y = jj * 2;// 

 if ((y0a == y1a) || (y < y0a) || (y > y1a)){
  //for (int ebx = startx; ebx < stopx; ebx += incl){}
  for (int ii = 0; ii < xsize; ++ii){

   unsigned char eax;
   int edx,ebx;

   ebx = startx + ii*incl;


   eax = ((*(mapp + ebx)) << 3) + (*(mapn + ebx));

   if (eax != 0){
    edx = (*(prvpf + ebx) + *(prvnf + ebx)) * 3 - ((*(curf + ebx) << 2) + *(curpf + ebx) + *(curnf + ebx));

    if (edx < 0){ edx = -edx; }
    //b30
    if (edx > 23){ //else p30
     if ((eax & 9) != 0){accumPc += edx;}
     //p10
     if (edx > 42){ //else p30

      if ((eax & 18) != 0){accumPm += edx;}
      //p20
      if ((eax & 36) != 0){ accumPml += edx; }
     }
    }
    //p30
    edx = (*(nxtpf + ebx) + *(nxtnf + ebx)) * 3 - ((*(curf + ebx) << 2) + *(curpf + ebx) + *(curnf + ebx));
    if (edx < 0){ edx = -edx; }
    //b20
    if (edx > 23){ //else p60
     if ((eax & 9) != 0){ accumNc += edx; }
     //p40
     if (edx > 42){ //else p60
      if ((eax & 18) != 0){ accumNm += edx; }
      //p50
      if ((eax & 36) != 0){ accumNml += edx; }
     }
    }
    //p60
    if ((eax & 56) != 0){ //else p120
     edx = (*(prvpf + ebx) << 2) + *(prvppf + ebx) + *(prvnf + ebx) - (*(curpf + ebx) + *(curf + ebx)) * 3;
     if (edx < 0){ edx = -edx; }
     //b40
     if (edx > 23){ //else p90
      if ((eax & 8) != 0){ accumPc += edx; }
      //p70
      if (edx > 42){//else p90
       if ((eax & 16) != 0){ accumPm += edx; }
       //p80
       if ((eax & 32) != 0){ accumPml += edx; }
      }
     }
     //p90
     edx = (*(nxtpf + ebx) << 2) + *(nxtppf + ebx) + *(nxtnf + ebx) - (*(curpf + ebx) + *(curf + ebx)) * 3;
     if (edx < 0){ edx = -edx; }
     //b50
     if (edx > 23){ //else p120
      if ((eax & 8) != 0){ accumNc += edx; }
      //p100
      if (edx > 42){ //else p120
       if ((eax & 16) != 0){ accumNm += edx; }
       //p110
       if ((eax & 32) != 0){ accumNml += edx; }
      }
     }
    }
    //p120
   }
  }
 }
 mapp += map_pitch;
 mapn += map_pitch;

 prvpf += prvf_pitch;
 prvnf += prvf_pitch;
 prvppf += prvf_pitch;

 curpf += curf_pitch;
 curnf += curf_pitch;
 curf += curf_pitch;

 nxtpf += nxtf_pitch;
 nxtnf += nxtf_pitch;
 nxtppf += nxtf_pitch;

}
 

というように解読して、その後C言語でパラ化。
・・・まではしたのですが・・・ね。

0 件のコメント:

コメントを投稿