5

編集

リリースを32ビットでテストしたところ、コードはコンパクトでした。したがって、以下は64ビットの問題です。


VS2012RCを使用しています。デバッグは32ビット、リリースは64ビットです。以下は、コード行のデバッグ後のリリース逆アセンブルです。

         crc = (crc >> 8) ^ crcTable[((val & 0x0000ff00) >> 8) ^ crc & 0xff];
0000006f  mov         eax,dword ptr [ebp-40h] 
00000072  shr         eax,8 
00000075  mov         edx,dword ptr [ebp-3Ch] 
00000078  mov         ecx,0FF00h 
0000007d  and         edx,ecx 
0000007f  shr         edx,8 
00000082  mov         ecx,dword ptr [ebp-40h] 
00000085  mov         ebx,0FFh 
0000008a  and         ecx,ebx 
0000008c  xor         edx,ecx 
0000008e  mov         ecx,dword ptr ds:[03387F38h] 
00000094  cmp         edx,dword ptr [ecx+4] 
00000097  jb          0000009E 
00000099  call        6F54F5EC 
0000009e  xor         eax,dword ptr [ecx+edx*4+8] 
000000a2  mov         dword ptr [ebp-40h],eax
-----------------------------------------------------------------------------
         crc = (crc >> 8) ^ crcTable[((val & 0x0000ff00) >> 8) ^ crc & 0xff];
000000a5  mov         eax,dword ptr [rsp+20h] 
000000a9  shr         eax,8 
000000ac  mov         dword ptr [rsp+38h],eax 
000000b0  mov         rdx,124DEE68h 
000000ba  mov         rdx,qword ptr [rdx] 
000000bd  mov         eax,dword ptr [rsp+00000090h] 
000000c4  and         eax,0FF00h 
000000c9  shr         eax,8 
000000cc  mov         ecx,dword ptr [rsp+20h] 
000000d0  and         ecx,0FFh 
000000d6  xor         eax,ecx 
000000d8  mov         ecx,eax 
000000da  mov         qword ptr [rsp+40h],rdx 
000000df  mov         rax,qword ptr [rsp+40h] 
000000e4  mov         rax,qword ptr [rax+8] 
000000e8  mov         qword ptr [rsp+48h],rcx 
000000ed  cmp         qword ptr [rsp+48h],rax 
000000f2  jae         0000000000000100 
000000f4  mov         rax,qword ptr [rsp+48h] 
000000f9  mov         qword ptr [rsp+48h],rax 
000000fe  jmp         0000000000000105 
00000100  call        000000005FA5D364 
00000105  mov         rax,qword ptr [rsp+40h] 
0000010a  mov         rcx,qword ptr [rsp+48h] 
0000010f  mov         ecx,dword ptr [rax+rcx*4+10h] 
00000113  mov         eax,dword ptr [rsp+38h] 
00000117  xor         eax,ecx 
00000119  mov         dword ptr [rsp+20h],eax

64ビットバージョンのすべての余分なコードは何をしていますか?何のためにテストしていますか?私はこれをベンチマークしていませんが、32ビットコードははるかに高速に実行されるはずです。

編集

機能全体:

public static uint CRC32(uint val)
{
    uint crc = 0xffffffff;

    crc = (crc >> 8) ^ crcTable[(val & 0x000000ff) ^ crc & 0xff];
    crc = (crc >> 8) ^ crcTable[((val & 0x0000ff00) >> 8) ^ crc & 0xff];
    crc = (crc >> 8) ^ crcTable[((val & 0x00ff0000) >> 16) ^ crc & 0xff];
    crc = (crc >> 8) ^ crcTable[(val >> 24) ^ crc & 0xff];

    // flip bits
    return (crc ^ 0xffffffff);
}
4

3 に答える 3

8

アセンブリコードを取得するためにリリースビルドをデバッグしているときに、「逆アセンブリに移動」を使用していると思われます。

[ツール]->[オプション]、[デバッグ]、[一般]に移動し、[モジュールの読み込み時にJIT最適化を抑制する]を無効にした後、エラーチェックなしでx64アセンブリリストを取得しました。

デフォルトでは、リリースモードでも、デバッガーが接続されている場合、コードは最適化されていないようです。コードのベンチマークを行う場合は、この点に注意してください。

PS:ベンチマークでは、x64がx86よりもわずかに速く、10億回の関数呼び出しで4.3秒対4.8秒であることが示されています。

編集:ブレークポイントはまだ機能していました。そうでないと、チェックを外した後、分解を確認できませんでした。上からの例の行は次のようになります(VS 2012 RC):

crc = (crc >> 8) ^ crcTable[((val & 0x0000ff00) >> 8) ^ crc & 0xff];
00000030  mov         r11d,eax 
00000033  shr         r11d,8 
00000037  mov         ecx,edx 
00000039  and         ecx,0FF00h 
0000003f  shr         ecx,8 
00000042  movzx       eax,al 
00000045  xor         ecx,eax 
00000047  mov         eax,ecx 
00000049  cmp         rax,r9 
0000004c  jae         00000000000000A4 
0000004e  mov         eax,dword ptr [r8+rax*4+10h] 
00000053  xor         r11d,eax 
于 2012-09-12T23:22:19.977 に答える
1

コードを見ると、これはcrcTableにアクセスするためのエラーチェックに関連しています。配列を掘り下げ始める前に、限界を超えています。

32ビットコードでは、これが表示されます

0000008e  mov         ecx,dword ptr ds:[03387F38h] 
....
0000009e  xor         eax,dword ptr [ecx+edx*4+8] 

この場合、03387F38hから配列のベースアドレスをロードし、標準のポインタ演算を使用して正しいエントリにアクセスします。

64ビットコードでは、これはより複雑なようです。

000000b0  mov         rdx,124DEE68h 
000000ba  mov         rdx,qword ptr [rdx]

これにより、アドレスがrdxレジスタにロードされます

000000da  mov         qword ptr [rsp+40h],rdx 
...
00000105  mov         rax,qword ptr [rsp+40h] 
0000010a  mov         rcx,qword ptr [rsp+48h] 
0000010f  mov         ecx,dword ptr [rax+rcx*4+10h] 

これにより、アドレスがスタックに移動され、後でそれがraxレジスタに移動され、同じポインタが配列にアクセスするために機能します。

000000daから00000100/00000105までのほとんどすべてが検証コードのようです。残りのコードは、64ビットコードと32ビットコードの間でかなりうまくマッピングされますが、64ビットコードではレジスタの使用率が低くなります。

于 2012-09-12T23:09:56.233 に答える
0

exp ^ crc&0xffはexp ^(cr&0xff)としてコンパイルされます:

00000082  mov         ecx,dword ptr [ebp-40h]  
00000085  mov         ebx,0FFh  
0000008a  and         ecx,ebx  
0000008c  xor         edx,ecx  

式を次のように書く必要がありますか?

(exp ^ crc) & 0xff

64ビットバージョンは、32ビットバージョンよりも明らかに最適化されていません。CLRには、2つの別個のJITコンパイラ実装があります。

また、perfが批判的である場合は、安全でないコードを使用して境界チェックを削除してください。

于 2012-09-12T23:48:25.593 に答える