gpt4 book ai didi

c# - ICorProfilerCallback2 : CLR profiler does not log all Leave calls

转载 作者:可可西里 更新时间:2023-11-01 09:24:05 27 4
gpt4 key购买 nike

我正在尝试编写一个记录进程中所有 .Net 方法调用的分析器。目标是使其具有高性能,并在内存中保留最后 5-10 分钟(固定缓冲区,循环覆盖旧信息),直到用户触发将该信息写入磁盘。预期用途是追踪很少重现的性能问题。

我从 https://github.com/appneta/SimpleCLRProfiler 的 SimpleCLRProfiler 项目开始.分析器使用 .Net 分析的 ICorProfilerCallback2 回调接口(interface)。我让它在我的环境中编译和工作(Win 8.1、.Net 4.5、VS2012)。但是,我注意到有时记录了 Enter 调用的 Leave 调用会丢失。 Console.WriteLine 调用示例(我将 DbgView 的输出减少到理解所需的最低限度):

Line 1481: Entering System.Console.WriteLine
Line 1483: Entering SyncTextWriter.WriteLine
Line 1485: Entering System.IO.TextWriter.WriteLine
Line 1537: Leaving SyncTextWriter.WriteLine

两个进入调用没有对应的离开调用。经过分析的 .Net 代码如下所示:

Console.WriteLine("Hello, Simple Profiler!");

相关的 SimpleCLRProfiler 方法是:

HRESULT CSimpleProfiler::registerGlobalCallbacks() 
{
HRESULT hr = profilerInfo3->SetEnterLeaveFunctionHooks3WithInfo(
(FunctionEnter3WithInfo*)MethodEntered3,
(FunctionEnter3WithInfo*)MethodLeft3,
(FunctionEnter3WithInfo*)MethodTailcall3);

if (FAILED(hr))
Trace_f(L"Failed to register global callbacks (%s)", _com_error(hr).ErrorMessage());

return S_OK;
}

void CSimpleProfiler::OnEnterWithInfo(FunctionID functionId, COR_PRF_ELT_INFO eltInfo)
{
MethodInfo info;
HRESULT hr = info.Create(profilerInfo3, functionId);
if (FAILED(hr))
Trace_f(L"Enter() failed to create MethodInfo object (%s)", _com_error(hr).ErrorMessage());

Trace_f(L"[%p] [%d] Entering %s.%s", functionId, GetCurrentThreadId(), info.className.c_str(), info.methodName.c_str());
}

void CSimpleProfiler::OnLeaveWithInfo(FunctionID functionId, COR_PRF_ELT_INFO eltInfo)
{
MethodInfo info;
HRESULT hr = info.Create(profilerInfo3, functionId);
if (FAILED(hr))
Trace_f(L"Enter() failed to create MethodInfo object (%s)", _com_error(hr).ErrorMessage());

Trace_f(L"[%p] [%d] Leaving %s.%s", functionId, GetCurrentThreadId(), info.className.c_str(), info.methodName.c_str());
}

有没有人知道为什么 .Net Profiler 不会对所有离开方法执行离开调用?顺便说一句,我检查过 OnLeaveMethod 不会由于异常等原因在任何跟踪之前意外退出。它没有。

谢谢,克里斯托夫

最佳答案

因为 stakx 似乎不会回到我的问题来提供官方答案(并获得荣誉)所以我会为他做:正如 stakx 所暗示的那样,我没有记录尾调用。事实上,我什至没有意识到这个概念,所以我完全忽略了那个钩子(Hook)方法(它是有线的但空的)。我在这里找到了对尾调用的很好解释:David Broman's CLR Profiling API Blog: Enter, Leave, Tailcall Hooks Part 2: Tall tales of tail calls .

我引用上面的链接:

Tail calling is a compiler optimization that saves execution of instructions and saves reads and writes of stack memory. When the last thing a function does is call another function (and other conditions are favorable), the compiler may consider implementing that call as a tail call, instead of a regular call.

考虑这段代码:

static public void Main() {
Helper();
}

static public void Helper() {
One();
Three();
}

static public void Three() {
...
}

当调用方法 Three 时,如果没有尾调用优化,堆栈将如下所示。

Three
Helper
Main

通过尾调用优化,堆栈看起来像这样:

Three
Main

因此在调用 Three 之前,由于优化,方法 Helper 已经从堆栈中弹出,结果堆栈上少了一个方法(less内存使用)以及一些执行和内存写入操作被保存。

关于c# - ICorProfilerCallback2 : CLR profiler does not log all Leave calls,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30950929/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com