Я пытаюсь написать профилировщик, который регистрирует все вызовы методов .Net в процессе. Цель состоит в том, чтобы сделать его высокопроизводительным и сохранить, скажем, последние 5-10 минут в памяти (фиксированный буфер, циклическая перезапись старой информации) до тех пор, пока пользователь не инициирует запись этой информации на диск. Предполагаемое использование — отследить редко повторяющиеся проблемы с производительностью.
Я начал с проекта SimpleCLRProfiler из https://github.com/appneta/SimpleCLRPProfiler. Профилировщик использует интерфейс обратного вызова ICorProfilerCallback2 профилирования .Net. Я получил его для компиляции и работы в моей среде (Win 8.1, .Net 4.5, VS2012). Однако я заметил, что иногда отсутствуют вызовы Leave, для которых были зарегистрированы вызовы Enter. Пример вызова 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!");
Соответствующие методы SimpleCLRPProfiler:
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 не будет выполнять вызовы Leave для всех методов ухода? Между прочим, я проверил, что OnLeaveMethod не завершается неожиданно перед любой трассировкой из-за исключения или чего-то подобного. Это не так.
Спасибо, Кристоф