From 7b48e5f8bbffc2328b525485c8820105e371a7d6 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer <siegfriedpammer@gmail.com> Date: Thu, 26 Aug 2010 20:26:24 +0000 Subject: [PATCH] Added option to disable event tracking (IL rewriting) in profiler; workaround for cases like http://community.sharpdevelop.net/forums/t/11725.aspx git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@6446 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Analysis/Profiler/Controller/Profiler.cs | 1 + .../Profiler/Controller/ProfilerOptions.cs | 14 ++- .../Analysis/Profiler/Controller/structs.cs | 1 + .../AddIn/Src/OptionPanels/General.xaml | 4 + .../AddIn/Src/OptionPanels/OptionWrapper.cs | 6 + .../Frontend/AddIn/Src/ProfilerRunner.cs | 1 + .../Analysis/Profiler/Hook/Profiler.cpp | 119 +++++++----------- .../Analysis/Profiler/Hook/SharedMemory.h | 1 + 8 files changed, 74 insertions(+), 73 deletions(-) diff --git a/src/AddIns/Analysis/Profiler/Controller/Profiler.cs b/src/AddIns/Analysis/Profiler/Controller/Profiler.cs index b24f532749..a49cdc7801 100644 --- a/src/AddIns/Analysis/Profiler/Controller/Profiler.cs +++ b/src/AddIns/Analysis/Profiler/Controller/Profiler.cs @@ -302,6 +302,7 @@ namespace ICSharpCode.Profiler.Controller memHeader32->ProcessorFrequency = GetProcessorFrequency(); memHeader32->DoNotProfileDotnetInternals = profilerOptions.DoNotProfileDotNetInternals; memHeader32->CombineRecursiveFunction = profilerOptions.CombineRecursiveFunction; + memHeader32->TrackEvents = profilerOptions.TrackEvents; if ((Int32)(fullView.Pointer + memHeader32->HeapOffset) % 8 != 0) { throw new DataMisalignedException("Heap is not aligned properly: " + ((Int32)(fullView.Pointer + memHeader32->HeapOffset)).ToString(CultureInfo.InvariantCulture) + "!"); diff --git a/src/AddIns/Analysis/Profiler/Controller/ProfilerOptions.cs b/src/AddIns/Analysis/Profiler/Controller/ProfilerOptions.cs index 680b09a93e..532fd97171 100644 --- a/src/AddIns/Analysis/Profiler/Controller/ProfilerOptions.cs +++ b/src/AddIns/Analysis/Profiler/Controller/ProfilerOptions.cs @@ -36,6 +36,7 @@ namespace ICSharpCode.Profiler.Controller bool enableDCAtStart; bool dotNotProfileDotNetInternals; bool combineRecursiveFunction; + bool trackEvents; int sharedMemorySize; PerformanceCounterDescriptor[] counters; @@ -82,17 +83,26 @@ namespace ICSharpCode.Profiler.Controller get { return sharedMemorySize; } } + /// <summary> + /// Gets whether events should be tracked or not. + /// </summary> + public bool TrackEvents { + get { return trackEvents; } + } + /// <summary> /// Creates new ProfilerOptions using the selected settings. /// </summary> public ProfilerOptions(bool enableDC, int sharedMemorySize, bool profileDotNetInternals, - bool combineRecursiveFunction, bool enableDCAtStart, IEnumerable<PerformanceCounterDescriptor> counters) + bool combineRecursiveFunction, bool enableDCAtStart, bool trackEvents, + IEnumerable<PerformanceCounterDescriptor> counters) { this.enableDC = enableDC; this.sharedMemorySize = sharedMemorySize; this.dotNotProfileDotNetInternals = profileDotNetInternals; this.combineRecursiveFunction = combineRecursiveFunction; this.enableDCAtStart = enableDCAtStart; + this.trackEvents = trackEvents; this.counters = counters.ToArray(); } @@ -100,7 +110,7 @@ namespace ICSharpCode.Profiler.Controller /// Creates default ProfilerOptions. /// </summary> public ProfilerOptions() - : this(true, DefaultSharedMemorySize, false, false, true, DefaultCounters) + : this(true, DefaultSharedMemorySize, false, false, true, true, DefaultCounters) { } } diff --git a/src/AddIns/Analysis/Profiler/Controller/structs.cs b/src/AddIns/Analysis/Profiler/Controller/structs.cs index b8e2805656..8b676398a8 100644 --- a/src/AddIns/Analysis/Profiler/Controller/structs.cs +++ b/src/AddIns/Analysis/Profiler/Controller/structs.cs @@ -32,6 +32,7 @@ namespace ICSharpCode.Profiler.Controller public int ProcessorFrequency; public bool DoNotProfileDotnetInternals; public bool CombineRecursiveFunction; + public bool TrackEvents; public Allocator32 Allocator; } diff --git a/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/OptionPanels/General.xaml b/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/OptionPanels/General.xaml index 54e442b2a8..afbfda50b0 100644 --- a/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/OptionPanels/General.xaml +++ b/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/OptionPanels/General.xaml @@ -23,6 +23,10 @@ IsChecked="{sd:OptionBinding addin:OptionWrapper.EnableDCAtStart}" VerticalAlignment="Top" Content="{sd:Localize AddIns.Profiler.Options.General.DataCollection.EnableDCAtStartup}" /> + <CheckBox + IsChecked="{sd:OptionBinding addin:OptionWrapper.TrackEvents}" + VerticalAlignment="Top" + Content="{sd:Localize AddIns.Profiler.Options.General.DataCollection.TrackEvents}" /> <Label HorizontalAlignment="Left" VerticalAlignment="Top" diff --git a/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/OptionPanels/OptionWrapper.cs b/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/OptionPanels/OptionWrapper.cs index 461b0bbcdd..504071f3eb 100644 --- a/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/OptionPanels/OptionWrapper.cs +++ b/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/OptionPanels/OptionWrapper.cs @@ -41,6 +41,11 @@ namespace ICSharpCode.Profiler.AddIn.OptionPanels set { properties.Set("EnableDCAtStart", value); } } + public static bool TrackEvents { + get { return properties.Get("TrackEvents", true); } + set { properties.Set("TrackEvents", value); } + } + public static ProfilerOptions CreateProfilerOptions() { return new ProfilerOptions( @@ -49,6 +54,7 @@ namespace ICSharpCode.Profiler.AddIn.OptionPanels properties.Get("DoNotProfileNetInternals", false), properties.Get("CombineRecursiveFunction", false), properties.Get("EnableDCAtStart", true), + properties.Get("TrackEvents", true), ProfilerOptions.DefaultCounters ); } diff --git a/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/ProfilerRunner.cs b/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/ProfilerRunner.cs index 2aef446906..cb56792685 100644 --- a/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/ProfilerRunner.cs +++ b/src/AddIns/Analysis/Profiler/Frontend/AddIn/Src/ProfilerRunner.cs @@ -76,6 +76,7 @@ namespace ICSharpCode.Profiler.AddIn LoggingService.Info("Combine recursive calls: " + options.CombineRecursiveFunction); LoggingService.Info("Enable DC: " + options.EnableDC); LoggingService.Info("Profile .NET internals: " + (!options.DoNotProfileDotNetInternals)); + LoggingService.Info("Track events: " + options.TrackEvents); } void FinishSession() diff --git a/src/AddIns/Analysis/Profiler/Hook/Profiler.cpp b/src/AddIns/Analysis/Profiler/Hook/Profiler.cpp index 7ed0d5b61a..966d407073 100644 --- a/src/AddIns/Analysis/Profiler/Hook/Profiler.cpp +++ b/src/AddIns/Analysis/Profiler/Hook/Profiler.cpp @@ -18,18 +18,15 @@ #include <intrin.h> #include "ProfilerMetaData.h" -STDMETHODIMP_(ULONG) CProfiler::AddRef() -{ +STDMETHODIMP_(ULONG) CProfiler::AddRef() { return 1; } -STDMETHODIMP_(ULONG) CProfiler::Release() -{ +STDMETHODIMP_(ULONG) CProfiler::Release() { return 1; } -HRESULT CProfiler::QueryInterface(const IID &riid, LPVOID *ppv) -{ +HRESULT CProfiler::QueryInterface(const IID &riid, LPVOID *ppv) { *ppv = nullptr; if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ICorProfilerCallback) || @@ -44,8 +41,7 @@ HRESULT CProfiler::QueryInterface(const IID &riid, LPVOID *ppv) // ---- CALLBACK FUNCTIONS ------------------ -__declspec(noinline) void FunctionEnterCreateNewRoot(ThreadLocalData *data, const ULONGLONG &tsc) -{ +__declspec(noinline) void FunctionEnterCreateNewRoot(ThreadLocalData *data, const ULONGLONG &tsc) { DebugWriteLine(L"Creating new root"); // first function call on this thread // create a new root node for this thread @@ -53,8 +49,7 @@ __declspec(noinline) void FunctionEnterCreateNewRoot(ThreadLocalData *data, cons DebugWriteLine(L"Created new root"); } -void CProfiler::EnterLock(ThreadLocalData *data) -{ +void CProfiler::EnterLock(ThreadLocalData *data) { data->inLock = 1; _ReadWriteBarrier(); _mm_mfence(); @@ -67,8 +62,7 @@ void CProfiler::EnterLock(ThreadLocalData *data) } } -ASSEMBLER_CALLBACK FunctionEnterGlobal(int functionID) -{ +ASSEMBLER_CALLBACK FunctionEnterGlobal(int functionID) { ThreadLocalData *data = getThreadLocalData(); if (data == nullptr) { @@ -116,8 +110,7 @@ EXIT: data->inLock = 0; } -void DetachFromThread(ThreadLocalData *data) -{ +void DetachFromThread(ThreadLocalData *data) { if (data != nullptr) { DebugWriteLine(L"DetachFromThread %d", data->threadID); ULONGLONG tsc = __rdtsc(); @@ -129,8 +122,7 @@ void DetachFromThread(ThreadLocalData *data) } } -ASSEMBLER_CALLBACK FunctionLeaveGlobal() -{ +ASSEMBLER_CALLBACK FunctionLeaveGlobal() { ThreadLocalData *data = getThreadLocalData(); profiler.EnterLock(data); @@ -154,8 +146,7 @@ EXIT: data->inLock = 0; } -ASSEMBLER_CALLBACK FunctionTailcallGlobal() -{ +ASSEMBLER_CALLBACK FunctionTailcallGlobal() { DebugWriteLine(L"FunctionTailcallGlobal"); // handle tail calls A->B as leave A, enter B, ... FunctionLeaveGlobal(); @@ -180,13 +171,11 @@ int getNewPosFunctionID() { } // this function is called by the CLR when a function has been mapped to an ID -UINT_PTR CProfiler::FunctionMapper(FunctionID functionID, BOOL *) -{ +UINT_PTR CProfiler::FunctionMapper(FunctionID functionID, BOOL *) { return profiler.MapFunction(functionID, nullptr); } -UINT_PTR CProfiler::MapFunction(FunctionID functionID, const WCHAR **sigOutput) -{ +UINT_PTR CProfiler::MapFunction(FunctionID functionID, const WCHAR **sigOutput) { mapFunctionCriticalSection.Enter(); int clientData = 0; @@ -233,15 +222,13 @@ FunctionInfo *CProfiler::CreateNewRoot() { return newThreadRoot; } -void CProfiler::MovedRootChild(FunctionInfo *newRootChild) -{ +void CProfiler::MovedRootChild(FunctionInfo *newRootChild) { rootElementCriticalSection.Enter(); sharedMemoryHeader->RootFuncInfo->AddOrUpdateChild(newRootChild); rootElementCriticalSection.Leave(); } -CProfiler::CProfiler() -{ +CProfiler::CProfiler() { this->pICorProfilerInfo = nullptr; this->pICorProfilerInfo2 = nullptr; this->sigReader = nullptr; @@ -250,8 +237,7 @@ CProfiler::CProfiler() // ---- ICorProfilerCallback IMPLEMENTATION ------------------ // called when the profiling object is created by the CLR -STDMETHODIMP CProfiler::Initialize(IUnknown *pICorProfilerInfoUnk) -{ +STDMETHODIMP CProfiler::Initialize(IUnknown *pICorProfilerInfoUnk) { #ifdef DEBUG MessageBox(nullptr, TEXT("CProfiler::Initialize - Attach debugger now!"), TEXT("Attach debugger"), MB_OK); //__debugbreak(); @@ -305,15 +291,13 @@ STDMETHODIMP CProfiler::Initialize(IUnknown *pICorProfilerInfoUnk) } // called when the profiler is being terminated by the CLR -STDMETHODIMP CProfiler::Shutdown() -{ +STDMETHODIMP CProfiler::Shutdown() { LogString(L"Shutdown..."); return S_OK; } -int CProfiler::InitializeCommunication() -{ +int CProfiler::InitializeCommunication() { DebugWriteLine(L"Looking for Shared Memory..."); TCHAR sharedMemName[68]; memset(sharedMemName, 0, sizeof(sharedMemName)); @@ -379,8 +363,7 @@ int CProfiler::InitializeCommunication() } // Writes a string to the log file. Uses the same calling convention as printf. -void CProfiler::LogString(WCHAR *pszFmtString, ...) -{ +void CProfiler::LogString(WCHAR *pszFmtString, ...) { WCHAR szBuffer[2 * 4096]; va_list args; @@ -394,18 +377,17 @@ void CProfiler::LogString(WCHAR *pszFmtString, ...) nativeToManagedCriticalSection.Leave(); } -HRESULT CProfiler::SetEventMask() -{ +HRESULT CProfiler::SetEventMask() { DWORD eventMask = COR_PRF_MONITOR_ENTERLEAVE | COR_PRF_MONITOR_THREADS | COR_PRF_MONITOR_FUNCTION_UNLOADS | COR_PRF_MONITOR_CLR_EXCEPTIONS | - COR_PRF_MONITOR_EXCEPTIONS | COR_PRF_MONITOR_JIT_COMPILATION | - COR_PRF_MONITOR_MODULE_LOADS; + COR_PRF_MONITOR_EXCEPTIONS; + if (sharedMemoryHeader->trackEvents) + eventMask = eventMask | COR_PRF_MONITOR_MODULE_LOADS/* | COR_PRF_MONITOR_JIT_COMPILATION*/; return pICorProfilerInfo->SetEventMask(eventMask); } // THREAD CALLBACK FUNCTIONS -STDMETHODIMP CProfiler::ThreadAssignedToOSThread(ThreadID managedThreadID, DWORD osThreadID) -{ +STDMETHODIMP CProfiler::ThreadAssignedToOSThread(ThreadID managedThreadID, DWORD osThreadID) { this->threadMapCriticalSection.Enter(); DebugWriteLine(L"ThreadAssignedToOSThread %d, %d", managedThreadID, osThreadID); @@ -429,8 +411,7 @@ STDMETHODIMP CProfiler::ThreadAssignedToOSThread(ThreadID managedThreadID, DWORD return S_OK; } -STDMETHODIMP CProfiler::ThreadNameChanged(ThreadID threadID, ULONG cchName, WCHAR name[]) -{ +STDMETHODIMP CProfiler::ThreadNameChanged(ThreadID threadID, ULONG cchName, WCHAR name[]) { this->threadMapCriticalSection.Enter(); DebugWriteLine(L"ThreadNameChanged %d, %s", threadID, name); @@ -459,8 +440,7 @@ STDMETHODIMP CProfiler::ThreadNameChanged(ThreadID threadID, ULONG cchName, WCHA } // UNLOAD CALLBACK FUNCTIONS -STDMETHODIMP CProfiler::FunctionUnloadStarted(FunctionID functionID) -{ +STDMETHODIMP CProfiler::FunctionUnloadStarted(FunctionID functionID) { mapFunctionCriticalSection.Enter(); DebugWriteLine(L"FunctionUnloadStarted %d", functionID); @@ -469,8 +449,7 @@ STDMETHODIMP CProfiler::FunctionUnloadStarted(FunctionID functionID) return S_OK; } -STDMETHODIMP CProfiler::ThreadCreated(ThreadID threadID) -{ +STDMETHODIMP CProfiler::ThreadCreated(ThreadID threadID) { this->threadMapCriticalSection.Enter(); DebugWriteLine(L"ThreadCreated %d", threadID); @@ -490,8 +469,7 @@ STDMETHODIMP CProfiler::ThreadCreated(ThreadID threadID) return S_OK; } -STDMETHODIMP CProfiler::ThreadDestroyed(ThreadID threadID) -{ +STDMETHODIMP CProfiler::ThreadDestroyed(ThreadID threadID) { this->threadMapCriticalSection.Enter(); DebugWriteLine(L"ThreadDestroyed %d", threadID); @@ -510,24 +488,24 @@ STDMETHODIMP CProfiler::ThreadDestroyed(ThreadID threadID) return S_OK; } -STDMETHODIMP CProfiler::ExceptionThrown(ObjectID) -{ +STDMETHODIMP CProfiler::ExceptionThrown(ObjectID) { DebugWriteLine(L"ExceptionThrown"); return S_OK; } -STDMETHODIMP CProfiler::ExceptionUnwindFunctionLeave() -{ +STDMETHODIMP CProfiler::ExceptionUnwindFunctionLeave() { DebugWriteLine(L"ExceptionUnwindFunctionLeave"); FunctionLeaveGlobal(); return S_OK; } -STDMETHODIMP CProfiler::JITCompilationStarted(FunctionID functionID, BOOL /*fIsSafeToBlock*/) -{ +STDMETHODIMP CProfiler::JITCompilationStarted(FunctionID functionID, BOOL /*fIsSafeToBlock*/) { WCHAR *name; int nameId = (int)MapFunction(functionID, (const WCHAR **)(&name)); + if (name == nullptr) + return S_OK; + for (int i = 0; i < CONSOLE_GROUP_LENGTH; i++) { if (wcsstr(consoleGroupList[i], name) != nullptr) Rewrite(functionID, 0x1, nameId); @@ -546,14 +524,12 @@ STDMETHODIMP CProfiler::JITCompilationStarted(FunctionID functionID, BOOL /*fIsS return S_OK; } -void CProfiler::Activate() -{ +void CProfiler::Activate() { ThreadLocalData *data = getThreadLocalData(); data->active = true; } -void CProfiler::Deactivate() -{ +void CProfiler::Deactivate() { ThreadLocalData *data = getThreadLocalData(); data->active = false; } @@ -563,8 +539,7 @@ const ULONG TINY_HEADER_SIZE = 0x1; /* 1 byte */ const ULONG MAX_CODE_SIZE_TINY = 0x40; /* 64 bytes */ const WORD DEFAULT_MAX_STACK = 0x8; /* default stack depth in slots */ -void CProfiler::Rewrite(FunctionID functionID, int type, int nameId) -{ +void CProfiler::Rewrite(FunctionID functionID, int type, int nameId) { ModuleID moduleID; mdToken token; HRESULT hr = S_OK; @@ -715,8 +690,7 @@ void CProfiler::Rewrite(FunctionID functionID, int type, int nameId) int CProfiler::SetInjectionCode(IMetaDataImport *metaData, byte *buffer, int *size, mdMethodDef activateCall, mdMethodDef loggerCall, mdMethodDef deactivateCall, - int type, int nameId) -{ + int type, int nameId) { HRESULT hr = S_OK; int start = *size; @@ -797,8 +771,7 @@ int CProfiler::SetInjectionCode(IMetaDataImport *metaData, byte *buffer, int *si return *size - start; } -void CProfiler::ConvertToFat(byte *target, int *size) -{ +void CProfiler::ConvertToFat(byte *target, int *size) { COR_ILMETHOD_FAT *targetTable = (COR_ILMETHOD_FAT *)target; memset(targetTable, 0, FAT_HEADER_SIZE); targetTable->Flags = CorILMethod_FatFormat; @@ -810,8 +783,7 @@ void CProfiler::ConvertToFat(byte *target, int *size) /// <summary> /// Moves all offsets in SEH section tables by the given count of bytes. /// </summary> -void CProfiler::FixSEHSections(const COR_ILMETHOD_SECT *sections, int offset) -{ +void CProfiler::FixSEHSections(const COR_ILMETHOD_SECT *sections, int offset) { while (sections) { if (sections->Kind() == CorILMethod_Sect_EHTable) { COR_ILMETHOD_SECT_EH *peh = (COR_ILMETHOD_SECT_EH *) sections; @@ -845,8 +817,7 @@ void CProfiler::FixSEHSections(const COR_ILMETHOD_SECT *sections, int offset) } } -bool CProfiler::CreateMethod(IMetaDataEmit *emitter, const WCHAR *name, PCCOR_SIGNATURE sig, mdMethodDef *methodDefinition, mdToken moduleRef) -{ +bool CProfiler::CreateMethod(IMetaDataEmit *emitter, const WCHAR *name, PCCOR_SIGNATURE sig, mdMethodDef *methodDefinition, mdToken moduleRef) { HRESULT hr = emitter->DefineMethod(mdTokenNil, name, mdPublic | mdStatic | mdPinvokeImpl, sig, sizeof(sig), 0, miIL | miManaged, methodDefinition); if (!SUCCEEDED(hr)) @@ -860,8 +831,7 @@ bool CProfiler::CreateMethod(IMetaDataEmit *emitter, const WCHAR *name, PCCOR_SI return true; } -STDMETHODIMP CProfiler::ModuleLoadFinished(ModuleID moduleID, HRESULT /*hrStatus*/) -{ +STDMETHODIMP CProfiler::ModuleLoadFinished(ModuleID moduleID, HRESULT /*hrStatus*/) { HRESULT hr = S_OK; IMetaDataEmit *pIMetaDataEmit = nullptr; @@ -890,7 +860,7 @@ STDMETHODIMP CProfiler::ModuleLoadFinished(ModuleID moduleID, HRESULT /*hrStatus mdMethodDef activator; if (!CreateMethod(pIMetaDataEmit, L"ActivateProfiler", rgSig, &activator, moduleRef)) goto CLEANUP; - + mdMethodDef logger; hr = pIMetaDataEmit->DefineMethod(mdTokenNil, L"LogEvent", mdPublic | mdStatic | mdPinvokeImpl, loggerSig, sizeof(loggerSig), 0, miIL | miManaged, &logger); @@ -912,6 +882,13 @@ STDMETHODIMP CProfiler::ModuleLoadFinished(ModuleID moduleID, HRESULT /*hrStatus } CLEANUP: + #ifdef DEBUG + if (!SUCCEEDED(hr)) { + MessageBox(nullptr, TEXT("Crashed in ModuleLoadFinished"), TEXT("Crash!"), MB_OK); + __debugbreak(); + } + #endif + if (pIMetaDataEmit != nullptr) pIMetaDataEmit->Release(); diff --git a/src/AddIns/Analysis/Profiler/Hook/SharedMemory.h b/src/AddIns/Analysis/Profiler/Hook/SharedMemory.h index d0d30b882d..99b7eccf69 100644 --- a/src/AddIns/Analysis/Profiler/Hook/SharedMemory.h +++ b/src/AddIns/Analysis/Profiler/Hook/SharedMemory.h @@ -28,6 +28,7 @@ struct SharedMemoryHeader int ProcFrequency; bool doNotProfileDotnetInternals; bool combineRecursiveFunction; + bool trackEvents; freeListAllocator<FunctionInfoAllocationSize> mallocator; };