对以下内容进行基准测试令人惊讶地为托管阵列提供了更好的结果(速度提高了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 );
}
我正在尝试一种性能非常关键的音频应用程序的不安全代码。我希望提高性能,减少/消除垃圾收集。
任何见解都表示赞赏!
答案 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
显然,代码越大,执行速度越慢......