real_het

TestFastMove_selfmod.dpr

Sep 12th, 2012
159
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 10.04 KB | None | 0 0
  1. program TestFastMove;
  2. {$APPTYPE CONSOLE}
  3. uses Windows, SysUtils;
  4.  
  5. ////////////////////////////////////////////////////////////////////////////////
  6. ///  FastMove                                                  real_het 2012 ///
  7. ////////////////////////////////////////////////////////////////////////////////
  8.  
  9. {$R-}{$O+}
  10.  
  11. var
  12.   FastMoveCacheLimit:integer=3 shl 20; //should set to half of the cache size of one processor core
  13.  
  14. type
  15.   _TMoveProc=procedure(dst,dstEnd:pointer;dstToSrc:integer);
  16.  
  17. procedure _SSE_Move64_fwd_nocache(dst,dstEnd:pointer;dstToSrc:integer);
  18. asm
  19. @@1:
  20.   movups xmm0,[eax+ecx+$00]
  21.   movups xmm1,[eax+ecx+$10]
  22.   movups xmm2,[eax+ecx+$20]
  23.   movups xmm3,[eax+ecx+$30]
  24.   movntps [eax+$00],xmm0 prefetchnta [eax+ecx+$100]
  25.   movntps [eax+$10],xmm1 add eax,$40
  26.   movntps [eax+$20-$40],xmm2
  27.   movntps [eax+$30-$40],xmm3 cmp eax,edx  jne @@1
  28. end;
  29.  
  30. procedure _SSE_Move64_fwd_cache_selfmod_proto(dst,dstEnd:pointer;dstToSrc:integer);
  31. asm
  32.   test ecx,$F jz @@2
  33.  
  34.   //patch palignr offsets
  35.   push ecx push esi
  36.   call @@getIP @@getIP: pop esi
  37.   and ecx,$F
  38.   mov [esi+$31],cl  mov [esi+$41],cl  mov [esi+$51],cl  mov [esi+$5f],cl
  39.   pop esi pop ecx
  40.  
  41.   and ecx,not $f //align delta
  42.   movdqa xmm0,[eax+ecx+$00]
  43.   dw $00EB //jmp +0, reset ICache
  44. @@1:
  45.   movdqa xmm1,[eax+ecx+$10]
  46.   movdqa xmm2,[eax+ecx+$20]  movdqa xmm7,xmm1  palignr xmm1,xmm0,1
  47.   movdqa xmm3,[eax+ecx+$30]  movdqa xmm6,xmm2  palignr xmm2,xmm7,2
  48.   movdqa xmm4,[eax+ecx+$40]  movdqa xmm5,xmm3  palignr xmm3,xmm6,3
  49.   movdqa [eax+$00    ],xmm1  movdqa xmm0,xmm4  palignr xmm4,xmm5,4
  50.   movdqa [eax+$10    ],xmm2  add eax,$40                       //^ patched
  51.   movdqa [eax+$20-$40],xmm3  prefetchnta [eax+ecx+$100]
  52.   movdqa [eax+$30-$40],xmm4  cmp eax,edx  jne @@1
  53.   ret
  54. @@2:
  55.   movaps xmm0,[eax+ecx+$00]
  56.   movaps xmm1,[eax+ecx+$10]
  57.   movaps xmm2,[eax+ecx+$20]
  58.   movaps xmm3,[eax+ecx+$30]
  59.   movaps [eax+$00],xmm0 prefetchnta [eax+ecx+$100]
  60.   movaps [eax+$10],xmm1 add eax,$40
  61.   movaps [eax+$20-$40],xmm2
  62.   movaps [eax+$30-$40],xmm3 cmp eax,edx  jne @@2
  63.   ret;nop;nop;nop //end of proc signal
  64. end;
  65. var
  66.   _SSE_Move64_fwd_cache_selfmod_storage:ansistring;
  67.   _SSE_Move64_fwd_cache_selfmod:_TMoveProc;
  68.  
  69. procedure _SSE_Move64_rev_nocache(dst,dstEnd:pointer;dstToSrc:integer);
  70. asm
  71.   xchg edx,eax sub eax,$40 sub edx,$40 //mirror buffer start/end positions
  72. @@1:
  73.   movups xmm0,[eax+ecx+$00]
  74.   movups xmm1,[eax+ecx+$10]
  75.   movups xmm2,[eax+ecx+$20]
  76.   movups xmm3,[eax+ecx+$30]
  77.   movntps [eax+$00],xmm0 prefetchnta [eax+ecx-$100]
  78.   movntps [eax+$10],xmm1 sub eax,$40
  79.   movntps [eax+$20+$40],xmm2
  80.   movntps [eax+$30+$40],xmm3 cmp eax,edx  jne @@1
  81. end;
  82.  
  83. procedure _SSE_Move64_rev_cache_selfmod_proto(dst,dstEnd:pointer;dstToSrc:integer);
  84. asm
  85.   xchg edx,eax sub eax,$40 sub edx,$40 //mirror buffer start/end positions
  86.   test ecx,$F jz @@2 //aligned?
  87.  
  88.   //patch palignr offsets
  89.   push ecx push esi
  90.   call @@getIP @@getIP: pop esi
  91.   and ecx,$F
  92.   mov [esi-$91+$C2],cl  mov [esi-$91+$CD],cl  mov [esi-$91+$D9],cl  mov [esi-$91+$E4],cl
  93.   pop esi pop ecx
  94.  
  95.   and ecx,not $f; add ecx,$10 //align delta
  96.  
  97.   movdqa xmm0,[eax+ecx+$30]
  98.   dw $00EB //jmp +0, reset ICache
  99. @@1:
  100.   movdqa xmm1,[eax+ecx+$20]
  101.   movdqa xmm2,[eax+ecx+$10]  palignr xmm0,xmm1,1
  102.   movdqa xmm3,[eax+ecx+$00]  palignr xmm1,xmm2,2
  103.   movdqa xmm4,[eax+ecx-$10]  palignr xmm2,xmm3,3
  104.   movdqa [eax+$30    ],xmm0  palignr xmm3,xmm4,4  movdqa xmm0,xmm4
  105.   movdqa [eax+$20    ],xmm1  sub eax,$40     //^ patched
  106.   movdqa [eax+$10+$40],xmm2  prefetchnta [eax+ecx-$100]
  107.   movdqa [eax+$00+$40],xmm3  cmp eax,edx  jne @@1
  108.   ret
  109. @@2:
  110.   movaps xmm0,[eax+ecx+$00]
  111.   movaps xmm1,[eax+ecx+$10]
  112.   movaps xmm2,[eax+ecx+$20]
  113.   movaps xmm3,[eax+ecx+$30]
  114.   movaps [eax+$00],xmm0 prefetchnta [eax+ecx-$100]
  115.   movaps [eax+$10],xmm1 sub eax,$40
  116.   movaps [eax+$20+$40],xmm2
  117.   movaps [eax+$30+$40],xmm3 cmp eax,edx  jne @@2
  118.   ret;nop;nop;nop //end of proc signal
  119. end;
  120. var
  121.   _SSE_Move64_rev_cache_selfmod_storage:ansistring;
  122.   _SSE_Move64_rev_cache_selfmod:_TMoveProc;
  123.  
  124. procedure InitFastMove;
  125.  
  126.   procedure copyToDs(const src:pointer;var dst:_TMoveProc;var storage:ansistring;align:integer);
  127.   var siz:integer;
  128.   begin
  129.     siz:=0;repeat inc(siz);until pcardinal(integer(src)+siz)^=$C3909090;inc(siz);
  130.     SetLength(storage,siz);
  131.     move(src^,storage[1],siz+1);
  132.     dst:=pointer(storage);
  133.   end;
  134.  
  135. begin
  136.   copyToDs(@_SSE_Move64_fwd_cache_selfmod_proto, _SSE_Move64_fwd_cache_selfmod, _SSE_Move64_fwd_cache_selfmod_storage,1);
  137.   copyToDs(@_SSE_Move64_rev_cache_selfmod_proto, _SSE_Move64_rev_cache_selfmod, _SSE_Move64_rev_cache_selfmod_storage,10);
  138. end;
  139.  
  140. procedure FastMove(const src;var dst;size:integer);
  141. const AlignPosMask=16-1;
  142.       AlignSizeMask=64-1;
  143.  
  144. var delta:integer;
  145.     pDst,pDstInner,pDstEnd,pDstInnerEnd:integer;
  146.     InnerSize:integer;
  147.     reverse,nocache,unaligned:boolean;
  148. begin
  149.   if size<(AlignSizeMask+1)*2 then begin system.Move(src,dst,size);exit end;
  150.   //check params
  151.   if(@src=nil)or(@dst=nil)then exit;
  152.   delta:=integer(@dst)-integer(@src);
  153.   if delta=0 then exit;
  154.   reverse:=(delta>0)and(delta<size);
  155.   delta:=-delta;//Delta: points from dst -> src
  156.   unaligned:=(delta and $f)<>0;
  157.  
  158.   pDst:=integer(@dst);
  159.   pDstEnd:=pDst+size;
  160.   pDstInner:=(pDst+AlignPosMask+16*ord(    reverse and unaligned))and not AlignPosMask;
  161.   InnerSize:=(pDstEnd-pDstInner-16*ord(not reverse and unaligned))and not AlignSizeMask;
  162.   pDstInnerEnd:=pDstInner+InnerSize;
  163.  
  164.   nocache:=Size>FastMoveCacheLimit;
  165.   if reverse then begin
  166.     system.Move(pointer(pDstInnerEnd+delta)^,pointer(pDstInnerEnd)^,pDstEnd-pDstInnerEnd);
  167.     if nocache then _SSE_Move64_rev_nocache(pointer(pDstInner),pointer(pDstInnerEnd),delta)
  168.                else _SSE_Move64_rev_cache_selfmod(pointer(pDstInner),pointer(pDstInnerEnd),delta);
  169.     system.Move(Src,Dst,pDstInner-pDst);
  170.   end else begin
  171.     system.Move(Src,Dst,pDstInner-pDst);
  172.     if nocache then _SSE_Move64_fwd_nocache(pointer(pDstInner),pointer(pDstInnerEnd),delta)
  173.                else _SSE_Move64_fwd_cache_selfmod(pointer(pDstInner),pointer(pDstInnerEnd),delta);
  174.     system.Move(pointer(pDstInnerEnd+delta)^,pointer(pDstInnerEnd)^,pDstEnd-pDstInnerEnd);
  175.   end;
  176. end;
  177.  
  178. ////////////////////////////////////////////////////////////////////////////////
  179. ///  FastMove Functional and performance test                                 ///
  180. ////////////////////////////////////////////////////////////////////////////////
  181.  
  182. function _TestFastMove:ansistring;
  183.  
  184.   procedure log(s:ansistring);begin result:=result+s+#13#10;writeln(s)end;
  185.  
  186. const TestDataSize=256;
  187.       BufSize=128 shl 20;
  188.  
  189. type TByteArray=array[0..BufSize-1]of byte;PByteArray=^TByteArray;
  190.  
  191. var
  192.   _buf:array of byte;
  193.   buf:PByteArray;
  194.   i,j,k:integer;
  195.   pref,psrc,pdst:pointer;
  196.   siz,alignMask,TestDataSizeBig:integer;
  197.   rate:single;
  198.   bestrate:array[0..7]of single;
  199.   t0,t1,tf:int64;
  200.   s:ansistring;
  201. begin
  202.   result:='';randseed:=0;
  203.   //functional test
  204.   alignMask:=$fff;
  205.   setlength(_buf,BufSize+alignMask);
  206.   buf:=pointer((integer(_buf)+alignMask)and not alignMask);
  207.   //buf:4K aligned 256megs
  208.  
  209.   //test small blocks with various src/dst offsets and sizes
  210.   TestDataSizeBig:=FastMoveCacheLimit+1;
  211.   for i:=0 to TestDataSizeBig-1 do buf[i]:=i*251;//reference data
  212.   for i:=-64 to 64 do for j:=-64 to 64 do for k:=0 to TestDataSize do begin
  213.     if k=TestDataSize then
  214.       if((i or j) and $1f)<>0 then continue;//only a few shifts for big blocks
  215.  
  216.     pref:=@buf[0];
  217.     psrc:=@buf[BufSize shr 1+i];
  218.     pdst:=@buf[BufSize shr 1+j];
  219.     if k=TestDataSize then siz:=TestDataSizeBig//big data a vegen
  220.                       else siz:=k;
  221.  
  222.     System.Move(pref^,psrc^,siz);
  223.     FastMove(psrc^,pdst^,siz);
  224.     if not sysutils.CompareMem(pref,pdst,siz)then begin
  225. //      System.Move(pref^,psrc^,siz);FastMove(psrc^,pdst^,siz);}//reproduce last error for debugging
  226.       raise Exception.CreateFmt('TestFastMove() functional test failed %p %p %x',[psrc,pdst,siz]);
  227.     end;
  228.   end;
  229.  
  230.   //Benchmark
  231.   SetPriorityClass(GetCurrentProcess,REALTIME_PRIORITY_CLASS);
  232.  
  233.   log(Format('%10s%8s%8s%7s%8s%8s%7s%8s%8s%7s%8s%8s%7s',
  234.     ['Size','AASys','AAFast','AAGain','UASys','UAFast','UAGain','AUSys','AUFast','AUGain','UUSys','UUFast','UUGain']));
  235.   siz:=1;
  236.   while siz<=bufsize shr 1 do begin
  237.  
  238.     for k:=0 to 1 do //repeat full test
  239.     for i:=0 to high(bestrate) do begin
  240.  
  241.       bestrate[i]:=0;
  242.       for j:=0 to 7 do begin
  243.  
  244.         QueryPerformanceCounter(t0);
  245.  
  246.         case i and 1 of  //bit0:Fast or not
  247.           0:System.Move(buf[0+i shr 1 and 1],buf[bufsize shr 1-(i shr 2 and 1)*3],siz);
  248.           else FastMove(buf[0+i shr 1 and 1],buf[bufsize shr 1-(i shr 2 and 1)*3],siz);
  249.         end;                //Bit1:srcalign  //Bit2:dstAlign
  250.  
  251.         QueryPerformanceCounter(t1);
  252.         QueryPerformanceFrequency(tf);
  253.         rate:=siz*(tf/(t1-t0))/(1024*1024);
  254.         if bestrate[i]<rate then bestrate[i]:=rate;
  255.       end;
  256.     end;
  257.  
  258.     s:=format('%10d',[siz]);
  259.     for i:=0 to high(bestrate)do begin
  260.       s:=s+format('%8.0f',[bestRate[i]]);
  261.       if(i and 1)<>0 then
  262.         s:=s+format('%7.3f',[bestRate[i]/bestRate[i-1]]);
  263.     end;
  264.     log(s);
  265.  
  266.     if siz<4 then inc(siz)
  267.              else if(siz and(siz shr 1))<>0 then siz:=siz*4 div 3
  268.                                             else siz:=siz*3 div 2;
  269.   end;
  270. end;
  271.  
  272. const fn='FastMove.txt';
  273. var f:TextFile;
  274. begin
  275.   InitFastMove;
  276.   try
  277.     writeln('SSE FastMove tester.');
  278.     writeln('Running test (this could take 10 or more seconds)...');
  279.     AssignFile(f,fn);rewrite(f);Write(f,_TestFastMove);closefile(f);
  280.  
  281.     writeln('All speeds in MByte/sec, AA means 16byte aligned source and destination memory locations, U means unaliged src and/or dst.');
  282.     writeln('(Note that the last unaligned results for system.move are significally slower due to the overlapped source and destination buffer. In that case data have to be moved in reverse direction and system.move is not using cache prefetch hints.)');
  283.     writeln('Results saved in ['+fn+']');
  284.     writeln('Press Enter to exit');
  285.     readln;
  286.   except
  287.     on E: Exception do
  288.       Writeln(E.ClassName, ': ', E.Message);
  289.   end;
  290. end.
Advertisement
Add Comment
Please, Sign In to add comment