Delphi SampleProfiler:这段代码如何调用ntdll.dll?

前端之家收集整理的这篇文章主要介绍了Delphi SampleProfiler:这段代码如何调用ntdll.dll?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我使用 Delphi Sampling Profiler. Like most people描述了我的应用程序的一部分,我看到在ntdll.dll中花费的大部分时间.

Note: i turned on the options to ignore Application.Idle time,and calls from System.pas. So it
isn’t inside ntdll because the
application is idle:

07002

多次运行多次后,大部分时间似乎都花在了ntdll.dll中,但奇怪的是调用者是谁:

来电者来自Virtual Treeview:

PrepareCell(PaintInfo,Window.Left,NodeBitmap.Width);

Note: The application is not inside ntdll.dll because the
application is idle,because the
caller isn’t Application.Idle.

令我困惑的是,这条线本身(即不是PrepareCell内部的东西)是ntdll的调用者.更令人困惑的是:

>不仅不是PrepareCell内部的东西()
>它甚至不是PrepareCell的设置(例如弹出堆栈变量,设置隐式异常帧等),即调用者.这些东西会在探查器中显示为PrepareCell内部开始的热点.

VirtualTrees.pas:

procedure TBaseVirtualTree.PrepareCell(var PaintInfo: TVTPaintInfo; WindowOrgX,MaxWidth: Integer);
begin
   ...
end;

所以我想弄清楚这一行:

PrepareCell(PaintInfo,NodeBitmap.Width);

正在调用ntdll.dll.

其他唯一的方法是三个参数:

> PaintInfo
> Window.Left
> NodeBitmap.Width

也许其中一个是调用ntdll的函数属性getter.所以我在线上放了一个断点,并在运行时查看cpu窗口:

alt text http://i44.tinypic.com/2ut0pkx.jpg

那里有一条线可能是罪魁祸首:

call dword ptr [edx+$2c]

但是,当我按照跳转,它不会在ntdll.dll中结束,但TBitmap.GetWidth:

alt text http://i44.tinypic.com/2uswzlc.jpg

正如你所看到的那样,你不会在任何地方打电话;当然不会进入ntdll.dll.

那么这条线怎么样:

PrepareCell(PaintInfo,NodeBitmap.Width);

调用ntdll.dll?

注意:我完全知道它并没有真正调用ntdll.dll.所以任何有效的答案都必须包括“采样分析器误导;该行没有调用ntdll.dll”.答案还必须要么说大部分时间都没花在ntdll.dll上,或者突出显示的行不是调用者.最后,任何答案都必须解释为什么Sampling Profiler是错误的,以及如何修复它.

更新2

什么是ntdll.dll文件? Ntdll是Windows NT的本机API集. Win32 API是ntdll.dll的包装器,看起来像Windows 1/2 / 3 / 9x中存在的Windows API.为了实际进入ntdll,你必须直接或间接调用一个使用ntdll的函数.

例如,当我的Delphi应用程序空闲时,它会通过调用user32.dll函数来等待消息:

WaitMessage;

当你真正看到它时:

USER32.WaitMessage
  mov eax,$00001226
  mov edx,$7ffe0300
  call dword ptr [edx]
  ret

调用$7ffe0300指定的函数是Windows转换为Ring0的方式,调用EAX中指定的FunctionID.在这种情况下,被调用的系统函数是0x1226.在我的操作系统上,Windows Vista,0x1226对应于系统函数NtUserWaitMessage.

这是你如何进入ntdll.dll:你称之为.

当我提出原始问题时,我正拼命地试图避免挥手无法回答.通过非常具体,仔细地指出我所看到的现实,我试图阻止人们忽视事实,并试图用挥手的论点.

更新三

我转换了两个参数:

PrepareCell(PaintInfo,NodeBitmap.Width);

进入堆栈变量:

_profiler_WindowLeft := Window.Left;
_profiler_NodeBitmapWidth := NodeBitmap.Width;
PrepareCell(PaintInfo,_profiler_WindowLeft,_profiler_NodeBitmapWidth);

要确认瓶颈不是,请致电

> Windows.Left,或
> Nodebitmap.Width

Profiler仍然表明该行

PrepareCell(PaintInfo,_profiler_NodeBitmapWidth);

本身就是瓶颈; PrepareCell里面没有任何东西.这必须意味着它是准备单元格的调用设置内部,或者在PrepareCell的开头:

VirtualTrees.pas.15746: PrepareCell(PaintInfo,_profiler_NodeBitmapWidth);
   mov eax,[ebp-$54]
   push eax
   mov edx,esi
   mov ecx,[ebp-$50]
   mov eax,[ebp-$04]
   call TBasevirtualTree.PrepareCell

没有任何内容可以调用ntdll.现在PrepareCell本身的前导:

VirtualTrees.pas.15746: begin
   push ebp
   mov ebp,esp
   add esp,-$44
   push ebx
   push esi
   push edi
   mov [ebp-$14],ecx
   mov [ebp-$18],edx
   mov [ebp-$1c],eax
   lea esi,[ebp-$1c]
   mov edi,[ebp-$18]

没有任何内容调用ntdll.dll.

问题仍然存在:

>为什么将一个变量推入堆栈,另外两个进入寄存器瓶颈?
>为什么PrepareCell内部没有任何内容成为瓶颈?

解决方法

那么,这个问题实际上是我制作自己的采样分析器的主要原因:
http://code.google.com/p/asmprofiler/wiki/AsmProfilerSamplingMode

也许不完美,但你可以尝试一下.让我知道你对它的看法.

顺便说一下,我认为这与几乎所有调用都会结束对内核的调用(内存请求,绘制事件等)这一事实有关.只有计算不需要调用内核.
大多数调用都以等待内核结果结束:

ntdll.dll!KiFastSystemCallRet

您可以在Process Explorer中使用线程堆栈视图,或在Delphi中,或在AsmProfiler的“实时视图”中使用StackWalk64 API来查看:
http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer

原文链接:https://www.f2er.com/delphi/102184.html

猜你在找的Delphi相关文章