C#(Mono)托管与非托管阵列:基准偏好托管?

C#(Mono)托管与非托管阵列:基准偏好托管?,c#,arrays,mono,benchmarking,unsafe,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;

令人惊讶的是,对以下各项进行基准测试可以为受管阵列提供更好的结果(速度快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 );
}
unsafe void Bench()
{
//当地人
int i,j;
常量int bufSize=1024*1024;
常数整数=1000;
常数浮点增益=1.6745f;
浮动[]管理缓冲区;
IntPtr-ptr;
浮动*非托管缓冲区;
秒表;
//分配
managedBuffer=newfloat[bufSize];
对于(i=0;i
我正在为一个性能非常关键的音频应用程序试验不安全的代码。我希望提高性能,减少/消除垃圾收集


任何见解,谢谢

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

如果您使用来观察IL代码,则区别在于(版本、默认设置、我的电脑:Windows 7 64):

我不知道每个IL指令对应多少机器代码,但这可能是优化问题(请参阅非托管缓冲区情况下计算索引所需的工作量)


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

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


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

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

非托管的

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 
管理的

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 

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

在对非托管数组进行迭代时,只是尝试了指针算术而不是索引器,情况更糟……基准测试是一门棘手的艺术,容易出错,机器代码中的微小差异也很明显。小于15%的差异不具有统计相关性。至少调用此代码10次,减少数量,这样您就不必等待太久。注意结果中的显著变化。当我在.NET上尝试时,代码以相同的速度运行。应该如此。