将C#代码反编译为机器指令

5
我正在尝试优化编译器性能。我有一小段代码,只有几个浮点数的乘加运算。该代码在循环中执行数百万次。我尝试使用C++、C#、Java、Perl、Python等语言编译代码,然后对结果进行测量执行时间。
我对C#的性能非常不满意。我的C#代码比等效的C++或Java慢了约60%。我确定实验中一定存在错误。我想反汇编生成的二进制文件以了解原因。
在MSIL代码中是否有此选项?是否可以检查C# JIT编译器的结果并查看机器指令级别的内容(x86指令而不是MSIL指令)?
更新:代码(u、v、g*为双精度浮点数;steps为整数)。
stopwatch.Start();
for (int i = 0; i < steps; i++)
{
    double uu = g11 * u + g12 * v;
    v = g21 * u + g22 * v;
    u = uu;
}
stopwatch.Stop();

你确定你的基准测试允许JIT首先启动吗?也许你应该展示一下。 - user395760
@delnan:您是什么意思?如果JIT没有编译代码,那么代码就无法运行。 - Guffa
@Guffa:问题是是否应该在基准测试中包括JIT时间。 - H H
展示代码并描述运行场景。指定在哪里以及如何测量时间。要知道,你的代码和任何它的被调用者在第一次调用时都会被JIT编译,这当然会引入时间惩罚。之后,除了直接编译成本地二进制代码的等效代码,没有太多原因能解释为什么代码运行速度更慢。是的,正如 @Guffa 所说的那样,他只是比我更快(也更简洁)。 - Paul Michalik
@Guffa,Paul Michalik - 执行时间在3到5秒之间。 - danatel
3个回答

7

在Visual Studio中调试你的代码(但要以发布模式编译),在循环中设置一个断点,当执行停止在断点处时,打开汇编窗口(调试->窗口->汇编)。


3
它可以运行,但您可能需要更好的方法。重写程序以两次运行感兴趣的代码,并在两次运行之间放置一个消息框。当消息框弹出时,将调试器附加到进程上。请记住,“即时编译器知道您是否正在进行调试”。它可以并且确实会在调试器运行时生成不太优化的代码,以使调试体验更好。如果您想知道即时编译器在调试器未运行时正在做什么,请在即时编译器第一次生成代码后再附加调试器。 - Eric Lippert
@Eric Lippert:我知道在调试模式和发布模式下编译有很大的区别,但是是否还取决于是否连接了调试器? - Guffa
1
@Guffa:可能会有。Jitter(即时编译器)知道是否连接了调试器,并可以选择跳过某些难以调试的优化。 - Eric Lippert
在调试版本中(技术上任何没有允许优化的属性的程序集),@danatel 在 JIT 编译时停止寄存器变量,因此以这种方式查看调试版本是愚蠢的,除非你通常运行调试版本! - ShuggyCoUk
@ShuggyCoUk - 或许我表达不够准确,我指的是 Guffa 方法中的 "调试模式"——附加了调试器的发布构建。尽管如此,关键在于我开始实验时,测量的是完全优化且未附加调试器的发布构建,但它比 C++ 代码运行慢。 - danatel
显示剩余2条评论

4

Ngen编译你的程序并反汇编结果。


1

或许你可以ngen(编译成本地代码)这个二进制文件,以避免JIT的编译。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接