2011-11-12 4 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를 사용하지 않습니까? 나는 마이크로 소프트가 코드를 튜닝하는 데 시간을 할애했다고 생각한다. 또한 엔디안 문제도 다룹니다.

[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)); 
    } 
} 

난에서 전환이 하나의 32 비트 워드를하고 의심 :

여기 (ULONG 서명으로 변환 한 후 서명에 캐스트) BitConverter 긴/ULONG로 바이트 []를 전환 방법 시간은 32 비트 효율입니다. 32 비트 CPU에 64 비트 레지스터가 없다는 것은 64 비트 int를 다루는 것이 훨씬 더 비쌉니다.

64 비트 하드웨어를 대상으로한다는 것을 알고 있다면 전환 속도가 빨라 졌을 수도 있습니다. 참고로

+0

성능을 향상시키기 위해 안전하지 않은 코드를 사용하고 있습니다. BCL 방법이 최선의 방법이라고 생각됩니다. –

+0

D' oh! 오늘은 다른 맥락에서 BitConverter를 사용했는데 그렇게 생각하지 않았습니다. BTW,이 최적화는 CityHash의 C# 포트의 전반적인 성능을 30 % 향상 시켰습니다 (이제는 C++ 버전보다 28 % 더 빠름). –

1

, 마이크로 소프트의 .NET 4.0 BitConverter.ToInt64 (http://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)); 
    } 
}