Delphi SampleProfiler:这段代码如何调用ntdll.dll?
我使用
Delphi Sampling Profiler.
Like most people描述了我的应用程序的一部分,我看到在ntdll.dll中花费的大部分时间.
多次运行多次后,大部分时间似乎都花在了ntdll.dll中,但奇怪的是调用者是谁: 来电者来自Virtual Treeview: PrepareCell(PaintInfo,Window.Left,NodeBitmap.Width);
令我困惑的是,这条线本身(即不是PrepareCell内部的东西)是ntdll的调用者.更令人困惑的是: >不仅不是PrepareCell内部的东西() VirtualTrees.pas: procedure TBaseVirtualTree.PrepareCell(var PaintInfo: TVTPaintInfo; WindowOrgX,MaxWidth: Integer); begin ... end; 所以我想弄清楚这一行: PrepareCell(PaintInfo,NodeBitmap.Width); 正在调用ntdll.dll. 其他唯一的方法是三个参数: > PaintInfo 也许其中一个是调用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,或 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. 问题仍然存在: >为什么将一个变量推入堆栈,另外两个进入寄存器瓶颈? 解决方法
那么,这个问题实际上是我制作自己的采样分析器的主要原因:
http://code.google.com/p/asmprofiler/wiki/AsmProfilerSamplingMode 也许不完美,但你可以尝试一下.让我知道你对它的看法. 顺便说一下,我认为这与几乎所有调用都会结束对内核的调用(内存请求,绘制事件等)这一事实有关.只有计算不需要调用内核. ntdll.dll!KiFastSystemCallRet 您可以在Process Explorer中使用线程堆栈视图,或在Delphi中,或在AsmProfiler的“实时视图”中使用StackWalk64 API来查看: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |