Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/278.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有办法查看给定C#/CIL的抖动产生的本机代码?_C#_.net_Jit_Cil - Fatal编程技术网

有没有办法查看给定C#/CIL的抖动产生的本机代码?

有没有办法查看给定C#/CIL的抖动产生的本机代码?,c#,.net,jit,cil,C#,.net,Jit,Cil,在一篇关于的评论中(建议在整数乘法/除法上使用位移位运算符,以提高性能),我询问这是否会更快。在我的脑海里有一个想法,在某种程度上,某种东西会足够聪明,可以得出>1和/2是相同的操作。然而,我现在想知道这是否是真的,如果是真的,在什么程度上会发生 测试程序为两种方法生成以下比较CIL(启用optimize时),这两种方法分别对其参数进行分割和移位: IL_0000: ldarg.0 IL_0001: ldc.i4.2 IL_0002: div IL_0003: ret }

在一篇关于的评论中(建议在整数乘法/除法上使用位移位运算符,以提高性能),我询问这是否会更快。在我的脑海里有一个想法,在某种程度上,某种东西会足够聪明,可以得出
>1
/2
是相同的操作。然而,我现在想知道这是否是真的,如果是真的,在什么程度上会发生

测试程序为两种方法生成以下比较CIL(启用
optimize
时),这两种方法分别对其参数进行分割和移位:

  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.2
  IL_0002:  div
  IL_0003:  ret
} // end of method Program::Divider

  IL_0000:  ldarg.0
  IL_0001:  ldc.i4.1
  IL_0002:  shr
  IL_0003:  ret
} // end of method Program::Shifter
因此,C#编译器发出的是
div
shr
指令,但并不聪明。我现在想看看抖动产生的实际x86汇编程序,但我不知道如何做到这一点。有可能吗

编辑以添加

调查结果 感谢您的回答,我已经接受了nobugz的答案,因为它包含了关于调试器选项的关键信息。最终对我起作用的是:

  • 切换到释放配置
  • Tools | Options | Debugger
    中,关闭“在模块加载时抑制JIT优化”(即我们希望允许JIT优化)
  • 在同一位置,关闭“仅启用我的代码”(即我们要调试所有代码)
  • Debugger.Break()
    语句放在某处
  • 构建程序集
  • 运行.exe,当它中断时,使用现有的VS实例进行调试
  • 现在,反汇编窗口向您显示将要执行的实际x86
至少可以说,结果很有启发性——事实证明抖动实际上可以做算术!下面是从“反汇编”窗口编辑的示例。使用
将各种
-移位器方法除以二的幂;各种
-Divider
方法使用
/

 Console.WriteLine(string.Format("
     {0} 
     shift-divided by 2: {1} 
     divide-divided by 2: {2}", 
     60, TwoShifter(60), TwoDivider(60)));

00000026  mov         dword ptr [edx+4],3Ch 
...
0000003b  mov         dword ptr [edx+4],1Eh 
...
00000057  mov         dword ptr [esi+4],1Eh 
这两种静态除以2的方法不仅是内联的,而且实际的计算都是通过抖动来完成的

Console.WriteLine(string.Format("
    {0} 
    divide-divided by 3: {1}", 
    60, ThreeDivider(60)));

00000085  mov         dword ptr [esi+4],3Ch 
...
000000a0  mov         dword ptr [esi+4],14h 
与静态除以3相同

Console.WriteLine(string.Format("
    {0} 
    shift-divided by 4: {1} 
    divide-divided by 4 {2}", 
    60, FourShifter(60), FourDivider(60)));

000000ce  mov         dword ptr [esi+4],3Ch 
...
000000e3  mov         dword ptr [edx+4],0Fh 
...
000000ff  mov         dword ptr [esi+4],0Fh 
静态除以4

最好的:

Console.WriteLine(string.Format("
    {0} 
    n-divided by 2: {1} 
    n-divided by 3: {2} 
    n-divided by 4: {3}", 
    60, Divider(60, 2), Divider(60, 3), Divider(60, 4)));

0000013e  mov         dword ptr [esi+4],3Ch 
...
0000015b  mov         dword ptr [esi+4],1Eh 
...
0000017b  mov         dword ptr [esi+4],14h 
...
0000019b  mov         dword ptr [edi+4],0Fh 
它是内联的,然后计算所有这些静态分区

