Ste*_*eve 16 .net c c# performance winapi
我们希望将性能关键型应用程序迁移到.Net,并发现c#版本比Win32/C慢30%到100%,具体取决于处理器(移动T7200处理器上的差异更明显).我有一个非常简单的代码示例来演示这一点.为简洁起见,我将只显示C版本 - c#是直接翻译:
#include "stdafx.h"
#include "Windows.h"
int array1[100000];
int array2[100000];
int Test();
int main(int argc, char* argv[])
{
int res = Test();
return 0;
}
int Test()
{
int calc,i,k;
calc = 0;
for (i = 0; i < 50000; i++) array1[i] = i + 2;
for (i = 0; i < 50000; i++) array2[i] = 2 * i - 2;
for (i = 0; i < 50000; i++)
{
for (k = 0; k < 50000; k++)
{
if (array1[i] == array2[k]) calc = calc - array2[i] + array1[k];
else calc = calc + array1[i] - array2[k];
}
}
return calc;
}
Run Code Online (Sandbox Code Playgroud)
如果我们在Win32中查看'else'的反汇编,我们有:
35: else calc = calc + array1[i] - array2[k];
004011A0 jmp Test+0FCh (004011bc)
004011A2 mov eax,dword ptr [ebp-8]
004011A5 mov ecx,dword ptr [ebp-4]
004011A8 add ecx,dword ptr [eax*4+48DA70h]
004011AF mov edx,dword ptr [ebp-0Ch]
004011B2 sub ecx,dword ptr [edx*4+42BFF0h]
004011B9 mov dword ptr [ebp-4],ecx
Run Code Online (Sandbox Code Playgroud)
(这是调试,但请耐心等待)
使用优化的exe上的CLR调试器对优化的c#版本进行反汇编:
else calc = calc + pev_tmp[i] - gat_tmp[k];
000000a7 mov eax,dword ptr [ebp-4]
000000aa mov edx,dword ptr [ebp-8]
000000ad mov ecx,dword ptr [ebp-10h]
000000b0 mov ecx,dword ptr [ecx]
000000b2 cmp edx,dword ptr [ecx+4]
000000b5 jb 000000BC
000000b7 call 792BC16C
000000bc add eax,dword ptr [ecx+edx*4+8]
000000c0 mov edx,dword ptr [ebp-0Ch]
000000c3 mov ecx,dword ptr [ebp-14h]
000000c6 mov ecx,dword ptr [ecx]
000000c8 cmp edx,dword ptr [ecx+4]
000000cb jb 000000D2
000000cd call 792BC16C
000000d2 sub eax,dword ptr [ecx+edx*4+8]
000000d6 mov dword ptr [ebp-4],eax
Run Code Online (Sandbox Code Playgroud)
更多的说明,大概是性能差异的原因.
真的有3个问题:
我是否正在查看2个程序的正确拆卸或误导我的工具?
如果生成的指令数量的差异不是造成差异的原因是什么?
除了将所有性能关键代码保存在本机DLL中之外,我们还能做些什么.
先谢谢史蒂夫
PS我最近收到了一个MS/Intel联合研讨会的邀请,题为"建立性能关键的原生应用程序"嗯...
Ree*_*sey 18
我相信你在这段代码中的主要问题是检查你的数组.
如果你切换到在C#中使用不安全的代码,并使用指针数学,你应该能够实现相同(或可能更快)的代码.
此问题先前已在此问题中详细讨论过.
Mic*_*ael 13
我相信你看到了阵列边界检查的结果.您可以使用不安全的代码来避免边界检查.
我相信JITer可以识别类似for循环的模式,这些循环可以达到array.Length并避免边界检查,但它看起来不像你的代码可以利用它.
正如其他人所说,其中一个方面是边界检查.在阵列访问方面,代码中也存在一些冗余.通过将内部块更改为:我已经设法改善了性能:
int tmp1 = array1[i];
int tmp2 = array2[k];
if (tmp1 == tmp2)
{
calc = calc - array2[i] + array1[k];
}
else
{
calc = calc + tmp1 - tmp2;
}
Run Code Online (Sandbox Code Playgroud)
这一变化将总时间从约8.8秒降至约5秒.