C#(Mono)托管与非托管阵列:基准优惠管理?

时间:2015-02-12 13:29:58

标签: c# arrays mono benchmarking unsafe

对以下内容进行基准测试令人惊讶地为托管阵列提供了更好的结果(速度提高了10%,始终如一)。我在Unity测试,所以它可能与Mono有关吗?

unsafe void Bench()
{
    //Locals
    int i, j;
    const int   bufSize         = 1024 * 1024;
    const int   numIterations   = 1000;
    const float gain            = 1.6745f;

    float[] managedBuffer;

    IntPtr  ptr;
    float * unmanagedBuffer;

    Stopwatch stopwatch; 

    // Allocations
    managedBuffer = new float[ bufSize ];
    for( i = 0; i < bufSize; i++ )
    {
        managedBuffer[ i ] = UnityEngine.Random.value;
    }

    ptr             = Marshal.AllocHGlobal( bufSize * sizeof( float ) );
    unmanagedBuffer = ( float * )ptr.ToPointer();

    Marshal.Copy( managedBuffer, 0, ptr, bufSize );

    stopwatch = new Stopwatch();
    stopwatch.Start();

    // Unmanaged array iterations
    for( i = 0; i < numIterations; i++ )
    {
        for( j = 0; j < bufSize; j++ )
        {
            unmanagedBuffer[ j ] *= gain;
        }
    }

    UnityEngine.Debug.Log( stopwatch.ElapsedMilliseconds );

    stopwatch.Reset();
    stopwatch.Start();

    // Managed array iterations
    for( i = 0; i < numIterations; i++ )
    {
        for( j = 0; j < bufSize; j++ )
        {
            managedBuffer[ j ] *= gain;
        }
    }

    UnityEngine.Debug.Log( stopwatch.ElapsedMilliseconds );

    Marshal.FreeHGlobal( ptr );
}

我正在尝试一种性能非常关键的音频应用程序的不安全代码。我希望提高性能,减少/消除垃圾收集。

任何见解都表示赞赏!

2 个答案:

答案 0 :(得分:0)

不是一个真正的答案,但需要更多的空间而不是评论。

如果您使用ILSpy来观察IL代码,那么差异是(发布,默认设置,我的电脑:Windows 7 64):

        // unmanaged        
        IL_005a: ldloc.s unmanagedBuffer
        IL_005c: ldloc.1
        IL_005d: conv.i
        IL_005e: ldc.i4.4
        IL_005f: mul
        IL_0060: add
        IL_0061: dup
        IL_0062: ldind.r4
        IL_0063: ldc.r4 1.6745
        IL_0068: mul
        IL_0069: stind.r4
        IL_006a: ldloc.1
        IL_006b: ldc.i4.1
        IL_006c: add
        IL_006d: stloc.1

        // managed
        IL_00a4: ldloc.2
        IL_00a5: ldloc.1
        IL_00a6: ldelema [mscorlib]System.Single
        IL_00ab: dup
        IL_00ac: ldobj [mscorlib]System.Single
        IL_00b1: ldc.r4 1.6745
        IL_00b6: mul
        IL_00b7: stobj [mscorlib]System.Single
        IL_00bc: ldloc.1
        IL_00bd: ldc.i4.1
        IL_00be: add
        IL_00bf: stloc.1

我不知道每个IL指令对应了多少机器代码,但它可能是优化问题(看看在非托管缓冲区的情况下计算索引需要多少工作)。


我注意到迭代次数和时间之间的非线性相关性:

第一列是numIterations,第二列是未管理时间(ms),最后一列是管理时间(ms)。

直到170它是线性的,然后开始发生一些事情(忽略增量,屏幕上是10,我尝试5它也很好,直到170)。这让我很烦恼,我真的想在这里得到真正的答案。

答案 1 :(得分:0)

不是答案,但我需要空间。 使用C#nad VS13我看到了不同的装配用于乘法。

<强> UNMANAGED

00007FFC013555D9  movsxd      rcx,dword ptr [rbp+0D8h]  
00007FFC013555E0  mov         rax,qword ptr [rbp+0C0h]  
00007FFC013555E7  lea         rax,[rax+rcx*4]  
00007FFC013555EB  mov         qword ptr [rbp+50h],rax  
00007FFC013555EF  mov         rax,qword ptr [rbp+50h]  
00007FFC013555F3  movss       xmm0,dword ptr [7FFC013558A0h]  
00007FFC013555FB  mulss       xmm0,dword ptr [rax]  
00007FFC013555FF  mov         rax,qword ptr [rbp+50h]  
00007FFC01355603  movss       dword ptr [rax],xmm0 

<强>托管

00007FFC01355722  movsxd      rcx,dword ptr [rbp+0D8h]  
00007FFC01355729  mov         rax,qword ptr [rbp+0D0h]  
00007FFC01355730  mov         rax,qword ptr [rax+8]  
00007FFC01355734  mov         qword ptr [rbp+78h],rcx  
00007FFC01355738  cmp         qword ptr [rbp+78h],rax  
00007FFC0135573C  jae         00007FFC01355748  
00007FFC0135573E  mov         rax,qword ptr [rbp+78h]  
00007FFC01355742  mov         qword ptr [rbp+78h],rax  
00007FFC01355746  jmp         00007FFC0135574D  
00007FFC01355748  call        00007FFC60E86590  
00007FFC0135574D  mov         rcx,qword ptr [rbp+0D0h]  
00007FFC01355754  mov         rax,qword ptr [rbp+78h]  
00007FFC01355758  lea         rax,[rcx+rax*4+10h]  
00007FFC0135575D  mov         qword ptr [rbp+80h],rax  
00007FFC01355764  mov         rax,qword ptr [rbp+80h]  
00007FFC0135576B  movss       xmm0,dword ptr [7FFC013558A0h]  
00007FFC01355773  mulss       xmm0,dword ptr [rax]  
00007FFC01355777  mov         rax,qword ptr [rbp+80h]  
00007FFC0135577E  movss       dword ptr [rax],xmm0 

显然,代码越大,执行速度越慢......

相关问题