但如果结果不是静态的呢?我在代码中添加了从控制台读取整数的命令。这是它为其上的部门生成的结果:

Console.WriteLine(string.Format("
    {0} 
    shift-divided by 2:  {1} 
    divide-divided by 2: {2}", 
    i, TwoShifter(i), TwoDivider(i)));

00000211  sar         eax,1 
...
00000230  sar         eax,1 
因此,尽管CIL不同,抖动知道除以2等于右移1

Console.WriteLine(string.Format("
    {0} 
    divide-divided by 3: {1}", i, ThreeDivider(i)));
00000283 idiv eax,ecx

它知道你必须除以3

Console.WriteLine(string.Format("
    {0} 
    shift-divided by 4: {1} 
    divide-divided by 4 {2}", 
    i, FourShifter(i), FourDivider(i)));

000002c5  sar         eax,2 
...
000002ec  sar         eax,2 
它知道除以4等于右移2

终于(又是最好的!)

它内联了该方法,并根据静态可用的参数找到了最佳的方法。很好



因此,是的,在C#和x86之间的堆栈中的某个地方,有一些东西足够聪明,可以证明
>1
/2
是相同的。所有这些在我的脑海中给予了我更大的分量,我的观点是,将C编译器、抖动和CLR加在一起,比我们作为卑微的应用程序程序员可以尝试的任何小技巧都要聪明得多:)

是的。VisualStudio有一个内置的反汇编程序来实现这一点。不过,您必须将该命令添加到菜单栏中。转到Extras/Customize/Commands(我不知道在英文版中它们是否真的是这样称呼的)并将disassembly命令添加到菜单栏的某个位置,这是一个反调试命令

然后,在程序中设置断点,当断点中断时,单击此反汇编命令。VS将向您显示反汇编的机器代码

除法器方法的输出示例:

public static int Divider(int intArg)
    {
00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  push        edi  
00000004  push        esi  
00000005  push        ebx  
00000006  sub         esp,34h 
00000009  mov         esi,ecx 
0000000b  lea         edi,[ebp-38h] 
0000000e  mov         ecx,0Bh 
00000013  xor         eax,eax 
00000015  rep stos    dword ptr es:[edi] 
00000017  mov         ecx,esi 
00000019  xor         eax,eax 
0000001b  mov         dword ptr [ebp-1Ch],eax 
0000001e  mov         dword ptr [ebp-3Ch],ecx 
00000021  cmp         dword ptr ds:[00469240h],0 
00000028  je          0000002F 
0000002a  call        6BA09D91 
0000002f  xor         edx,edx 
00000031  mov         dword ptr [ebp-40h],edx 
00000034  nop              
    return intArg / 2;
00000035  mov         eax,dword ptr [ebp-3Ch] 
00000038  sar         eax,1 
0000003a  jns         0000003F 
0000003c  adc         eax,0 
0000003f  mov         dword ptr [ebp-40h],eax 
00000042  nop              
00000043  jmp         00000045 
    }

在调试过程中(并且仅在调试过程中),只需单击Debug-Windows-discomposition或按相应的快捷键Ctrl+Alt+D即可。

在配置调试器之前,您不会得到有意义的结果。工具+选项,调试,常规,关闭“在模块加载时抑制JIT优化”。切换到释放模式配置。示例代码段:

static void Main(string[] args) {
  int value = 4;
  int result = divideby2(value);
}
如果拆解过程如下所示,则说明操作正确:

00000000  ret  
0000000a  mov         edx,2 
0000000f  mov         eax,dword ptr [ecx] 
00000011  call        dword ptr [eax+000000BCh] 
您必须愚弄JIT优化器来强制计算表达式。使用Console.WriteLine(变量)会有所帮助。那么你应该看到这样的东西:

00000000  ret  
0000000a  mov         edx,2 
0000000f  mov         eax,dword ptr [ecx] 
00000011  call        dword ptr [eax+000000BCh] 

是的,它在编译时评估了结果。效果很好,不是吗。

为了我们大家的利益,你能发布你的发现吗?谢谢:)无需将该命令添加到VS,它位于“调试->Windows”菜单上。当“在模块加载时抑制JIT优化”处于启用状态时,为什么不能获得有意义的结果?我的解释是,启用此功能只意味着调试优化的/发布的本机代码。