2011-11-12 10 views
5

C#コードのプロファイリングを行っています。以下の方法は、最も高価なものの一つです。この質問の目的のために、マイクロ最適化を行うことが適切であると仮定します。この方法のパフォーマンスを向上させるアプローチはありますか?C#コードフラグメントの最適化

入力パラメータをpからulong[]に変更すると、マクロが非効率的になります。

static ulong Fetch64(byte[] p, int ofs = 0) 
{ 
    unchecked 
    { 
     ulong result = p[0 + ofs] + 
      ((ulong) p[1 + ofs] << 8) + 
      ((ulong) p[2 + ofs] << 16) + 
      ((ulong) p[3 + ofs] << 24) + 
      ((ulong) p[4 + ofs] << 32) + 
      ((ulong) p[5 + ofs] << 40) + 
      ((ulong) p[6 + ofs] << 48) + 
      ((ulong) p[7 + ofs] << 56); 
     return result; 
    } 
} 
+3

BitConverter.ToInt64のように見えます - http://msdn.microsoft.com/en-us/library/system.bitconverter.toint64.aspx? –

+0

数バイトの読み取りとシフト - それは正直に高価ですか?私はあなたがそれをたくさん呼んでいると確信していますが、コンパイラがそれほど間違っていたら驚いています – Rup

+1

@Alexei ToUInt64、でもそうです。それを代わりに使用することを意味するのであれば、答えとして投稿してください。 (または、エリックでもBitConverterを最適化したいのですか?) – Rup

答えて

5

なぜBitConverterを使用しないのですか?私はマイクロソフトがそのコードを調整するのにある程度時間を費やしてきたと信じなければならない。さらに、エンディアンの問題も扱います。ここで

はBitConverterが長い/ ULONG(ULONGが署名した後、符号なしにそれをキャストとしてそれを変換)に[]バイトを回す方法は次のとおりです。

[SecuritySafeCritical] 
public static unsafe long ToInt64(byte[] value, int startIndex) 
{ 
    if (value == null) 
    { 
    ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); 
    } 
    if (((ulong) startIndex) >= value.Length) 
    { 
    ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); 
    } 
    if (startIndex > (value.Length - 8)) 
    { 
    ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); 
    } 
    fixed (byte* numRef = &(value[startIndex])) 
    { 
    if ((startIndex % 8) == 0) 
    { 
     return *(((long*) numRef)); 
    } 
    if (IsLittleEndian) 
    { 
     int num = ((numRef[0] | (numRef[1] << 8)) | (numRef[2] << 0x10)) | (numRef[3] << 0x18); 
     int num2 = ((numRef[4] | (numRef[5] << 8)) | (numRef[6] << 0x10)) | (numRef[7] << 0x18); 
     return (((long) ((ulong) num)) | (num2 << 0x20)); 
    } 
    int num3 = (((numRef[0] << 0x18) | (numRef[1] << 0x10)) | (numRef[2] << 8)) | numRef[3]; 
    int num4 = (((numRef[4] << 0x18) | (numRef[5] << 0x10)) | (numRef[6] << 8)) | numRef[7]; 
    return (((long) ((ulong) num4)) | (num3 << 0x20)); 
    } 
} 

私が変換1つの32ビット・ワードをやっている疑いがあります時間は32ビットの効率です。 32ビットCPU上の64ビットレジスタは、64ビットintを扱うことはずっと高価です。

64ビットハードウェアをターゲットにしていることが分かっている場合は、1つの方法で変換するのが速くなる可能性があります。参考のため

+0

パフォーマンスを向上させるために安全でないコードを使用していることにも注意してください。 BCLメソッドが最善の策だと思われます。 –

+0

D'oh!今日は別のコンテキストでBitConverterを使用していて、それについては考えていませんでした。ところで、この最適化はCityHashのC#ポート全体のパフォーマンスを30%向上させました(これは現在、移植されたC++バージョンより28%速くなっています)。 –

1

、Microsoftの.NET 4.0 BitConverter.ToInt64http://referencesource.microsoft.com/netframework.aspxでシェアードソースイニシアティブ):

// Converts an array of bytes into a long. 
    [System.Security.SecuritySafeCritical] // auto-generated 
    public static unsafe long ToInt64 (byte[] value, int startIndex) { 
     if(value == null) { 
      ThrowHelper.ThrowArgumentNullException(ExceptionArgument.value); 
     } 

     if ((uint) startIndex >= value.Length) { 
      ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.startIndex, ExceptionResource.ArgumentOutOfRange_Index); 
     } 

     if (startIndex > value.Length -8) { 
      ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_ArrayPlusOffTooSmall); 
     } 

     fixed(byte * pbyte = &value[startIndex]) { 
      if(startIndex % 8 == 0) { // data is aligned 
       return *((long *) pbyte); 
      } 
      else { 
       if(IsLittleEndian) { 
        int i1 = (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24); 
        int i2 = (*(pbyte+4)) | (*(pbyte + 5) << 8) | (*(pbyte + 6) << 16) | (*(pbyte + 7) << 24); 
        return (uint)i1 | ((long)i2 << 32); 
       } 
       else { 
        int i1 = (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3)); 
        int i2 = (*(pbyte+4) << 24) | (*(pbyte + 5) << 16) | (*(pbyte + 6) << 8) | (*(pbyte + 7)); 
        return (uint)i2 | ((long)i1 << 32); 
       } 
      } 
     } 
    } 
1

なぜ危険な行きませんか?

unsafe static ulong Fetch64(byte[] p, int ofs = 0) 
{ 
    fixed (byte* bp = p) 
    { 
    return *((ulong*)(bp + ofs)); 
    } 
}