我正在尝试编写一个记录进程中所有 .Net 方法调用的分析器。目标是使其具有高性能并保持假设最后 5-10 分钟在内存中(固定缓冲区,循环覆盖旧信息),直到用户触发将该信息写入磁盘。预期用途是跟踪很少重现的性能问题。
我从https://github.com/appneta/SimpleCLRProfiler的 SimpleCLRProfiler 项目开始。分析器使用 .Net 分析的ICorProfilerCallback2回调接口。我让它在我的环境中编译和工作(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 不会在任何跟踪之前由于异常左右而意外退出。它没有。
谢谢,克里斯托夫