俺的回收站

架构分析 解释编译原理
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

厉害的 JITter 优化

Posted on 2006-12-22 17:36  Riceball LEE  阅读(2567)  评论(19编辑  收藏  举报
编译汇编语句: ADD EBX, 300,重复2017次,测得其运行时间为 60 个 QueryPerfomanceCount。在这里直接运行的机器码应该是最快实现了吧。但是让我们编译IL语句: ldc.i4 300, ADD 重复2017次,测得其运行时间居然只有区区 5个 QueryPerfomanceCount。跌破眼球吧,到底是怎么回事了,这就是JITter 优化的功劳了。

IL代码如下:
L_0006: ldc.i4 300
L_000b: stloc.3
L_000c: ldloca.s num2
L_000e: call Borland.Delphi.LongBool Borland.Vcl.Units.Windows::QueryPerformanceCounter(int64&) L_0013: pop
L_0014: ldloc.3
L_0015: ldc.i4 300
L_001a: add
L_001b: stloc.3
L_001c: ldloc.3
L_001d: ldc.i4 300
L_0022: add
....
L_3f0b: stloc.3
L_3f0c: ldloc.3
L_3f0d: ldc.i4 300
L_3f12: add
L_3f13: stloc.3
L_3f14: ldloca.s num3
L_3f16: call Borland.Delphi.LongBool Borland.Vcl.Units.Windows::QueryPerformanceCounter(int64&)

用高级语言表述其实就是(Pascal):
var
  i, count: Integer;
  tBegin, tEnd: Int64;
i := 300;
QueryPerformanceCounter(tBegin);
i := i + 300;
....
i := i + 300;
QueryPerformanceCounter(tEnd);
count := tEnd - tBegin;
writeln('ExecuteTime:',count, '; Result=', i);;
估计JITter将中间结果给省略了,直接变成了 i := 300 * 2017,这样一下子就来了,当然快的不得了。关闭JITter优化必须在调试器中运行,感谢 neoragex2002 的测试,而关闭Optimal参数只是将额外附加一个NOOP指令而已.


想个办法让它不能省略中间结果,弄个数组,将每一步的值装载起来,看看能不能骗过去。
var
   tBegin, tEnd: Int64;
   count,i: Integer;
   aArray: array [0..2016] of Integer;

i := 300;
count := 0;
aArray[count] := i;
QueryPerformanceCounter(tBegin);
i:= i+300;Inc(count);aArray[count] := i;
....
i:= i+300;Inc(count);aArray[count] := i;

现在,默认全速的情况下(debug off, optimal on),执行时间是24,唉,只骗过一点点,不过将debug on, optimal off 之后情况就正常了,执行时间在143-178之间徘徊。

JITter优化真是惹人爱啊,但是这里却让我无法测试它的JITter真实的编译开销,到底有多大,俗话说,优化越多,那么JITter在编译上花销的时间也就该越多。也许将debug on, optimal off 之后情况才是真实的JITter编译开销?

不知道那位大侠有这方面的资料,还忘不吝赐教啊。