diff options
author | David Mason <davmason@microsoft.com> | 2021-06-15 21:54:02 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-15 21:54:02 +0300 |
commit | ab71c1f4031d449ed3d60ccaaecb629bb73b648a (patch) | |
tree | 891426baadbc67a3718edc12632887ef5cc83d00 /src/coreclr/vm | |
parent | 63c8ab2e7acedca0547bc9d59ba8b7d34faf3ddb (diff) |
Add the concept of "notification profilers" to the runtime (#53122)
Diffstat (limited to 'src/coreclr/vm')
37 files changed, 1086 insertions, 1264 deletions
diff --git a/src/coreclr/vm/ClrEtwAll.man b/src/coreclr/vm/ClrEtwAll.man index 79e1f17b069..d8a275c6da6 100644 --- a/src/coreclr/vm/ClrEtwAll.man +++ b/src/coreclr/vm/ClrEtwAll.man @@ -87,6 +87,8 @@ message="$(string.RuntimePublisher.TypeDiagnosticKeywordMessage)" symbol="CLR_TYPEDIAGNOSTIC_KEYWORD" /> <keyword name="JitInstrumentationDataKeyword" mask="0x10000000000" message="$(string.RuntimePublisher.JitInstrumentationDataKeywordMessage)" symbol="CLR_JITINSTRUMENTEDDATA_KEYWORD" /> + <keyword name="ProfilerKeyword" mask="0x20000000000" + message="$(string.RuntimePublisher.ProfilerKeywordMessage)" symbol="CLR_PROFILER_KEYWORD" /> </keywords> <!--Tasks--> <tasks> @@ -429,7 +431,14 @@ <opcode name="ExecutionCheckpoint" message="$(string.RuntimePublisher.ExecutionCheckpointOpcodeMessage)" symbol="CLR_EXECUTIONCHECKPOINT_OPCODE" value="11"> </opcode> </opcodes> </task> - <!--Next available ID is 36--> + <task name="Profiler" symbol="CLR_PROFILER_TASK" + value="36" eventGUID="{68895E46-FD03-4528-89D2-5E1FBB1D3BCF}" + message="$(string.RuntimePublisher.ProfilerTaskMessage)"> + <opcodes> + <opcode name="Profiler" message="$(string.RuntimePublisher.ProfilerOpcodeMessage)" symbol="CLR_PROFILER_OPCODE" value="11"/> + </opcodes> + </task> + <!--Next available ID is 37--> </tasks> <!--Maps--> <maps> @@ -2896,6 +2905,17 @@ </ExecutionCheckpoint> </UserData> </template> + + <template tid="ProfilerMessage"> + <data name="ClrInstanceID" inType="win:UInt16"/> + <data name="Message" inType="win:UnicodeString" /> + <UserData> + <Settings xmlns="myNs"> + <ClrInstanceID> %1 </ClrInstanceID> + <Message> %2 </Message> + </Settings> + </UserData> + </template> </templates> <events> @@ -3921,6 +3941,11 @@ task="JitInstrumentationData" symbol="JitInstrumentationDataVerbose" message="$(string.RuntimePublisher.JitInstrumentationDataEventMessage)"/> + <event value="299" version="0" level="win:Informational" template="ProfilerMessage" + keywords ="ProfilerKeyword" opcode="Profiler" + task="Profiler" + symbol="ProfilerMessage" message="$(string.RuntimePublisher.ProfilerEventMessage)"/> + <!-- Execution Checkpoint event 300 --> <event value="300" version="0" level="win:Informational" template="ExecutionCheckpoint" keywords ="PerfTrackKeyword" opcode="ExecutionCheckpoint" task="ExecutionCheckpoint" symbol="ExecutionCheckpoint" @@ -7183,6 +7208,7 @@ <string id="RuntimePublisher.AssemblyLoadFromResolveHandlerInvokedEventMessage" value="ClrInstanceID=%1;%nAssemblyName=%2;%nIsTrackedLoad=%3;%nRequestingAssemblyPath=%4;%nComputedRequestedAssemblyPath=%5" /> <string id="RuntimePublisher.KnownPathProbedEventMessage" value="ClrInstanceID=%1;%nFilePath=%2;%nSource=%3;%nResult=%4" /> <string id="RuntimePublisher.JitInstrumentationDataEventMessage" value="%MethodId=%4" /> + <string id="RuntimePublisher.ProfilerEventMessage" value="%Message=%2" /> <string id="RuntimePublisher.ResolutionAttemptedEventMessage" value="ClrInstanceID=%1;%nAssemblyName=%2;%nStage=%3;%nAssemblyLoadContext=%4;%nResult=%5;%nResultAssemblyName=%6;%nResultAssemblyPath=%7;%nErrorMessage=%8" /> <string id="RuntimePublisher.StackEventMessage" value="ClrInstanceID=%1;%nReserved1=%2;%nReserved2=%3;%nFrameCount=%4;%nStack=%5" /> <string id="RuntimePublisher.AppDomainMemAllocatedEventMessage" value="AppDomainID=%1;%nAllocated=%2;%nClrInstanceID=%3" /> @@ -7383,6 +7409,7 @@ <string id="RuntimePublisher.TypeLoadTaskMessage" value="TypeLoad" /> <string id="RuntimePublisher.JitInstrumentationDataTaskMessage" value="JitInstrumentationData" /> <string id="RuntimePublisher.ExecutionCheckpointTaskMessage" value="ExecutionCheckpoint" /> + <string id="RuntimePublisher.ProfilerTaskMessage" value="Profiler" /> <string id="RundownPublisher.EEStartupTaskMessage" value="Runtime" /> <string id="RundownPublisher.MethodTaskMessage" value="Method" /> @@ -7712,6 +7739,7 @@ <string id="RuntimePublisher.MethodDiagnosticKeywordMessage" value="MethodDiagnostic" /> <string id="RuntimePublisher.TypeDiagnosticKeywordMessage" value="TypeDiagnostic" /> <string id="RuntimePublisher.JitInstrumentationDataKeywordMessage" value="JitInstrumentationData" /> + <string id="RuntimePublisher.ProfilerKeywordMessage" value="Profiler" /> <string id="RuntimePublisher.GenAwareBeginEventMessage" value="NONE" /> <string id="RuntimePublisher.GenAwareEndEventMessage" value="NONE" /> <string id="RundownPublisher.LoaderKeywordMessage" value="Loader" /> @@ -7855,6 +7883,8 @@ <string id="RuntimePublisher.ExecutionCheckpointOpcodeMessage" value="ExecutionCheckpoint" /> + <string id="RuntimePublisher.ProfilerOpcodeMessage" value="ProfilerMessage" /> + <string id="RundownPublisher.MethodDCStartOpcodeMessage" value="DCStart" /> <string id="RundownPublisher.MethodDCEndOpcodeMessage" value="DCStop" /> <string id="RundownPublisher.MethodDCStartVerboseOpcodeMessage" value="DCStartVerbose" /> diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 3f7c4deb6b0..f7bf57c5b52 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -2034,31 +2034,31 @@ void SystemDomain::NotifyProfilerStartup() CONTRACTL_END; { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); _ASSERTE(System()); - g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System()); - END_PIN_PROFILER(); + (&g_profControlBlock)->AppDomainCreationStarted((AppDomainID) System()); + END_PROFILER_CALLBACK(); } { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); _ASSERTE(System()); - g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System(), S_OK); - END_PIN_PROFILER(); + (&g_profControlBlock)->AppDomainCreationFinished((AppDomainID) System(), S_OK); + END_PROFILER_CALLBACK(); } { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); _ASSERTE(System()->DefaultDomain()); - g_profControlBlock.pProfInterface->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain()); - END_PIN_PROFILER(); + (&g_profControlBlock)->AppDomainCreationStarted((AppDomainID) System()->DefaultDomain()); + END_PROFILER_CALLBACK(); } { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); _ASSERTE(System()->DefaultDomain()); - g_profControlBlock.pProfInterface->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK); - END_PIN_PROFILER(); + (&g_profControlBlock)->AppDomainCreationFinished((AppDomainID) System()->DefaultDomain(), S_OK); + END_PROFILER_CALLBACK(); } } @@ -2073,31 +2073,31 @@ HRESULT SystemDomain::NotifyProfilerShutdown() CONTRACTL_END; { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); _ASSERTE(System()); - g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System()); - END_PIN_PROFILER(); + (&g_profControlBlock)->AppDomainShutdownStarted((AppDomainID) System()); + END_PROFILER_CALLBACK(); } { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); _ASSERTE(System()); - g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System(), S_OK); - END_PIN_PROFILER(); + (&g_profControlBlock)->AppDomainShutdownFinished((AppDomainID) System(), S_OK); + END_PROFILER_CALLBACK(); } { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); _ASSERTE(System()->DefaultDomain()); - g_profControlBlock.pProfInterface->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain()); - END_PIN_PROFILER(); + (&g_profControlBlock)->AppDomainShutdownStarted((AppDomainID) System()->DefaultDomain()); + END_PROFILER_CALLBACK(); } { - BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); _ASSERTE(System()->DefaultDomain()); - g_profControlBlock.pProfInterface->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK); - END_PIN_PROFILER(); + (&g_profControlBlock)->AppDomainShutdownFinished((AppDomainID) System()->DefaultDomain(), S_OK); + END_PROFILER_CALLBACK(); } return (S_OK); } diff --git a/src/coreclr/vm/assembly.cpp b/src/coreclr/vm/assembly.cpp index 6f45022d10b..9d4cd4ab7ce 100644 --- a/src/coreclr/vm/assembly.cpp +++ b/src/coreclr/vm/assembly.cpp @@ -270,10 +270,10 @@ void ProfilerCallAssemblyUnloadStarted(Assembly* assemblyUnloaded) { WRAPPER_NO_CONTRACT; { - BEGIN_PIN_PROFILER(CORProfilerPresent()); + BEGIN_PROFILER_CALLBACK(CORProfilerPresent()); GCX_PREEMP(); - g_profControlBlock.pProfInterface->AssemblyUnloadStarted((AssemblyID)assemblyUnloaded); - END_PIN_PROFILER(); + (&g_profControlBlock)->AssemblyUnloadStarted((AssemblyID)assemblyUnloaded); + END_PROFILER_CALLBACK(); } } @@ -281,10 +281,10 @@ void ProfilerCallAssemblyUnloadFinished(Assembly* assemblyUnloaded) { WRAPPER_NO_CONTRACT; { - BEGIN_PIN_PROFILER(CORProfilerPresent()); + BEGIN_PROFILER_CALLBACK(CORProfilerPresent()); GCX_PREEMP(); - g_profControlBlock.pProfInterface->AssemblyUnloadFinished((AssemblyID) assemblyUnloaded, S_OK); - END_PIN_PROFILER(); + (&g_profControlBlock)->AssemblyUnloadFinished((AssemblyID) assemblyUnloaded, S_OK); + END_PROFILER_CALLBACK(); } } #endif @@ -347,10 +347,10 @@ Assembly * Assembly::Create( #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAssemblyLoads()); GCX_COOP(); - g_profControlBlock.pProfInterface->AssemblyLoadStarted((AssemblyID)(Assembly *) pAssembly); - END_PIN_PROFILER(); + (&g_profControlBlock)->AssemblyLoadStarted((AssemblyID)(Assembly *) pAssembly); + END_PROFILER_CALLBACK(); } // Need TRY/HOOK instead of holder so we can get HR of exception thrown for profiler callback @@ -363,11 +363,11 @@ Assembly * Assembly::Create( EX_HOOK { { - BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAssemblyLoads()); GCX_COOP(); - g_profControlBlock.pProfInterface->AssemblyLoadFinished((AssemblyID)(Assembly *) pAssembly, + (&g_profControlBlock)->AssemblyLoadFinished((AssemblyID)(Assembly *) pAssembly, GET_EXCEPTION()->GetHR()); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } EX_END_HOOK; diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 1dff1e92480..a41ed4c81a5 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -163,10 +163,10 @@ void Module::DoInit(AllocMemTracker *pamTracker, LPCWSTR szName) #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads()); GCX_COOP(); - g_profControlBlock.pProfInterface->ModuleLoadStarted((ModuleID) this); - END_PIN_PROFILER(); + (&g_profControlBlock)->ModuleLoadStarted((ModuleID) this); + END_PROFILER_CALLBACK(); } // Need TRY/HOOK instead of holder so we can get HR of exception thrown for profiler callback EX_TRY @@ -180,9 +180,9 @@ void Module::DoInit(AllocMemTracker *pamTracker, LPCWSTR szName) EX_HOOK { { - BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads()); - g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, GET_EXCEPTION()->GetHR()); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads()); + (&g_profControlBlock)->ModuleLoadFinished((ModuleID) this, GET_EXCEPTION()->GetHR()); + END_PROFILER_CALLBACK(); } } EX_END_HOOK; @@ -291,20 +291,20 @@ void Module::NotifyProfilerLoadFinished(HRESULT hr) BOOL profilerCallbackHappened = FALSE; // Notify the profiler, this may cause metadata to be updated { - BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads()); { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ModuleLoadFinished((ModuleID) this, hr); + (&g_profControlBlock)->ModuleLoadFinished((ModuleID) this, hr); if (SUCCEEDED(hr)) { - g_profControlBlock.pProfInterface->ModuleAttachedToAssembly((ModuleID) this, + (&g_profControlBlock)->ModuleAttachedToAssembly((ModuleID) this, (AssemblyID)m_pAssembly); } profilerCallbackHappened = TRUE; } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } // If there are more types than before, add these new types to the @@ -315,13 +315,13 @@ void Module::NotifyProfilerLoadFinished(HRESULT hr) } { - BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAssemblyLoads()); if (IsManifest()) { GCX_COOP(); - g_profControlBlock.pProfInterface->AssemblyLoadFinished((AssemblyID) m_pAssembly, hr); + (&g_profControlBlock)->AssemblyLoadFinished((AssemblyID) m_pAssembly, hr); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } } @@ -1219,7 +1219,7 @@ void Module::Destruct() LOG((LF_EEMEM, INFO3, "Deleting module %x\n", this)); #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads()); if (!IsBeingUnloaded()) { // Profiler is causing some peripheral class loads. Probably this just needs @@ -1227,14 +1227,14 @@ void Module::Destruct() EX_TRY { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this); + (&g_profControlBlock)->ModuleUnloadStarted((ModuleID) this); } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -1277,19 +1277,19 @@ void Module::Destruct() #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads()); // Profiler is causing some peripheral class loads. Probably this just needs // to be turned into a Fault_not_fatal and moved to a specific place inside the profiler. EX_TRY { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ModuleUnloadFinished((ModuleID) this, S_OK); + (&g_profControlBlock)->ModuleUnloadFinished((ModuleID) this, S_OK); } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } if (m_pValidatedEmitter.Load() != NULL) @@ -3129,7 +3129,7 @@ void Module::StartUnload() WRAPPER_NO_CONTRACT; #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackModuleLoads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackModuleLoads()); if (!IsBeingUnloaded()) { // Profiler is causing some peripheral class loads. Probably this just needs @@ -3137,14 +3137,14 @@ void Module::StartUnload() EX_TRY { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ModuleUnloadStarted((ModuleID) this); + (&g_profControlBlock)->ModuleUnloadStarted((ModuleID) this); } EX_CATCH { } EX_END_CATCH(SwallowAllExceptions); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -3607,11 +3607,11 @@ void Module::SetSymbolBytes(LPCBYTE pbSyms, DWORD cbSyms) IfFailThrow(HRESULT_FROM_WIN32(dwError)); #if PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE) - BEGIN_PIN_PROFILER(CORProfilerInMemorySymbolsUpdatesEnabled()); + BEGIN_PROFILER_CALLBACK(CORProfilerInMemorySymbolsUpdatesEnabled()); { - g_profControlBlock.pProfInterface->ModuleInMemorySymbolsUpdated((ModuleID) this); + (&g_profControlBlock)->ModuleInMemorySymbolsUpdated((ModuleID) this); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); #endif //PROFILING_SUPPORTED && !defined(CROSSGEN_COMPILE) ETW::CodeSymbolLog::EmitCodeSymbols(this); diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 14e9dd9da8a..cdc5925234a 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -703,11 +703,6 @@ void EEStartupHelper() } #endif -#ifdef PROFILING_SUPPORTED - // The diagnostics server might register a profiler for delayed startup, indicate here that - // it is not currently set. This will be set to TRUE if a profiler is registered. - g_profControlBlock.fIsStoredProfilerRegistered = FALSE; -#endif // PROFILING_SUPPORTED #ifdef FEATURE_PERFTRACING DiagnosticServerAdapter::Initialize(); DiagnosticServerAdapter::PauseForDiagnosticsMonitor(); @@ -1404,10 +1399,10 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading) // Don't call back in to the profiler if we are being torn down, it might be unloaded if (!fIsDllUnloading) { - BEGIN_PIN_PROFILER(CORProfilerPresent()); + BEGIN_PROFILER_CALLBACK(CORProfilerPresent()); GCX_PREEMP(); - g_profControlBlock.pProfInterface->Shutdown(); - END_PIN_PROFILER(); + (&g_profControlBlock)->Shutdown(); + END_PROFILER_CALLBACK(); } g_fEEShutDown |= ShutDown_Profiler; diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp index 17417e0b760..6f2da9db3c2 100644 --- a/src/coreclr/vm/class.cpp +++ b/src/coreclr/vm/class.cpp @@ -94,7 +94,7 @@ void EEClass::Destruct(MethodTable * pOwningMT) #ifdef PROFILING_SUPPORTED // If profiling, then notify the class is getting unloaded. { - BEGIN_PIN_PROFILER(CORProfilerTrackClasses()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackClasses()); { // Calls to the profiler callback may throw, or otherwise fail, if // the profiler AVs/throws an unhandled exception/etc. We don't want @@ -115,7 +115,7 @@ void EEClass::Destruct(MethodTable * pOwningMT) { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ClassUnloadStarted((ClassID) pOwningMT); + (&g_profControlBlock)->ClassUnloadStarted((ClassID) pOwningMT); } EX_CATCH { @@ -125,7 +125,7 @@ void EEClass::Destruct(MethodTable * pOwningMT) } EX_END_CATCH(RethrowTerminalExceptions); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -178,7 +178,7 @@ void EEClass::Destruct(MethodTable * pOwningMT) #ifdef PROFILING_SUPPORTED // If profiling, then notify the class is getting unloaded. { - BEGIN_PIN_PROFILER(CORProfilerTrackClasses()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackClasses()); { // See comments in the call to ClassUnloadStarted for details on this // FAULT_NOT_FATAL marker and exception swallowing. @@ -186,14 +186,14 @@ void EEClass::Destruct(MethodTable * pOwningMT) EX_TRY { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ClassUnloadFinished((ClassID) pOwningMT, S_OK); + (&g_profControlBlock)->ClassUnloadFinished((ClassID) pOwningMT, S_OK); } EX_CATCH { } EX_END_CATCH(RethrowTerminalExceptions); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED diff --git a/src/coreclr/vm/clsload.cpp b/src/coreclr/vm/clsload.cpp index 65692222bb3..62eccc0995f 100644 --- a/src/coreclr/vm/clsload.cpp +++ b/src/coreclr/vm/clsload.cpp @@ -3452,7 +3452,7 @@ void ClassLoader::Notify(TypeHandle typeHnd) #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackClasses()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackClasses()); // We don't tell profilers about typedescs, as per IF above. Also, we don't // tell profilers about: if ( @@ -3465,7 +3465,7 @@ void ClassLoader::Notify(TypeHandle typeHnd) { LOG((LF_CLASSLOADER, LL_INFO1000, "Notifying profiler of Started1 %p %s\n", pMT, pMT->GetDebugClassName())); // Record successful load of the class for the profiler - g_profControlBlock.pProfInterface->ClassLoadStarted(TypeHandleToClassID(typeHnd)); + (&g_profControlBlock)->ClassLoadStarted(TypeHandleToClassID(typeHnd)); // // Profiler can turn off TrackClasses during the Started() callback. Need to @@ -3474,11 +3474,11 @@ void ClassLoader::Notify(TypeHandle typeHnd) if (CORProfilerTrackClasses()) { LOG((LF_CLASSLOADER, LL_INFO1000, "Notifying profiler of Finished1 %p %s\n", pMT, pMT->GetDebugClassName())); - g_profControlBlock.pProfInterface->ClassLoadFinished(TypeHandleToClassID(typeHnd), + (&g_profControlBlock)->ClassLoadFinished(TypeHandleToClassID(typeHnd), S_OK); } } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif //PROFILING_SUPPORTED diff --git a/src/coreclr/vm/comcallablewrapper.cpp b/src/coreclr/vm/comcallablewrapper.cpp index eb5b5abd368..dfee278b891 100644 --- a/src/coreclr/vm/comcallablewrapper.cpp +++ b/src/coreclr/vm/comcallablewrapper.cpp @@ -3725,7 +3725,7 @@ BOOL ComMethodTable::LayOutInterfaceMethodTable(MethodTable* pClsMT) #ifdef PROFILING_SUPPORTED // Notify profiler of the CCW, so it can avoid double-counting. { - BEGIN_PIN_PROFILER(CORProfilerTrackCCW()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackCCW()); #if defined(_DEBUG) WCHAR rIID[40]; // {00000000-0000-0000-0000-000000000000} GuidToLPWSTR(m_IID, rIID, lengthof(rIID)); @@ -3735,11 +3735,11 @@ BOOL ComMethodTable::LayOutInterfaceMethodTable(MethodTable* pClsMT) LOG((LF_CORPROF, LL_INFO100, "COMClassicVTableCreated Class:%#x, IID:{%08x-...}, vTbl:%#08x\n", pItfClass, m_IID.Data1, pUnkVtable)); #endif - g_profControlBlock.pProfInterface->COMClassicVTableCreated((ClassID) TypeHandle(pItfClass).AsPtr(), + (&g_profControlBlock)->COMClassicVTableCreated((ClassID) TypeHandle(pItfClass).AsPtr(), m_IID, pUnkVtable, m_cbSlots+cbExtraSlots); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -4858,7 +4858,7 @@ ComCallWrapperTemplate* ComCallWrapperTemplate::CreateTemplate(TypeHandle thClas // Notify profiler of the CCW, so it can avoid double-counting. if (pTemplate->SupportsIClassX()) { - BEGIN_PIN_PROFILER(CORProfilerTrackCCW()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackCCW()); // When under the profiler, we'll eagerly generate the IClassX CMT. pTemplate->GetClassComMT(); @@ -4880,11 +4880,11 @@ ComCallWrapperTemplate* ComCallWrapperTemplate::CreateTemplate(TypeHandle thClas LOG((LF_CORPROF, LL_INFO100, "COMClassicVTableCreated TypeHandle:%#x, IID:{%08x-...}, vTbl:%#08x\n", thClass.AsPtr(), IClassXIID.Data1, pComVtable)); #endif - g_profControlBlock.pProfInterface->COMClassicVTableCreated( + (&g_profControlBlock)->COMClassicVTableCreated( (ClassID) thClass.AsPtr(), IClassXIID, pComVtable, pTemplate->m_pClassComMT->m_cbSlots + ComMethodTable::GetNumExtraSlots(pTemplate->m_pClassComMT->GetInterfaceType())); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED RETURN pTemplate; diff --git a/src/coreclr/vm/comsynchronizable.cpp b/src/coreclr/vm/comsynchronizable.cpp index bc79ffcd8fa..39f00d06741 100644 --- a/src/coreclr/vm/comsynchronizable.cpp +++ b/src/coreclr/vm/comsynchronizable.cpp @@ -1009,16 +1009,16 @@ void QCALLTYPE ThreadNative::InformThreadNameChange(QCall::ThreadHandle thread, #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackThreads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackThreads()); if (name == NULL) { - g_profControlBlock.pProfInterface->ThreadNameChanged((ThreadID)pThread, 0, NULL); + (&g_profControlBlock)->ThreadNameChanged((ThreadID)pThread, 0, NULL); } else { - g_profControlBlock.pProfInterface->ThreadNameChanged((ThreadID)pThread, len, (WCHAR*)name); + (&g_profControlBlock)->ThreadNameChanged((ThreadID)pThread, len, (WCHAR*)name); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED diff --git a/src/coreclr/vm/crossgencompile.cpp b/src/coreclr/vm/crossgencompile.cpp index 1e14e79be7f..df3555e31a7 100644 --- a/src/coreclr/vm/crossgencompile.cpp +++ b/src/coreclr/vm/crossgencompile.cpp @@ -123,7 +123,7 @@ DWORD GetCurrentExceptionCode() // disable PROFILING_SUPPORTED for crossgen because of it affects data layout and FCall tables. // -UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction) +UINT_PTR EEToProfInterfaceImpl::EEFunctionIDMapper(FunctionID funcId, BOOL *pbHookFunction) { UNREACHABLE(); } diff --git a/src/coreclr/vm/eetoprofinterfaceimpl.cpp b/src/coreclr/vm/eetoprofinterfaceimpl.cpp index 34cd1475a42..745f2b6ef1c 100644 --- a/src/coreclr/vm/eetoprofinterfaceimpl.cpp +++ b/src/coreclr/vm/eetoprofinterfaceimpl.cpp @@ -103,15 +103,17 @@ enum ClrToProfEntrypointFlags }; #define ASSERT_EVAC_COUNTER_NONZERO() \ - _ASSERTE((GetThreadNULLOk() == NULL) || \ - (GetThreadNULLOk()->GetProfilerEvacuationCounter() != 0U)) + _ASSERTE(m_pProfilerInfo->dwProfilerEvacuationCounter.Load() > 0) #define CHECK_PROFILER_STATUS(ee2pFlags) \ /* If one of these asserts fires, perhaps you forgot to use */ \ - /* BEGIN/END_PIN_PROFILER */ \ + /* BEGIN/END_PROFILER_CALLBACK */ \ ASSERT_EVAC_COUNTER_NONZERO(); \ - _ASSERTE(g_profControlBlock.pProfInterface.Load() != NULL); \ - _ASSERTE(g_profControlBlock.pProfInterface == this); \ + /* Either we are initializing, or we have the ProfToEEInterfaceImpl */ \ + _ASSERTE((((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) || (m_pProfilerInfo->pProfInterface.Load() != NULL)); \ + /* If we are initializing, null is fine. Otherwise we want to make sure we haven't messed up the association between */ \ + /* EEToProfInterfaceImpl/ProfToEEInterfaceImpl somehow. */ \ + _ASSERTE((((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) || (m_pProfilerInfo->pProfInterface == this)); \ /* Early abort if... */ \ if ( \ /* Profiler isn't active, */ \ @@ -121,7 +123,7 @@ enum ClrToProfEntrypointFlags /* on a detaching profiler, and b) the profiler is detaching */ \ !( \ (((ee2pFlags) & kEE2PAllowableWhileDetaching) != 0) && \ - (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching) \ + (m_pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching) \ ) && \ \ /* and it's not the case that both a) this callback is allowed */ \ @@ -129,9 +131,9 @@ enum ClrToProfEntrypointFlags !( \ (((ee2pFlags) & kEE2PAllowableWhileInitializing) != 0) && \ ( \ - (g_profControlBlock.curProfStatus.Get() \ + (m_pProfilerInfo->curProfStatus.Get() \ == kProfStatusInitializingForStartupLoad) || \ - (g_profControlBlock.curProfStatus.Get() \ + (m_pProfilerInfo->curProfStatus.Get() \ == kProfStatusInitializingForAttachLoad) \ ) \ ) \ @@ -412,14 +414,13 @@ EEToProfInterfaceImpl::EEToProfInterfaceImpl() : m_pCallback8(NULL), m_pCallback9(NULL), m_pCallback10(NULL), + m_pCallback11(NULL), m_hmodProfilerDLL(NULL), m_fLoadedViaAttach(FALSE), m_pProfToEE(NULL), m_pProfilersFuncIDMapper(NULL), m_pProfilersFuncIDMapper2(NULL), m_pProfilersFuncIDMapper2ClientData(NULL), - m_GUID(k_guidZero), - m_lGUIDCount(0), m_pGCRefDataFreeList(NULL), m_csGCRefDataFreeList(NULL), m_pEnter(NULL), @@ -437,6 +438,7 @@ EEToProfInterfaceImpl::EEToProfInterfaceImpl() : m_pTailcall3WithInfo(NULL), m_fUnrevertiblyModifiedIL(FALSE), m_fModifiedRejitState(FALSE), + m_pProfilerInfo(NULL), m_pFunctionIDHashTable(NULL), m_pFunctionIDHashTableRWLock(NULL), m_dwConcurrentGCWaitTimeoutInMs(INFINITE), @@ -585,6 +587,12 @@ HRESULT EEToProfInterfaceImpl::Init( return S_OK; } +void EEToProfInterfaceImpl::SetProfilerInfo(ProfilerInfo *pProfilerInfo) +{ + LIMITED_METHOD_CONTRACT; + m_pProfilerInfo = pProfilerInfo; + m_pProfToEE->SetProfilerInfo(pProfilerInfo); +} //--------------------------------------------------------------------------------------- // @@ -660,18 +668,39 @@ HRESULT EEToProfInterfaceImpl::CreateProfiler( // ATTENTION: Please update EEToProfInterfaceImpl::~EEToProfInterfaceImpl() after adding the next ICorProfilerCallback interface here !!! - // The profiler may optionally support ICorProfilerCallback3,4,5,6,7,8,9,10. Let's check. - ReleaseHolder<ICorProfilerCallback10> pCallback10; + // The profiler may optionally support ICorProfilerCallback3,4,5,6,7,8,9,10,11. Let's check. + ReleaseHolder<ICorProfilerCallback11> pCallback11; hr = m_pCallback2->QueryInterface( - IID_ICorProfilerCallback10, - (LPVOID *)&pCallback10); - if (SUCCEEDED(hr) && (pCallback10 != NULL)) + IID_ICorProfilerCallback11, + (LPVOID *)&pCallback11); + if (SUCCEEDED(hr) && (pCallback11 != NULL)) + { + _ASSERTE(m_pCallback11 == NULL); + m_pCallback11 = pCallback11.Extract(); + pCallback11 = NULL; + } + + if (m_pCallback11 == NULL) + { + ReleaseHolder<ICorProfilerCallback10> pCallback10; + hr = m_pCallback2->QueryInterface( + IID_ICorProfilerCallback10, + (LPVOID *)&pCallback10); + if (SUCCEEDED(hr) && (pCallback10 != NULL)) + { + _ASSERTE(m_pCallback10 == NULL); + m_pCallback10 = pCallback10.Extract(); + pCallback10 = NULL; + } + } + else { _ASSERTE(m_pCallback10 == NULL); - m_pCallback10 = pCallback10.Extract(); - pCallback10 = NULL; + m_pCallback10 = static_cast<ICorProfilerCallback10 *>(m_pCallback11); + m_pCallback10->AddRef(); } + // Due to inheritance, if we have an interface we must also have // all the previous versions if (m_pCallback10 == NULL) @@ -847,7 +876,7 @@ EEToProfInterfaceImpl::~EEToProfInterfaceImpl() // scan through list of detaching profilers to make sure none of them give a // GetEEToProfPtr() equal to this #ifdef FEATURE_PROFAPI_ATTACH_DETACH - _ASSERTE(ProfilingAPIDetach::GetEEToProfPtr() == NULL); + _ASSERTE(!ProfilingAPIDetach::IsEEToProfPtrRegisteredForDetach(this)); #endif // FEATURE_PROFAPI_ATTACH_DETACH // Release user-specified profiler DLL @@ -912,6 +941,12 @@ EEToProfInterfaceImpl::~EEToProfInterfaceImpl() m_pCallback10 = NULL; } + if (m_pCallback11 != NULL) + { + m_pCallback11->Release(); + m_pCallback11 = NULL; + } + // Only unload the V4 profiler if this is not part of shutdown. This protects // Whidbey profilers that aren't used to being FreeLibrary'd. if (fIsV4Profiler && !g_fEEShutDown) @@ -972,8 +1007,6 @@ EEToProfInterfaceImpl::~EEToProfInterfaceImpl() m_pSavedAllocDataBlock = NULL; } - m_GUID = k_guidZero; - if (m_csGCRefDataFreeList != NULL) { ClrDeleteCriticalSection(m_csGCRefDataFreeList); @@ -993,70 +1026,6 @@ EEToProfInterfaceImpl::~EEToProfInterfaceImpl() } } - - -//--------------------------------------------------------------------------------------- -// -// Initialize the GUID used for the cookie in remoting callbacks. If already -// initialized, this just does nothing and returns S_OK. -// -// Return Value: -// HRESULT indicating success or failure. If the GUID was already initialized, -// just returns S_OK -// -// - -HRESULT EEToProfInterfaceImpl::InitGUID() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - CANNOT_TAKE_LOCK; - ASSERT_NO_EE_LOCKS_HELD(); - } - CONTRACTL_END; - - if (IsEqualGUID(m_GUID, k_guidZero)) - { - return CoCreateGuid(&m_GUID); - } - - return S_OK; -} - -//--------------------------------------------------------------------------------------- -// -// Returns a GUID suitable for use as a remoting callback cookie for this thread. -// The GUID is based on the template GUID (m_GUID), the current thread, and -// a counter. -// -// Arguments: -// pGUID - [out] The GUID requested -// - -void EEToProfInterfaceImpl::GetGUID(GUID * pGUID) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - ASSERT_NO_EE_LOCKS_HELD(); - } - CONTRACTL_END; - - // the member GUID and the argument should both be valid - _ASSERTE(!(IsEqualGUID(m_GUID, k_guidZero))); - _ASSERTE(pGUID); - - // Copy the contents of the template GUID - memcpy(pGUID, &m_GUID, sizeof(GUID)); - - // Adjust the last two bytes - pGUID->Data4[6] = (BYTE) GetCurrentThreadId(); - pGUID->Data4[7] = (BYTE) InterlockedIncrement((LPLONG)&m_lGUIDCount); -} - //--------------------------------------------------------------------------------------- // // Wrapper around calling profiler's FunctionIDMapper hook. Called by JIT. @@ -1955,14 +1924,13 @@ HRESULT EEToProfInterfaceImpl::EnsureProfilerDetachable() { LIMITED_METHOD_CONTRACT; - if (((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE) != 0) || - ((g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) != 0)) + if (m_pProfilerInfo->eventMask.IsEventMaskSet(COR_PRF_MONITOR_IMMUTABLE) || + m_pProfilerInfo->eventMask.IsEventMaskHighSet(COR_PRF_HIGH_MONITOR_IMMUTABLE)) { LOG(( LF_CORPROF, LL_ERROR, - "**PROF: Profiler may not detach because it set an immutable flag. Flags = 0x%x.\n", - g_profControlBlock.dwEventMask)); + "**PROF: Profiler may not detach because it set an immutable flag.\n")); return CORPROF_E_IMMUTABLE_FLAGS_SET; } @@ -2172,6 +2140,15 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask } CONTRACTL_END; + BOOL isMainProfiler = g_profControlBlock.IsMainProfiler(this); + + if (!isMainProfiler && + ((dwEventMask & ~COR_PRF_ALLOWABLE_NOTIFICATION_PROFILER) + || (dwEventMaskHigh & ~COR_PRF_HIGH_ALLOWABLE_NOTIFICATION_PROFILER))) + { + return E_INVALIDARG; + } + static const DWORD kEventFlagsRequiringSlowPathEnterLeaveHooks = COR_PRF_ENABLE_FUNCTION_ARGS | COR_PRF_ENABLE_FUNCTION_RETVAL | @@ -2222,17 +2199,17 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask // not trying to set an immutable attribute // FUTURE: If we add immutable flags to the high event mask, this would be a good // place to check for them as well. - if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad) + if (m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForStartupLoad) { #ifdef _DEBUG if (((dwEventMask & dwImmutableEventFlags) != - (g_profControlBlock.dwEventMask & dwImmutableEventFlags)) || + (m_pProfilerInfo->eventMask.GetEventMask() & dwImmutableEventFlags)) || #else //!_DEBUG if (((dwEventMask & COR_PRF_MONITOR_IMMUTABLE) != - (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_IMMUTABLE)) || + (m_pProfilerInfo->eventMask.GetEventMask() & COR_PRF_MONITOR_IMMUTABLE)) || #endif //_DEBUG ((dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE) != - (g_profControlBlock.dwEventMaskHigh & COR_PRF_HIGH_MONITOR_IMMUTABLE))) + (m_pProfilerInfo->eventMask.GetEventMaskHigh() & COR_PRF_HIGH_MONITOR_IMMUTABLE))) { // FUTURE: Should we have a dedicated HRESULT for setting immutable flag? return E_FAIL; @@ -2254,7 +2231,7 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask // After fast path ELT hooks are set in Initial callback, the startup profiler is not allowed to change flags // that require slow path ELT hooks or disable ELT hooks. - if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) && + if ((m_pProfilerInfo->curProfStatus.Get() == kProfStatusInitializingForStartupLoad) && ( (m_pEnter3 != NULL) || (m_pLeave3 != NULL) || @@ -2266,13 +2243,13 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask ) ) { - _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) == 0); + _ASSERTE(!m_pProfilerInfo->eventMask.IsEventMaskSet(kEventFlagsRequiringSlowPathEnterLeaveHooks)); return CORPROF_E_INCONSISTENT_WITH_FLAGS; } // After slow path ELT hooks are set in Initial callback, the startup profiler is not allowed to remove // all flags that require slow path ELT hooks or to change the flag to disable the ELT hooks. - if ((g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) && + if ((m_pProfilerInfo->curProfStatus.Get() == kProfStatusInitializingForStartupLoad) && ( (m_pEnter3WithInfo != NULL) || (m_pLeave3WithInfo != NULL) || @@ -2284,7 +2261,7 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask ) ) { - _ASSERTE((g_profControlBlock.dwEventMask & kEventFlagsRequiringSlowPathEnterLeaveHooks) != 0); + _ASSERTE(m_pProfilerInfo->eventMask.IsEventMaskSet(kEventFlagsRequiringSlowPathEnterLeaveHooks)); return CORPROF_E_INCONSISTENT_WITH_FLAGS; } @@ -2295,7 +2272,7 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask ( ( // Old flags - ((g_profControlBlock.dwEventMask & kEventFlagsAffectingEnterLeaveHooks) ^ + ((m_pProfilerInfo->eventMask.GetEventMask() & kEventFlagsAffectingEnterLeaveHooks) ^ // XORed w/ the new flags (dwEventMask & kEventFlagsAffectingEnterLeaveHooks)) ) != 0 @@ -2316,13 +2293,18 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask (m_pTailcall != NULL) ); + if (fEnterLeaveHooksAffected && !isMainProfiler) + { + return E_INVALIDARG; + } + BOOL fNeedToTurnOffConcurrentGC = FALSE; if (((dwEventMask & COR_PRF_MONITOR_GC) != 0) && - ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_GC) == 0)) + ((m_pProfilerInfo->eventMask.GetEventMask() & COR_PRF_MONITOR_GC) == 0)) { // We don't need to worry about startup load as we'll turn off concurrent GC later - if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad) + if (m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForStartupLoad) { // Since we're not an initializing startup profiler, the EE must be fully started up // so we can check whether concurrent GC is on @@ -2341,7 +2323,7 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask // If we are attaching and we are turning on COR_PRF_MONITOR_GC, turn off concurrent GC later // in this function - if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForAttachLoad) + if (m_pProfilerInfo->curProfStatus.Get() == kProfStatusInitializingForAttachLoad) { if (GCHeapUtilities::GetGCHeap()->IsConcurrentGCEnabled()) { @@ -2375,12 +2357,12 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask if ((dwEventMask & COR_PRF_ENABLE_REJIT) != 0) { - if ((g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad) && !ReJitManager::IsReJITEnabled()) + if ((m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForStartupLoad) && !ReJitManager::IsReJITEnabled()) { return CORPROF_E_REJIT_NOT_ENABLED; } - g_profControlBlock.pProfInterface->SetModifiedRejitState(); + m_pProfilerInfo->pProfInterface->SetModifiedRejitState(); } // High event bits @@ -2398,8 +2380,10 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask } // Now save the modified masks - g_profControlBlock.dwEventMask = dwEventMask; - g_profControlBlock.dwEventMaskHigh = dwEventMaskHigh; + m_pProfilerInfo->eventMask.SetEventMask(dwEventMask); + m_pProfilerInfo->eventMask.SetEventMaskHigh(dwEventMaskHigh); + + g_profControlBlock.UpdateGlobalEventMask(); if (fEnterLeaveHooksAffected) { @@ -2410,26 +2394,13 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask } } - if (g_profControlBlock.curProfStatus.Get() == kProfStatusInitializingForStartupLoad) - { - // If the profiler has requested remoting cookies so that it can - // track logical call stacks, then we must initialize the cookie - // template. - if ((g_profControlBlock.dwEventMask & COR_PRF_MONITOR_REMOTING_COOKIE) - == COR_PRF_MONITOR_REMOTING_COOKIE) - { - hr = InitGUID(); - if (FAILED(hr)) - { - return hr; - } - } - } - // Turn off concurrent GC as the last step so that we don't need to turn it back on if something // else failed after that if (fNeedToTurnOffConcurrentGC) { + // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling + g_profControlBlock.fConcurrentGCDisabledForAttach = TRUE; + // Turn off concurrent GC if it is on so that user can walk the heap safely in GC callbacks IGCHeap * pGCHeap = GCHeapUtilities::GetGCHeap(); @@ -2460,13 +2431,14 @@ HRESULT EEToProfInterfaceImpl::SetEventMask(DWORD dwEventMask, DWORD dwEventMask m_bHasTimedOutWaitingForConcurrentGC = TRUE; } + // TODO: think about race conditions... I am pretty sure there is one + // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling + g_profControlBlock.fConcurrentGCDisabledForAttach = FALSE; pGCHeap->TemporaryEnableConcurrentGC(); + return hr; } - // Remember that we've turned off concurrent GC and we'll turn it back on in TerminateProfiling - g_profControlBlock.fConcurrentGCDisabledForAttach = TRUE; - LOG((LF_CORPROF, LL_INFO10, "**PROF: Concurrent GC has been turned off at attach.\n")); } @@ -5339,290 +5311,6 @@ HRESULT EEToProfInterfaceImpl::RuntimeThreadResumed(ThreadID resumedThreadId) } //--------------------------------------------------------------------------------------- -// REMOTING -// - -HRESULT EEToProfInterfaceImpl::RemotingClientInvocationStarted() -{ - CONTRACTL - { - // Yay! - NOTHROW; - - // Yay! - GC_TRIGGERS; - - // Yay! - MODE_PREEMPTIVE; - - // Yay! - CAN_TAKE_LOCK; - - // Yay! - ASSERT_NO_EE_LOCKS_HELD(); - - } - CONTRACTL_END; - - CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, - LL_INFO1000, - "**PROF: RemotingClientInvocationStarted. ThreadID: 0x%p\n", - GetThreadNULLOk())); - - { - // All callbacks are really NOTHROW, but that's enforced partially by the profiler, - // whose try/catch blocks aren't visible to the contract system - PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout); - return m_pCallback2->RemotingClientInvocationStarted(); - } -} - -HRESULT EEToProfInterfaceImpl::RemotingClientSendingMessage(GUID *pCookie, BOOL fIsAsync) -{ - CONTRACTL - { - // Yay! - NOTHROW; - - // Yay! - GC_TRIGGERS; - - // Yay! - MODE_PREEMPTIVE; - - // Yay! - CAN_TAKE_LOCK; - - // Yay! - ASSERT_NO_EE_LOCKS_HELD(); - - } - CONTRACTL_END; - - CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, - LL_INFO1000, - "**PROF: RemotingClientSendingMessage. ThreadID: 0x%p\n", - GetThreadNULLOk())); - - { - // All callbacks are really NOTHROW, but that's enforced partially by the profiler, - // whose try/catch blocks aren't visible to the contract system - PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout); - return m_pCallback2->RemotingClientSendingMessage(pCookie, fIsAsync); - } -} - -HRESULT EEToProfInterfaceImpl::RemotingClientReceivingReply(GUID * pCookie, BOOL fIsAsync) -{ - CONTRACTL - { - // Yay! - NOTHROW; - - // Yay! - GC_TRIGGERS; - - // Yay! - MODE_PREEMPTIVE; - - // Yay! - CAN_TAKE_LOCK; - - // Yay! - ASSERT_NO_EE_LOCKS_HELD(); - - } - CONTRACTL_END; - - CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, - LL_INFO1000, - "**PROF: RemotingClientReceivingReply. ThreadID: 0x%p\n", - GetThreadNULLOk())); - - { - // All callbacks are really NOTHROW, but that's enforced partially by the profiler, - // whose try/catch blocks aren't visible to the contract system - PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout); - return m_pCallback2->RemotingClientReceivingReply(pCookie, fIsAsync); - } -} - -HRESULT EEToProfInterfaceImpl::RemotingClientInvocationFinished() -{ - CONTRACTL - { - // Yay! - NOTHROW; - - // Yay! - GC_TRIGGERS; - - // Yay! - MODE_PREEMPTIVE; - - // Yay! - CAN_TAKE_LOCK; - - // Yay! - ASSERT_NO_EE_LOCKS_HELD(); - - } - CONTRACTL_END; - - CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, - LL_INFO1000, - "**PROF: RemotingClientInvocationFinished. ThreadID: 0x%p\n", - GetThreadNULLOk())); - - { - // All callbacks are really NOTHROW, but that's enforced partially by the profiler, - // whose try/catch blocks aren't visible to the contract system - PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout); - return m_pCallback2->RemotingClientInvocationFinished(); - } -} - -HRESULT EEToProfInterfaceImpl::RemotingServerReceivingMessage(GUID *pCookie, BOOL fIsAsync) -{ - CONTRACTL - { - // Yay! - NOTHROW; - - // Yay! - GC_TRIGGERS; - - // Yay! - MODE_PREEMPTIVE; - - // Yay! - CAN_TAKE_LOCK; - - // Yay! - ASSERT_NO_EE_LOCKS_HELD(); - - } - CONTRACTL_END; - - CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, - LL_INFO1000, - "**PROF: RemotingServerReceivingMessage. ThreadID: 0x%p\n", - GetThreadNULLOk())); - - { - // All callbacks are really NOTHROW, but that's enforced partially by the profiler, - // whose try/catch blocks aren't visible to the contract system - PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout); - return m_pCallback2->RemotingServerReceivingMessage(pCookie, fIsAsync); - } -} - -HRESULT EEToProfInterfaceImpl::RemotingServerInvocationStarted() -{ - CONTRACTL - { - // Yay! - NOTHROW; - - // Yay! - GC_TRIGGERS; - - // Yay! - MODE_PREEMPTIVE; - - // Yay! - CAN_TAKE_LOCK; - - // Yay! - ASSERT_NO_EE_LOCKS_HELD(); - - } - CONTRACTL_END; - - CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, - LL_INFO1000, - "**PROF: RemotingServerInvocationStarted. ThreadID: 0x%p\n", - GetThreadNULLOk())); - - { - // All callbacks are really NOTHROW, but that's enforced partially by the profiler, - // whose try/catch blocks aren't visible to the contract system - PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout); - return m_pCallback2->RemotingServerInvocationStarted(); - } -} - -HRESULT EEToProfInterfaceImpl::RemotingServerInvocationReturned() -{ - CONTRACTL - { - // Yay! - NOTHROW; - - // Yay! - GC_TRIGGERS; - - // Yay! - MODE_PREEMPTIVE; - - // Yay! - CAN_TAKE_LOCK; - - // Yay! - ASSERT_NO_EE_LOCKS_HELD(); - - } - CONTRACTL_END; - - CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, - LL_INFO1000, - "**PROF: RemotingServerInvocationReturned. ThreadID: 0x%p\n", - GetThreadNULLOk())); - - { - // All callbacks are really NOTHROW, but that's enforced partially by the profiler, - // whose try/catch blocks aren't visible to the contract system - PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout); - return m_pCallback2->RemotingServerInvocationReturned(); - } -} - -HRESULT EEToProfInterfaceImpl::RemotingServerSendingReply(GUID *pCookie, BOOL fIsAsync) -{ - CONTRACTL - { - // Yay! - NOTHROW; - - // Yay! - GC_TRIGGERS; - - // Yay! - MODE_PREEMPTIVE; - - // Yay! - CAN_TAKE_LOCK; - - // Yay! - ASSERT_NO_EE_LOCKS_HELD(); - - } - CONTRACTL_END; - - CLR_TO_PROFILER_ENTRYPOINT((LF_CORPROF, - LL_INFO1000, - "**PROF: RemotingServerSendingReply. ThreadID: 0x%p\n", - GetThreadNULLOk())); - - { - // All callbacks are really NOTHROW, but that's enforced partially by the profiler, - // whose try/catch blocks aren't visible to the contract system - PERMANENT_CONTRACT_VIOLATION(ThrowsViolation, ReasonProfilerCallout); - return m_pCallback2->RemotingServerSendingReply(pCookie, fIsAsync); - } -} - -//--------------------------------------------------------------------------------------- // GC EVENTS // @@ -6354,4 +6042,31 @@ HRESULT EEToProfInterfaceImpl::EventPipeProviderCreated(EventPipeProvider *provi #endif // FEATURE_PERFTRACING } +HRESULT EEToProfInterfaceImpl::LoadAsNotficationOnly(BOOL *pbNotificationOnly) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + // This one API is special, we call in to the profiler before we've set up any of our + // machinery to do asserts (m_pProfilerInfo in specific). So we can't use + // CLR_TO_PROFILER_ENTRYPOINT here. + + LOG((LF_CORPROF, + LL_INFO1000, + "**PROF: LoadAsNotficationOnly.\n")); + + if (m_pCallback11 == NULL) + { + *pbNotificationOnly = FALSE; + return S_OK; + } + + return m_pCallback11->LoadAsNotficationOnly(pbNotificationOnly); +} + #endif // PROFILING_SUPPORTED diff --git a/src/coreclr/vm/eetoprofinterfaceimpl.h b/src/coreclr/vm/eetoprofinterfaceimpl.h index c43b8599465..4ec468a4150 100644 --- a/src/coreclr/vm/eetoprofinterfaceimpl.h +++ b/src/coreclr/vm/eetoprofinterfaceimpl.h @@ -33,10 +33,9 @@ class ProfToEEInterfaceImpl; interface IAssemblyBindingClosure; struct AssemblyReferenceClosureWalkContextForProfAPI; -const GUID k_guidZero = {0}; - class EEToProfInterfaceImpl { + friend class ProfControlBlock; public: // @@ -54,6 +53,8 @@ public: BOOL fLoadedViaAttach, DWORD dwConcurrentGCWaitTimeoutInMs); + void SetProfilerInfo(ProfilerInfo *pProfilerInfo); + BOOL IsCallback3Supported(); BOOL IsCallback4Supported(); BOOL IsCallback5Supported(); @@ -118,15 +119,6 @@ public: UINT_PTR EEFunctionIDMapper(FunctionID funcId, BOOL * pbHookFunction); - // This fills in the non call-specific portions of the cookie GUID. - // This should only be called once at startup if necessary. - HRESULT InitGUID(); - - // This will assign a mostly-unique GUID. If enough calls to GetGUID - // are made from the same thread, then the GUIDs will cycle. - // (Current, it will cycle every 256 calls) - void GetGUID(GUID * pGUID); - // // Initialize callback // @@ -377,31 +369,6 @@ public: /* [in] */ void * pVTable); // - // Remoting Events - // - - HRESULT RemotingClientInvocationStarted(); - - HRESULT RemotingClientSendingMessage(GUID * pCookie, - BOOL fIsAsync); - - HRESULT RemotingClientReceivingReply(GUID * pCookie, - BOOL fIsAsync); - - HRESULT RemotingClientInvocationFinished(); - - HRESULT RemotingServerReceivingMessage(GUID * pCookie, - BOOL fIsAsync); - - HRESULT RemotingServerInvocationStarted(); - - HRESULT RemotingServerInvocationReturned(); - - HRESULT RemotingServerSendingReply(GUID * pCookie, - BOOL fIsAsync); - - - // // GC Events // @@ -507,6 +474,8 @@ public: HRESULT EventPipeProviderCreated(EventPipeProvider *provider); + HRESULT LoadAsNotficationOnly(BOOL *pbNotificationOnly); + private: // @@ -578,6 +547,7 @@ private: ICorProfilerCallback8 * m_pCallback8; ICorProfilerCallback9 * m_pCallback9; ICorProfilerCallback10 * m_pCallback10; + ICorProfilerCallback11 * m_pCallback11; HMODULE m_hmodProfilerDLL; @@ -589,13 +559,6 @@ private: FunctionIDMapper2 * m_pProfilersFuncIDMapper2; void * m_pProfilersFuncIDMapper2ClientData; - // This is used as a cookie template for remoting calls - GUID m_GUID; - - // This is an incrementing counter for constructing unique GUIDS from - // m_GUID - LONG m_lGUIDCount; - // This will contain a list of free ref data structs, so they // don't have to be re-allocated on every GC GCReferencesData * m_pGCRefDataFreeList; @@ -628,6 +591,7 @@ private: // Remember whether the profiler has enabled Rejit, and prevent detach if it has. BOOL m_fModifiedRejitState; + ProfilerInfo *m_pProfilerInfo; GCReferencesData * AllocateMovedReferencesData(); diff --git a/src/coreclr/vm/eetoprofinterfaceimpl.inl b/src/coreclr/vm/eetoprofinterfaceimpl.inl index 48a07b5a237..1ed73db1f58 100644 --- a/src/coreclr/vm/eetoprofinterfaceimpl.inl +++ b/src/coreclr/vm/eetoprofinterfaceimpl.inl @@ -247,7 +247,7 @@ inline BOOL EEToProfInterfaceImpl::RequiresGenericsContextForEnterLeave() return CORProfilerPresent() && - ((g_profControlBlock.dwEventMask & COR_PRF_ENABLE_FRAME_INFO) != 0) && + ((&g_profControlBlock)->globalEventMask.IsEventMaskSet(COR_PRF_ENABLE_FRAME_INFO)) && ( (m_pEnter2 != NULL) || (m_pLeave2 != NULL) || diff --git a/src/coreclr/vm/eetoprofinterfacewrapper.inl b/src/coreclr/vm/eetoprofinterfacewrapper.inl index bdf328e4c7a..afa00001b17 100644 --- a/src/coreclr/vm/eetoprofinterfacewrapper.inl +++ b/src/coreclr/vm/eetoprofinterfacewrapper.inl @@ -32,15 +32,15 @@ class EEToProfilerExceptionInterfaceWrapper { WRAPPER_NO_CONTRACT; { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); _ASSERTE(pThread->PreemptiveGCDisabled()); // Get a reference to the object that won't move OBJECTREF thrown = pThread->GetThrowable(); - g_profControlBlock.pProfInterface->ExceptionThrown( + (&g_profControlBlock)->ExceptionThrown( reinterpret_cast<ObjectID>((*(BYTE **)&thrown))); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } @@ -53,14 +53,14 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler of the function being searched for a handler. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); if (!pFunction->IsNoMetadata()) { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ExceptionSearchFunctionEnter( + (&g_profControlBlock)->ExceptionSearchFunctionEnter( (FunctionID) pFunction); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } @@ -69,13 +69,13 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler of the function being searched for a handler. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); if (!pFunction->IsNoMetadata()) { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ExceptionSearchFunctionLeave(); + (&g_profControlBlock)->ExceptionSearchFunctionLeave(); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } @@ -84,14 +84,14 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler of the filter. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); if (!pFunc->IsNoMetadata()) { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ExceptionSearchFilterEnter( + (&g_profControlBlock)->ExceptionSearchFilterEnter( (FunctionID) pFunc); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } @@ -100,10 +100,10 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler of the filter. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); GCX_PREEMP(); - g_profControlBlock.pProfInterface->ExceptionSearchFilterLeave(); - END_PIN_PROFILER(); + (&g_profControlBlock)->ExceptionSearchFilterLeave(); + END_PROFILER_CALLBACK(); } } @@ -111,14 +111,14 @@ class EEToProfilerExceptionInterfaceWrapper { WRAPPER_NO_CONTRACT; { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); if (!pFunc->IsNoMetadata()) { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ExceptionSearchCatcherFound( + (&g_profControlBlock)->ExceptionSearchCatcherFound( (FunctionID) pFunc); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } @@ -130,13 +130,13 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler of the function being searched for a handler. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); if (!pFunc->IsNoMetadata()) { - g_profControlBlock.pProfInterface->ExceptionUnwindFunctionEnter( + (&g_profControlBlock)->ExceptionUnwindFunctionEnter( (FunctionID) pFunc); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } @@ -145,12 +145,12 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler that searching this function is over. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); if (!pFunction->IsNoMetadata()) { - g_profControlBlock.pProfInterface->ExceptionUnwindFunctionLeave(); + (&g_profControlBlock)->ExceptionUnwindFunctionLeave(); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } @@ -159,13 +159,13 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler of the function being searched for a handler. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); if (!pFunc->IsNoMetadata()) { - g_profControlBlock.pProfInterface->ExceptionUnwindFinallyEnter( + (&g_profControlBlock)->ExceptionUnwindFinallyEnter( (FunctionID) pFunc); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } @@ -174,9 +174,9 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler of the function being searched for a handler. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); - g_profControlBlock.pProfInterface->ExceptionUnwindFinallyLeave(); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); + (&g_profControlBlock)->ExceptionUnwindFinallyLeave(); + END_PROFILER_CALLBACK(); } } @@ -185,7 +185,7 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); if (!pFunc->IsNoMetadata()) { // <TODO>Remove the thrown variable as well as the @@ -197,13 +197,13 @@ class EEToProfilerExceptionInterfaceWrapper GCPROTECT_BEGIN(thrown); thrown = pThread->GetThrowable(); { - g_profControlBlock.pProfInterface->ExceptionCatcherEnter( + (&g_profControlBlock)->ExceptionCatcherEnter( (FunctionID) pFunc, reinterpret_cast<ObjectID>((*(BYTE **)&thrown))); } GCPROTECT_END(); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } @@ -212,9 +212,9 @@ class EEToProfilerExceptionInterfaceWrapper WRAPPER_NO_CONTRACT; // Notify the profiler of the function being searched for a handler. { - BEGIN_PIN_PROFILER(CORProfilerTrackExceptions()); - g_profControlBlock.pProfInterface->ExceptionCatcherLeave(); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackExceptions()); + (&g_profControlBlock)->ExceptionCatcherLeave(); + END_PROFILER_CALLBACK(); } } diff --git a/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h index 58263ae1a79..8094d7b22d9 100644 --- a/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ds-rt-coreclr.h @@ -310,10 +310,12 @@ ds_rt_profiler_startup (DiagnosticsStartupProfilerCommandPayload *payload) STATIC_CONTRACT_NOTHROW; HRESULT hr = S_OK; - EX_TRY { - memcpy(&(g_profControlBlock.clsStoredProfilerGuid), reinterpret_cast<const CLSID *>(ds_startup_profiler_command_payload_get_profiler_guid_cref (payload)), sizeof(CLSID)); - g_profControlBlock.sStoredProfilerPath.Set(reinterpret_cast<LPCWSTR>(ds_startup_profiler_command_payload_get_profiler_path (payload))); - g_profControlBlock.fIsStoredProfilerRegistered = TRUE; + EX_TRY { + StoredProfilerNode *profilerData = new StoredProfilerNode(); + profilerData->guid = *(reinterpret_cast<const CLSID *>(ds_startup_profiler_command_payload_get_profiler_guid_cref (payload))); + profilerData->path.Set(reinterpret_cast<LPCWSTR>(ds_startup_profiler_command_payload_get_profiler_path (payload))); + + g_profControlBlock.storedProfilers.InsertHead(profilerData); } EX_CATCH_HRESULT (hr); diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h index be90259da1d..607286d048b 100644 --- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h @@ -1661,9 +1661,9 @@ ep_rt_notify_profiler_provider_created (EventPipeProvider *provider) #ifndef DACCESS_COMPILE // Let the profiler know the provider has been created so it can register if it wants to - BEGIN_PIN_PROFILER (CORProfilerIsMonitoringEventPipe ()); - g_profControlBlock.pProfInterface->EventPipeProviderCreated (provider); - END_PIN_PROFILER (); + BEGIN_PROFILER_CALLBACK (CORProfilerTrackEventPipe ()); + (&g_profControlBlock)->EventPipeProviderCreated (provider); + END_PROFILER_CALLBACK (); #endif // DACCESS_COMPILE } diff --git a/src/coreclr/vm/eventpipeadapter.h b/src/coreclr/vm/eventpipeadapter.h index 1510622a265..28a0c9fb1d6 100644 --- a/src/coreclr/vm/eventpipeadapter.h +++ b/src/coreclr/vm/eventpipeadapter.h @@ -200,7 +200,8 @@ public: EventPipeSerializationFormat format, const bool rundownRequested, IpcStream *const stream, - EventPipeSessionSynchronousCallback callback) + EventPipeSessionSynchronousCallback callback, + void *callbackAdditionalData) { CONTRACTL { @@ -222,7 +223,8 @@ public: format, rundownRequested, stream, - callback); + callback, + callbackAdditionalData); ep_rt_utf8_string_free (outputPathUTF8); return result; } diff --git a/src/coreclr/vm/eventpipeinternal.cpp b/src/coreclr/vm/eventpipeinternal.cpp index 7d0e429be2e..7097cb6208d 100644 --- a/src/coreclr/vm/eventpipeinternal.cpp +++ b/src/coreclr/vm/eventpipeinternal.cpp @@ -42,6 +42,7 @@ UINT64 QCALLTYPE EventPipeInternal::Enable( format, true, nullptr, + nullptr, nullptr); EventPipeAdapter::StartStreaming(sessionID); } diff --git a/src/coreclr/vm/eventtrace.cpp b/src/coreclr/vm/eventtrace.cpp index 99620ac07e2..14bd22538d2 100644 --- a/src/coreclr/vm/eventtrace.cpp +++ b/src/coreclr/vm/eventtrace.cpp @@ -682,13 +682,13 @@ void ETW::GCLog::MovedReference( // ProfAPI if (fAllowProfApiNotification) { - BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackGCMovedObjects()); - g_profControlBlock.pProfInterface->MovedReference(pbMemBlockStart, + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC() || CORProfilerTrackGCMovedObjects()); + (&g_profControlBlock)->MovedReference(pbMemBlockStart, pbMemBlockEnd, cbRelocDistance, &(pCtxForEtwAndProfapi->pctxProfAPI), fCompacting); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -808,9 +808,9 @@ VOID ETW::GCLog::EndMovedReferences(size_t profilingContext, BOOL fAllowProfApiN // ProfAPI if (fAllowProfApiNotification) { - BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackGCMovedObjects()); - g_profControlBlock.pProfInterface->EndMovedReferences(&(pCtxForEtwAndProfapi->pctxProfAPI)); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC() || CORProfilerTrackGCMovedObjects()); + (&g_profControlBlock)->EndMovedReferences(&(pCtxForEtwAndProfapi->pctxProfAPI)); + END_PROFILER_CALLBACK(); } #endif //PROFILING_SUPPORTED diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp index 4df3e3ae1cb..5be5bc2d9ec 100644 --- a/src/coreclr/vm/gcenv.ee.cpp +++ b/src/coreclr/vm/gcenv.ee.cpp @@ -559,7 +559,7 @@ BOOL ProfilerShouldTrackConditionalWeakTableElements() void ProfilerEndConditionalWeakTableElementReferences(void* heapId) { #if defined (GC_PROFILING) - g_profControlBlock.pProfInterface->EndConditionalWeakTableElementReferences(heapId); + (&g_profControlBlock)->EndConditionalWeakTableElementReferences(heapId); #else UNREFERENCED_PARAMETER(heapId); #endif // defined (GC_PROFILING) @@ -570,7 +570,7 @@ void ProfilerEndConditionalWeakTableElementReferences(void* heapId) void ProfilerEndRootReferences2(void* heapId) { #if defined (GC_PROFILING) - g_profControlBlock.pProfInterface->EndRootReferences2(heapId); + (&g_profControlBlock)->EndRootReferences2(heapId); #else UNREFERENCED_PARAMETER(heapId); #endif // defined (GC_PROFILING) @@ -603,24 +603,24 @@ void ScanHandleForProfilerAndETW(Object** pRef, Object* pSec, uint32_t flags, Sc { if (!isDependent) { - BEGIN_PIN_PROFILER(CORProfilerTrackGC()); - g_profControlBlock.pProfInterface->RootReference2( + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC()); + (&g_profControlBlock)->RootReference2( (uint8_t *)*pRef, kEtwGCRootKindHandle, (EtwGCRootFlags)flags, pRef, &pSC->pHeapId); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } else { - BEGIN_PIN_PROFILER(CORProfilerTrackConditionalWeakTableElements()); - g_profControlBlock.pProfInterface->ConditionalWeakTableElementReference( + BEGIN_PROFILER_CALLBACK(CORProfilerTrackConditionalWeakTableElements()); + (&g_profControlBlock)->ConditionalWeakTableElementReference( (uint8_t*)*pRef, (uint8_t*)pSec, pRef, &pSC->pHeapId); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } #endif // GC_PROFILING @@ -739,10 +739,10 @@ void GCProfileWalkHeap(bool etwOnly) #if defined (GC_PROFILING) { - BEGIN_PIN_PROFILER(!etwOnly && CORProfilerTrackGC()); + BEGIN_PROFILER_CALLBACK(!etwOnly && CORProfilerTrackGC()); GCProfileWalkHeapWorker(TRUE /* fProfilerPinned */, fShouldWalkHeapRootsForEtw, fShouldWalkHeapObjectsForEtw); fWalkedHeapForProfiler = TRUE; - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // defined (GC_PROFILING) @@ -759,7 +759,7 @@ void GCProfileWalkHeap(bool etwOnly) void WalkFReachableObjects(bool isCritical, void* objectID) { - g_profControlBlock.pProfInterface->FinalizeableObjectQueued(isCritical, (ObjectID)objectID); + (&g_profControlBlock)->FinalizeableObjectQueued(isCritical, (ObjectID)objectID); } static fq_walk_fn g_FQWalkFn = &WalkFReachableObjects; @@ -770,7 +770,7 @@ void GCToEEInterface::DiagGCStart(int gen, bool isInduced) DiagUpdateGenerationBounds(); GarbageCollectionStartedCallback(gen, isInduced); { - BEGIN_PIN_PROFILER(CORProfilerTrackGC()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC()); size_t context = 0; // When we're walking objects allocated by class, then we don't want to walk the large @@ -778,8 +778,8 @@ void GCToEEInterface::DiagGCStart(int gen, bool isInduced) GCHeapUtilities::GetGCHeap()->DiagWalkHeap(&AllocByClassHelper, (void *)&context, 0, false); // Notify that we've reached the end of the Gen 0 scan - g_profControlBlock.pProfInterface->EndAllocByClass(&context); - END_PIN_PROFILER(); + (&g_profControlBlock)->EndAllocByClass(&context); + END_PROFILER_CALLBACK(); } #endif // GC_PROFILING @@ -815,12 +815,9 @@ void GCToEEInterface::DiagGCEnd(size_t index, int gen, int reason, bool fConcurr void GCToEEInterface::DiagWalkFReachableObjects(void* gcContext) { #ifdef GC_PROFILING - if (CORProfilerTrackGC()) - { - BEGIN_PIN_PROFILER(CORProfilerPresent()); - GCHeapUtilities::GetGCHeap()->DiagWalkFinalizeQueue(gcContext, g_FQWalkFn); - END_PIN_PROFILER(); - } + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC()); + GCHeapUtilities::GetGCHeap()->DiagWalkFinalizeQueue(gcContext, g_FQWalkFn); + END_PROFILER_CALLBACK(); #endif //GC_PROFILING } diff --git a/src/coreclr/vm/gchandleutilities.cpp b/src/coreclr/vm/gchandleutilities.cpp index 2086dacdc62..dcc3682e5b3 100644 --- a/src/coreclr/vm/gchandleutilities.cpp +++ b/src/coreclr/vm/gchandleutilities.cpp @@ -22,9 +22,9 @@ void ValidateHandleAssignment(OBJECTHANDLE handle, OBJECTREF objRef) void DiagHandleCreated(OBJECTHANDLE handle, OBJECTREF objRef) { #ifdef GC_PROFILING - BEGIN_PIN_PROFILER(CORProfilerTrackGC()); - g_profControlBlock.pProfInterface->HandleCreated((uintptr_t)handle, (ObjectID)OBJECTREF_TO_UNCHECKED_OBJECTREF(objRef)); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC()); + (&g_profControlBlock)->HandleCreated((uintptr_t)handle, (ObjectID)OBJECTREF_TO_UNCHECKED_OBJECTREF(objRef)); + END_PROFILER_CALLBACK(); #else UNREFERENCED_PARAMETER(handle); UNREFERENCED_PARAMETER(objRef); @@ -34,9 +34,9 @@ void DiagHandleCreated(OBJECTHANDLE handle, OBJECTREF objRef) void DiagHandleDestroyed(OBJECTHANDLE handle) { #ifdef GC_PROFILING - BEGIN_PIN_PROFILER(CORProfilerTrackGC()); - g_profControlBlock.pProfInterface->HandleDestroyed((uintptr_t)handle); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC()); + (&g_profControlBlock)->HandleDestroyed((uintptr_t)handle); + END_PROFILER_CALLBACK(); #else UNREFERENCED_PARAMETER(handle); #endif // GC_PROFILING diff --git a/src/coreclr/vm/genanalysis.cpp b/src/coreclr/vm/genanalysis.cpp index 29cb5fc5a6f..fa2fcdf0a22 100644 --- a/src/coreclr/vm/genanalysis.cpp +++ b/src/coreclr/vm/genanalysis.cpp @@ -81,6 +81,7 @@ uint32_t gcGenAnalysisBufferMB = 0; EP_SERIALIZATION_FORMAT_NETTRACE_V4, false, nullptr, + nullptr, nullptr ); if (gcGenAnalysisEventPipeSessionId > 0) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 9250f436b4b..cb5fe80e0c4 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -7738,12 +7738,12 @@ getMethodInfoHelper( #if defined(PROFILING_SUPPORTED) BOOL fProfilerRequiresGenericsContextForEnterLeave = FALSE; { - BEGIN_PIN_PROFILER(CORProfilerPresent()); - if (g_profControlBlock.pProfInterface->RequiresGenericsContextForEnterLeave()) + BEGIN_PROFILER_CALLBACK(CORProfilerPresent()); + if ((&g_profControlBlock)->RequiresGenericsContextForEnterLeave()) { fProfilerRequiresGenericsContextForEnterLeave = TRUE; } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } if (fProfilerRequiresGenericsContextForEnterLeave) { @@ -8134,7 +8134,7 @@ CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller, // profiler that this inlining is going to take place, and give them a // chance to prevent it. { - BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackJITInfo()); if (pCaller->IsILStub() || pCallee->IsILStub()) { // do nothing @@ -8142,7 +8142,7 @@ CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller, else { BOOL fShouldInline; - HRESULT hr = g_profControlBlock.pProfInterface->JITInlining( + HRESULT hr = (&g_profControlBlock)->JITInlining( (FunctionID)pCaller, (FunctionID)pCallee, &fShouldInline); @@ -8154,7 +8154,7 @@ CorInfoInline CEEInfo::canInline (CORINFO_METHOD_HANDLE hCaller, goto exit; } } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } #endif // PROFILING_SUPPORTED @@ -11184,9 +11184,9 @@ void CEEJitInfo::GetProfilingHandle(bool *pbHookFunction, void * profilerHandle = m_pMethodBeingCompiled; { - BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled()); - profilerHandle = (void *)g_profControlBlock.pProfInterface->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerFunctionIDMapperEnabled()); + profilerHandle = (void *)(&g_profControlBlock)->EEFunctionIDMapper((FunctionID) m_pMethodBeingCompiled, &bHookFunction); + END_PROFILER_CALLBACK(); } m_gphCache.m_pvGphProfilerHandle = profilerHandle; @@ -13961,9 +13961,9 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, CORINFO_PROFILING_HANDLE profilerHandle = (CORINFO_PROFILING_HANDLE)funId; { - BEGIN_PIN_PROFILER(CORProfilerFunctionIDMapperEnabled()); - profilerHandle = (CORINFO_PROFILING_HANDLE) g_profControlBlock.pProfInterface->EEFunctionIDMapper(funId, &bHookFunction); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerFunctionIDMapperEnabled()); + profilerHandle = (CORINFO_PROFILING_HANDLE)(&g_profControlBlock)->EEFunctionIDMapper(funId, &bHookFunction); + END_PROFILER_CALLBACK(); } // Profiling handle is opaque token. It does not have to be aligned thus we can not store it in the same location as token. diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index f75d62bdef2..20f5cbfaf72 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -537,9 +537,9 @@ PCODE MethodDesc::GetPrecompiledNgenCode(PrepareCodeConfig* pConfig) { BOOL fShouldSearchCache = TRUE; { - BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches()); - g_profControlBlock.pProfInterface->JITCachedFunctionSearchStarted((FunctionID)this, &fShouldSearchCache); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackCacheSearches()); + (&g_profControlBlock)->JITCachedFunctionSearchStarted((FunctionID)this, &fShouldSearchCache); + END_PROFILER_CALLBACK(); } if (!fShouldSearchCache) @@ -585,10 +585,10 @@ PCODE MethodDesc::GetPrecompiledNgenCode(PrepareCodeConfig* pConfig) * cached jitted function has been made. */ { - BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches()); - g_profControlBlock.pProfInterface-> + BEGIN_PROFILER_CALLBACK(CORProfilerTrackCacheSearches()); + (&g_profControlBlock)-> JITCachedFunctionSearchFinished((FunctionID)this, COR_PRF_CACHED_FUNCTION_FOUND); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -866,7 +866,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackJITInfo()); // For methods with non-zero rejit id we send ReJITCompilationStarted, otherwise // JITCompilationStarted. It isn't clear if this is the ideal policy for these // notifications yet. @@ -875,7 +875,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J if (rejitId != 0) { _ASSERTE(!nativeCodeVersion.IsDefaultVersion()); - g_profControlBlock.pProfInterface->ReJITCompilationStarted((FunctionID)this, + (&g_profControlBlock)->ReJITCompilationStarted((FunctionID)this, rejitId, TRUE); } @@ -886,7 +886,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J { if (!IsNoMetadata()) { - g_profControlBlock.pProfInterface->JITCompilationStarted((FunctionID)this, TRUE); + (&g_profControlBlock)->JITCompilationStarted((FunctionID)this, TRUE); } else @@ -895,7 +895,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J CorInfoOptions corOptions; LPCBYTE ilHeaderPointer = this->AsDynamicMethodDesc()->GetResolver()->GetCodeInfo(&ilSize, &unused, &corOptions, &unused); - g_profControlBlock.pProfInterface->DynamicMethodJITCompilationStarted((FunctionID)this, TRUE, ilHeaderPointer, ilSize); + (&g_profControlBlock)->DynamicMethodJITCompilationStarted((FunctionID)this, TRUE, ilHeaderPointer, ilSize); } if (nativeCodeVersion.IsDefaultVersion()) @@ -903,7 +903,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J pConfig->SetProfilerMayHaveActivatedNonDefaultCodeVersion(); } } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -955,7 +955,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackJITInfo()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackJITInfo()); // For methods with non-zero rejit id we send ReJITCompilationFinished, otherwise // JITCompilationFinished. It isn't clear if this is the ideal policy for these // notifications yet. @@ -964,7 +964,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J if (rejitId != 0) { _ASSERTE(!nativeCodeVersion.IsDefaultVersion()); - g_profControlBlock.pProfInterface->ReJITCompilationFinished((FunctionID)this, + (&g_profControlBlock)->ReJITCompilationFinished((FunctionID)this, rejitId, S_OK, TRUE); @@ -976,14 +976,14 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J { if (!IsNoMetadata()) { - g_profControlBlock.pProfInterface-> + (&g_profControlBlock)-> JITCompilationFinished((FunctionID)this, pEntry->m_hrResultCode, TRUE); } else { - g_profControlBlock.pProfInterface->DynamicMethodJITCompilationFinished((FunctionID)this, pEntry->m_hrResultCode, TRUE); + (&g_profControlBlock)->DynamicMethodJITCompilationFinished((FunctionID)this, pEntry->m_hrResultCode, TRUE); } if (nativeCodeVersion.IsDefaultVersion()) @@ -991,7 +991,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J pConfig->SetProfilerMayHaveActivatedNonDefaultCodeVersion(); } } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED diff --git a/src/coreclr/vm/profdetach.cpp b/src/coreclr/vm/profdetach.cpp index 392fde6c0a1..0161bef9529 100644 --- a/src/coreclr/vm/profdetach.cpp +++ b/src/coreclr/vm/profdetach.cpp @@ -19,9 +19,9 @@ #include "eetoprofinterfaceimpl.inl" // Class static member variables -ProfilerDetachInfo ProfilingAPIDetach::s_profilerDetachInfo; -CLREvent ProfilingAPIDetach::s_eventDetachWorkAvailable; - +CQuickArrayList<ProfilerDetachInfo> ProfilingAPIDetach::s_profilerDetachInfos; +CLREvent ProfilingAPIDetach::s_eventDetachWorkAvailable; +Volatile<BOOL> ProfilingAPIDetach::s_profilerDetachThreadCreated; // --------------------------------------------------------------------------------------- // ProfilerDetachInfo constructor @@ -49,7 +49,7 @@ void ProfilerDetachInfo::Init() // use real contracts, as this requires that utilcode has been initialized. STATIC_CONTRACT_LEAF; - m_pEEToProf = NULL; + m_pProfilerInfo = NULL; m_ui64DetachStartTime = 0; m_dwExpectedCompletionMilliseconds = 0; } @@ -145,7 +145,7 @@ HRESULT ProfilingAPIDetach::Initialize() // // static -HRESULT ProfilingAPIDetach::RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds) +HRESULT ProfilingAPIDetach::RequestProfilerDetach(ProfilerInfo *pProfilerInfo, DWORD dwExpectedCompletionMilliseconds) { CONTRACTL { @@ -178,14 +178,19 @@ HRESULT ProfilingAPIDetach::RequestProfilerDetach(DWORD dwExpectedCompletionMill { CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst()); - // return immediately if detach is in progress + EEToProfInterfaceImpl *pEEToProf = pProfilerInfo->pProfInterface; - if (s_profilerDetachInfo.m_pEEToProf != NULL) + // return immediately if detach is in progress + for (SIZE_T pos = 0; pos < s_profilerDetachInfos.Size(); ++pos) { - return CORPROF_E_PROFILER_DETACHING; + ProfilerDetachInfo ¤t = s_profilerDetachInfos[pos]; + if (current.m_pProfilerInfo->pProfInterface == pEEToProf) + { + return CORPROF_E_PROFILER_DETACHING; + } } - ProfilerStatus curProfStatus = g_profControlBlock.curProfStatus.Get(); + ProfilerStatus curProfStatus = pProfilerInfo->curProfStatus.Get(); if ((curProfStatus == kProfStatusInitializingForStartupLoad) || (curProfStatus == kProfStatusInitializingForAttachLoad)) @@ -201,8 +206,6 @@ HRESULT ProfilingAPIDetach::RequestProfilerDetach(DWORD dwExpectedCompletionMill return CORPROF_E_PROFILER_DETACHING; } - EEToProfInterfaceImpl * pEEToProf = g_profControlBlock.pProfInterface; - // Since prof status was active after entering the lock, the profiler must not // have unloaded out from under us. _ASSERTE(pEEToProf != NULL); @@ -219,13 +222,25 @@ HRESULT ProfilingAPIDetach::RequestProfilerDetach(DWORD dwExpectedCompletionMill { return hr; } - s_profilerDetachInfo.m_pEEToProf = pEEToProf; - s_profilerDetachInfo.m_ui64DetachStartTime = CLRGetTickCount64(); - s_profilerDetachInfo.m_dwExpectedCompletionMilliseconds = dwExpectedCompletionMilliseconds; + + EX_TRY + { + ProfilerDetachInfo detachInfo; + detachInfo.m_pProfilerInfo = pProfilerInfo; + detachInfo.m_ui64DetachStartTime = CLRGetTickCount64(); + detachInfo.m_dwExpectedCompletionMilliseconds = dwExpectedCompletionMilliseconds; + s_profilerDetachInfos.Push(detachInfo); + } + EX_CATCH_HRESULT(hr); + + if (FAILED(hr)) + { + return hr; + } // Ok, time to seal the profiler from receiving or making calls with the CLR. // (This will force a FlushStoreBuffers().) - g_profControlBlock.curProfStatus.Set(kProfStatusDetaching); + pProfilerInfo->curProfStatus.Set(kProfStatusDetaching); } // Sealing done. Wake up the DetachThread so it can loop until the profiler code is @@ -274,58 +289,58 @@ void ProfilingAPIDetach::ExecuteEvacuationLoop() } CONTRACTL_END; - // Wait until there's a profiler to detach (or until this thread should "wake up" - // for some other reason, such as exiting due to an unsuccessful startup-load of a - // profiler). - DWORD dwRet = s_eventDetachWorkAvailable.Wait(INFINITE, FALSE /* alertable */); - if (dwRet != WAIT_OBJECT_0) + while (true) { - // The wait ended due to a failure or a reason other than the event getting - // signaled (e.g., WAIT_ABANDONED) - DWORD dwErr; - if (dwRet == WAIT_FAILED) + // Wait until there's a profiler to detach (or until this thread should "wake up" + // for some other reason, such as exiting due to an unsuccessful startup-load of a + // profiler). + DWORD dwRet = s_eventDetachWorkAvailable.Wait(INFINITE, FALSE /* alertable */); + if (dwRet != WAIT_OBJECT_0) { - dwErr = GetLastError(); - LOG(( - LF_CORPROF, - LL_ERROR, - "**PROF: DetachThread wait for s_eventDetachWorkAvailable failed with GetLastError = %d.\n", - dwErr)); + // The wait ended due to a failure or a reason other than the event getting + // signaled (e.g., WAIT_ABANDONED) + DWORD dwErr; + if (dwRet == WAIT_FAILED) + { + dwErr = GetLastError(); + LOG(( + LF_CORPROF, + LL_ERROR, + "**PROF: DetachThread wait for s_eventDetachWorkAvailable failed with GetLastError = %d.\n", + dwErr)); + } + else + { + dwErr = dwRet; // No extra error info available beyond the return code + LOG(( + LF_CORPROF, + LL_ERROR, + "**PROF: DetachThread wait for s_eventDetachWorkAvailable terminated with %d.\n", + dwErr)); + } + + ProfilingAPIUtility::LogProfError(IDS_PROF_DETACH_THREAD_ERROR, dwErr); + return; } - else + { - dwErr = dwRet; // No extra error info available beyond the return code - LOG(( - LF_CORPROF, - LL_ERROR, - "**PROF: DetachThread wait for s_eventDetachWorkAvailable terminated with %d.\n", - dwErr)); - } + CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst()); - ProfilingAPIUtility::LogProfError(IDS_PROF_DETACH_THREAD_ERROR, dwErr); - return; - } + for (SIZE_T pos = 0; pos < s_profilerDetachInfos.Size(); ++pos) + { + ProfilerDetachInfo current = s_profilerDetachInfos.Pop(); - // Peek to make sure there's actually a profiler to detach - { - CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst()); + do + { + // Give profiler a chance to return from its procs + SleepWhileProfilerEvacuates(¤t); + } + while (!ProfilingAPIUtility::IsProfilerEvacuated(current.m_pProfilerInfo)); - if (s_profilerDetachInfo.m_pEEToProf == NULL) - { - // Nothing to detach. This can happen if the DetachThread (i.e., current - // thread) was created but then the profiler failed to load. - return; + UnloadProfiler(¤t); + } } } - - do - { - // Give profiler a chance to return from its procs - SleepWhileProfilerEvacuates(); - } - while (!ProfilingAPIUtility::IsProfilerEvacuated()); - - UnloadProfiler(); } //--------------------------------------------------------------------------------------- @@ -335,7 +350,7 @@ void ProfilingAPIDetach::ExecuteEvacuationLoop() // // static -void ProfilingAPIDetach::SleepWhileProfilerEvacuates() +void ProfilingAPIDetach::SleepWhileProfilerEvacuates(ProfilerDetachInfo *pDetachInfo) { CONTRACTL { @@ -398,9 +413,9 @@ void ProfilingAPIDetach::SleepWhileProfilerEvacuates() { CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst()); - _ASSERTE(s_profilerDetachInfo.m_pEEToProf != NULL); - ui64ExpectedCompletionMilliseconds = s_profilerDetachInfo.m_dwExpectedCompletionMilliseconds; - ui64DetachStartTime = s_profilerDetachInfo.m_ui64DetachStartTime; + _ASSERTE(pDetachInfo->m_pProfilerInfo != NULL); + ui64ExpectedCompletionMilliseconds = pDetachInfo->m_dwExpectedCompletionMilliseconds; + ui64DetachStartTime = pDetachInfo->m_ui64DetachStartTime; } // ui64SleepMilliseconds is calculated to ensure that CLR checks evacuation status roughly: @@ -456,7 +471,7 @@ void ProfilingAPIDetach::SleepWhileProfilerEvacuates() // // static -void ProfilingAPIDetach::UnloadProfiler() +void ProfilingAPIDetach::UnloadProfiler(ProfilerDetachInfo *pDetachInfo) { CONTRACTL { @@ -467,27 +482,39 @@ void ProfilingAPIDetach::UnloadProfiler() } CONTRACTL_END; - _ASSERTE(g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching); + _ASSERTE(pDetachInfo->m_pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching); { CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst()); // Notify profiler it's about to be unloaded - _ASSERTE(s_profilerDetachInfo.m_pEEToProf != NULL); - s_profilerDetachInfo.m_pEEToProf->ProfilerDetachSucceeded(); - - // Reset detach state. - s_profilerDetachInfo.Init(); + _ASSERTE(pDetachInfo->m_pProfilerInfo != NULL); + + { + // This EvacuationCounterHolder is just to make asserts in EEToProfInterfaceImpl happy. + // Using it like this without the dirty read/evac counter increment/clean read pattern + // is not safe generally, but in this specific case we can skip all that since we are in + // a critical section and are the only ones with access to the ProfilerInfo * + EvacuationCounterHolder evacuationCounter(pDetachInfo->m_pProfilerInfo); + pDetachInfo->m_pProfilerInfo->pProfInterface->ProfilerDetachSucceeded(); + } + + EEToProfInterfaceImpl *pProfInterface = pDetachInfo->m_pProfilerInfo->pProfInterface.Load(); + pDetachInfo->m_pProfilerInfo->pProfInterface.Store(NULL); + delete pProfInterface; // This deletes the EEToProfInterfaceImpl object managing the detaching profiler, // releases the profiler's callback interfaces, unloads the profiler DLL, sets // the status to kProfStatusNone, and resets g_profControlBlock for use next time // a profiler tries to attach. // - // Note that s_profilerDetachInfo.Init() has already NULL'd out - // s_profilerDetachInfo.m_pEEToProf, so we won't have a dangling pointer to the + // Note that we've already NULL'd out + // pDetachInfo->m_pProfilerInfo->pProfInterface, so we won't have a dangling pointer to the // EEToProfInterfaceImpl that's about to be destroyed. - ProfilingAPIUtility::TerminateProfiling(); + ProfilingAPIUtility::TerminateProfiling(pDetachInfo->m_pProfilerInfo); + + // Reset detach state. + pDetachInfo->Init(); } ProfilingAPIUtility::LogProfInfo(IDS_PROF_DETACH_COMPLETE); @@ -570,56 +597,69 @@ HRESULT ProfilingAPIDetach::CreateDetachThread() NOTHROW; GC_NOTRIGGER; MODE_ANY; - CANNOT_TAKE_LOCK; + CAN_TAKE_LOCK; } CONTRACTL_END; - // FUTURE: When reattach with neutered profilers is implemented, this - // function should check if a DetachThread already exists (use synchronization - // to prevent race), and just return if so. - - HandleHolder hDetachThread; - - // The DetachThread is intentionally not an EE Thread-object thread (it won't - // execute managed code). - hDetachThread = ::CreateThread( - NULL, // lpThreadAttributes; don't want child processes inheriting this handle - 0, // dwStackSize (0 = use default) - ProfilingAPIDetachThreadStart, - NULL, // lpParameter (none to pass) - 0, // dwCreationFlags (0 = use default flags, start thread immediately) - NULL // lpThreadId (don't need therad ID) - ); - if (hDetachThread == NULL) + if (s_profilerDetachThreadCreated) + { + return S_OK; + } + { - DWORD dwErr = GetLastError(); + CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst()); + + if (!s_profilerDetachThreadCreated) + { + HandleHolder hDetachThread; + + // The DetachThread is intentionally not an EE Thread-object thread (it won't + // execute managed code). + hDetachThread = ::CreateThread( + NULL, // lpThreadAttributes; don't want child processes inheriting this handle + 0, // dwStackSize (0 = use default) + ProfilingAPIDetachThreadStart, + NULL, // lpParameter (none to pass) + 0, // dwCreationFlags (0 = use default flags, start thread immediately) + NULL // lpThreadId (don't need therad ID) + ); + if (hDetachThread == NULL) + { + DWORD dwErr = GetLastError(); - LOG(( - LF_CORPROF, - LL_ERROR, - "**PROF: Failed to create DetachThread. GetLastError=%d.\n", - dwErr)); + LOG(( + LF_CORPROF, + LL_ERROR, + "**PROF: Failed to create DetachThread. GetLastError=%d.\n", + dwErr)); - return HRESULT_FROM_WIN32(dwErr); + return HRESULT_FROM_WIN32(dwErr); + } + + s_profilerDetachThreadCreated = TRUE; + } } return S_OK; } -//--------------------------------------------------------------------------------------- -// -// Accessor for ProfilingAPIDetach::s_profilerDetachInfo.m_pEEToProf, which is the -// profiler being detached (or NULL if no profiler is being detached). -// -// Return Value: -// EEToProfInterfaceImpl * for the profiler being detached. -// - // static -EEToProfInterfaceImpl * ProfilingAPIDetach::GetEEToProfPtr() +BOOL ProfilingAPIDetach::IsEEToProfPtrRegisteredForDetach(EEToProfInterfaceImpl *pEEToProf) { LIMITED_METHOD_CONTRACT; - return s_profilerDetachInfo.m_pEEToProf; + + CRITSEC_Holder csh(ProfilingAPIUtility::GetStatusCrst()); + + for (SIZE_T pos = 0; pos < s_profilerDetachInfos.Size(); ++pos) + { + ProfilerDetachInfo ¤t = s_profilerDetachInfos[pos]; + if (current.m_pProfilerInfo->pProfInterface == pEEToProf) + { + return TRUE; + } + } + + return FALSE; } #endif // FEATURE_PROFAPI_ATTACH_DETACH diff --git a/src/coreclr/vm/profdetach.h b/src/coreclr/vm/profdetach.h index 7b85cb61c9d..5f97e4e59a9 100644 --- a/src/coreclr/vm/profdetach.h +++ b/src/coreclr/vm/profdetach.h @@ -24,13 +24,8 @@ struct ProfilerDetachInfo ProfilerDetachInfo(); void Init(); - // NULL if we're not trying to detach a profiler. Otherwise, this is the - // EEToProfInterfaceImpl instance we're detaching. - // - // FUTURE: Although m_pEEToProf, when non-NULL, is always the same as - // g_profControlBlock.pProfInterface, that will no longer be the case once we allow - // re-attach with neutered profilers. - EEToProfInterfaceImpl * m_pEEToProf; + // This is the profiler instance we're detaching. + ProfilerInfo *m_pProfilerInfo; // Time when profiler originally called RequestProfilerDetach() ULONGLONG m_ui64DetachStartTime; @@ -48,23 +43,25 @@ class ProfilingAPIDetach public: static HRESULT Initialize(); - static HRESULT RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds); + static HRESULT RequestProfilerDetach(ProfilerInfo *profilerInfo, DWORD dwExpectedCompletionMilliseconds); static HRESULT CreateDetachThread(); static DWORD WINAPI ProfilingAPIDetachThreadStart(LPVOID lpParameter); static void ExecuteEvacuationLoop(); - static EEToProfInterfaceImpl * GetEEToProfPtr(); + static BOOL IsEEToProfPtrRegisteredForDetach(EEToProfInterfaceImpl *pEEToProf); private: - static ProfilerDetachInfo s_profilerDetachInfo; + static CQuickArrayList<ProfilerDetachInfo> s_profilerDetachInfos; // Signaled by RequestProfilerDetach() when there is detach work ready to be // done by the DetachThread static CLREvent s_eventDetachWorkAvailable; - static void SleepWhileProfilerEvacuates(); - static void UnloadProfiler(); + static Volatile<BOOL> s_profilerDetachThreadCreated; + + static void SleepWhileProfilerEvacuates(ProfilerDetachInfo *pDetachInfo); + static void UnloadProfiler(ProfilerDetachInfo *pDetachInfo); // Prevent instantiation of ProfilingAPIDetach objects (should be static-only) ProfilingAPIDetach(); diff --git a/src/coreclr/vm/profilinghelper.cpp b/src/coreclr/vm/profilinghelper.cpp index ea1738f871a..ac2ea1469a4 100644 --- a/src/coreclr/vm/profilinghelper.cpp +++ b/src/coreclr/vm/profilinghelper.cpp @@ -52,9 +52,9 @@ // issue a profiler callback. Readers are scattered throughout the runtime, and have the // following format: // { -// BEGIN_PIN_PROFILER(CORProfilerTrackAppDomainLoads()); +// BEGIN_PROFILER_CALLBACK(CORProfilerTrackAppDomainLoads()); // g_profControlBlock.pProfInterface->AppDomainCreationStarted(MyAppDomainID); -// END_PIN_PROFILER(); +// END_PROFILER_CALLBACK(); // } // The BEGIN / END macros do the following: // * Evaluate the expression argument (e.g., CORProfilerTrackAppDomainLoads()). This is a @@ -95,33 +95,6 @@ // first, which the writer will be sure to see in (c). For more details about how the // evacuation counters work, see code:ProfilingAPIUtility::IsProfilerEvacuated. // -// WHEN ARE BEGIN/END_PIN_PROFILER REQUIRED? -// -// In general, any time you access g_profControlBlock.pProfInterface, you must be inside -// a BEGIN/END_PIN_PROFILER block. This is pretty much always true throughout the EE, but -// there are some exceptions inside the profiling API code itself, where the BEGIN / END -// macros are unnecessary: -// * If you are inside a public ICorProfilerInfo function's implementation, the -// profiler is already pinned. This is because the profiler called the Info -// function from either: -// * a callback implemented inside of g_profControlBlock.pProfInterface, in which -// case the BEGIN/END macros are already in place around the call to that -// callback, OR -// * a hijacked thread or a thread of the profiler's own creation. In either -// case, it's the profiler's responsibility to end hijacking and end its own -// threads before requesting a detach. So the profiler DLL is guaranteed not -// to disappear while hijacking or profiler-created threads are in action. -// * If you're executing while code:ProfilingAPIUtility::s_csStatus is held, then -// you're explicitly serialized against all code that might unload the profiler's -// DLL and delete g_profControlBlock.pProfInterface. So the profiler is therefore -// still guaranteed not to disappear. -// * If slow ELT helpers, fast ELT hooks, or profiler-instrumented code is on the -// stack, then the profiler cannot be detached yet anyway. Today, we outright -// refuse a detach request from a profiler that instrumented code or enabled ELT. -// Once rejit / revert is implemented, the evacuation checks will ensure all -// instrumented code (including ELT) are reverted and off all stacks before -// attempting to unload the profielr. - #include "common.h" @@ -148,44 +121,6 @@ #include "securitywrapper.h" #endif // !TARGET_UNIX -//--------------------------------------------------------------------------------------- -// Normally, this would go in profilepriv.inl, but it's not easily inlineable because of -// the use of BEGIN/END_PIN_PROFILER -// -// Return Value: -// TRUE iff security transparency checks in full trust assemblies should be disabled -// due to the profiler. -// -BOOL CORProfilerBypassSecurityChecks() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - CANNOT_TAKE_LOCK; - } - CONTRACTL_END; - - { - BEGIN_PIN_PROFILER(CORProfilerPresent()); - - // V2 profiler binaries, for compatibility purposes, should bypass transparency - // checks in full trust assemblies. - if (!(&g_profControlBlock)->pProfInterface->IsCallback3Supported()) - return TRUE; - - // V4 profiler binaries must opt in to bypassing transparency checks in full trust - // assemblies. - if (((&g_profControlBlock)->dwEventMask & COR_PRF_DISABLE_TRANSPARENCY_CHECKS_UNDER_FULL_TRUST) != 0) - return TRUE; - - END_PIN_PROFILER(); - } - - // All other cases, including no profiler loaded at all: Don't bypass - return FALSE; -} - // ---------------------------------------------------------------------------- // CurrentProfilerStatus methods @@ -379,6 +314,9 @@ void ProfilingAPIUtility::LogProfEventVA( AppendSupplementaryInformation(iStringResourceID, &messageToLog); + // Write to ETW and EventPipe with the message + FireEtwProfilerMessage(GetClrInstanceId(), messageToLog.GetUnicode()); + // Ouput debug strings for diagnostic messages. WszOutputDebugString(messageToLog); } @@ -498,6 +436,9 @@ HRESULT ProfilingAPIUtility::InitializeProfiling() } AttemptLoadProfilerForStartup(); + AttemptLoadDelayedStartupProfilers(); + AttemptLoadProfilerList(); + // For now, the return value from AttemptLoadProfilerForStartup is of no use to us. // Any event has been logged already by AttemptLoadProfilerForStartup, and // regardless of whether a profiler got loaded, we still need to continue. @@ -687,108 +628,85 @@ HRESULT ProfilingAPIUtility::AttemptLoadProfilerForStartup() fProfEnabled = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_ENABLE_PROFILING); NewArrayHolder<WCHAR> wszClsid(NULL); - NewArrayHolder<const WCHAR> cwszProfilerDLL(NULL); + NewArrayHolder<WCHAR> wszProfilerDLL(NULL); CLSID *pClsid; CLSID clsid; - if (fProfEnabled != 0) + if (fProfEnabled == 0) { - LOG((LF_CORPROF, LL_INFO10, "**PROF: Initializing Profiling Services.\n")); + LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling not enabled.\n")); + return S_FALSE; + } - NewArrayHolder<WCHAR> wszProfilerDLL(NULL); + LOG((LF_CORPROF, LL_INFO10, "**PROF: Initializing Profiling Services.\n")); - IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER, &wszClsid)); + IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER, &wszClsid)); - #if defined(TARGET_ARM64) - IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM64, &wszProfilerDLL)); - #elif defined(TARGET_ARM) - IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM32, &wszProfilerDLL)); - #endif +#if defined(TARGET_ARM64) + IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM64, &wszProfilerDLL)); +#elif defined(TARGET_ARM) + IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_ARM32, &wszProfilerDLL)); +#endif + if(wszProfilerDLL == NULL) + { +#ifdef TARGET_64BIT + IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_64, &wszProfilerDLL)); +#else + IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL)); +#endif if(wszProfilerDLL == NULL) { - #ifdef TARGET_64BIT - IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_64, &wszProfilerDLL)); - #else - IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL)); - #endif - if(wszProfilerDLL == NULL) - { - IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH, &wszProfilerDLL)); - } + IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH, &wszProfilerDLL)); } + } - // If the environment variable doesn't exist, profiling is not enabled. - if (wszClsid == NULL) - { - LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required " - "environment variable does not exist.\n")); - - LogProfError(IDS_E_PROF_NO_CLSID); - - return S_FALSE; - } + // If the environment variable doesn't exist, profiling is not enabled. + if (wszClsid == NULL) + { + LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required " + "environment variable does not exist.\n")); - if ((wszProfilerDLL != NULL) && (wcslen(wszProfilerDLL) >= MAX_LONGPATH)) - { - LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but COR_PROFILER_PATH was not set properly.\n")); + LogProfError(IDS_E_PROF_NO_CLSID); - LogProfError(IDS_E_PROF_BAD_PATH); + return S_FALSE; + } - return S_FALSE; - } + if ((wszProfilerDLL != NULL) && (wcslen(wszProfilerDLL) >= MAX_LONGPATH)) + { + LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but COR_PROFILER_PATH was not set properly.\n")); - #ifdef TARGET_UNIX - // If the environment variable doesn't exist, profiling is not enabled. - if (wszProfilerDLL == NULL) - { - LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required " - "environment variable does not exist.\n")); + LogProfError(IDS_E_PROF_BAD_PATH); - LogProfError(IDS_E_PROF_BAD_PATH); + return S_FALSE; + } - return S_FALSE; - } - #endif // TARGET_UNIX +#ifdef TARGET_UNIX + // If the environment variable doesn't exist, profiling is not enabled. + if (wszProfilerDLL == NULL) + { + LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling flag set, but required " + "environment variable does not exist.\n")); - hr = ProfilingAPIUtility::ProfilerCLSIDFromString(wszClsid, &clsid); - if (FAILED(hr)) - { - // ProfilerCLSIDFromString already logged an event if there was a failure - return hr; - } + LogProfError(IDS_E_PROF_BAD_PATH); - pClsid = &clsid; - cwszProfilerDLL.Assign(wszProfilerDLL.GetValue()); - wszProfilerDLL.SuppressRelease(); - } - else if (g_profControlBlock.fIsStoredProfilerRegistered) - { - LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiler loading from GUID/Path stored from the IPC channel.")); - pClsid = &(g_profControlBlock.clsStoredProfilerGuid); - - // Convert to string for logging - constexpr size_t guidStringSize = 128; - wszClsid.Assign(new (nothrow) WCHAR[guidStringSize]); - if (wszClsid != NULL) - { - StringFromGUID2(*pClsid, wszClsid, guidStringSize); - } - - // Assign, but don't take ownership of, the stored profiler path. This relies on - // g_profControlBlock.sStoredProfilerPath not mutating, which would invalidate the pointer. - cwszProfilerDLL.Assign(g_profControlBlock.sStoredProfilerPath.GetUnicode(), FALSE); + return S_FALSE; } - else +#endif // TARGET_UNIX + + hr = ProfilingAPIUtility::ProfilerCLSIDFromString(wszClsid, &clsid); + if (FAILED(hr)) { - LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiling not enabled.\n")); - return S_FALSE; + // ProfilerCLSIDFromString already logged an event if there was a failure + return hr; } + pClsid = &clsid; + hr = LoadProfiler( kStartupLoad, pClsid, wszClsid, - cwszProfilerDLL, + wszProfilerDLL, NULL, // No client data for startup load 0); // No client data for startup load if (FAILED(hr)) @@ -801,6 +719,121 @@ HRESULT ProfilingAPIUtility::AttemptLoadProfilerForStartup() return S_OK; } +//static +HRESULT ProfilingAPIUtility::AttemptLoadDelayedStartupProfilers() +{ + if (g_profControlBlock.storedProfilers.IsEmpty()) + { + return S_OK; + } + + HRESULT storedHr = S_OK; + STOREDPROFILERLIST *profilers = &g_profControlBlock.storedProfilers; + for (StoredProfilerNode* item = profilers->GetHead(); item != NULL; item = STOREDPROFILERLIST::GetNext(item)) + { + LOG((LF_CORPROF, LL_INFO10, "**PROF: Profiler loading from GUID/Path stored from the IPC channel.")); + CLSID *pClsid = &(item->guid); + + // Convert to string for logging + constexpr size_t guidStringSize = 39; + NewArrayHolder<WCHAR> wszClsid(new (nothrow) WCHAR[guidStringSize]); + // GUIDs should always be the same number of characters... + _ASSERTE(wszClsid != NULL); + if (wszClsid != NULL) + { + StringFromGUID2(*pClsid, wszClsid, guidStringSize); + } + + HRESULT hr = LoadProfiler( + kStartupLoad, + pClsid, + wszClsid, + item->path.GetUnicode(), + NULL, // No client data for startup load + 0); // No client data for startup load + if (FAILED(hr)) + { + // LoadProfiler logs if there is an error + storedHr = hr; + } + } + + return storedHr; +} + +// static +HRESULT ProfilingAPIUtility::AttemptLoadProfilerList() +{ + HRESULT hr = S_OK; + DWORD dwEnabled = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_ENABLE_NOTIFICATION_PROFILERS); + if (dwEnabled == 0) + { + // Profiler list explicitly disabled, bail + LogProfInfo(IDS_E_PROF_NOTIFICATION_DISABLED); + return S_OK; + } + + NewArrayHolder<WCHAR> wszProfilerList(NULL); +#ifdef TARGET_64BIT + CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_NOTIFICATION_PROFILERS_64, &wszProfilerList); +#else // TARGET_64BIT + CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_NOTIFICATION_PROFILERS_32, &wszProfilerList); +#endif // TARGET_64BIT + if (wszProfilerList == NULL) + { + CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_NOTIFICATION_PROFILERS, &wszProfilerList); + if (wszProfilerList == NULL) + { + // No profiler list specified, bail + return S_OK; + } + } + + WCHAR *pOuter = NULL; + WCHAR *pInner = NULL; + WCHAR *currentSection = NULL; + WCHAR *currentPath = NULL; + WCHAR *currentGuid = NULL; + + HRESULT storedHr = S_OK; + // Get each semicolon delimited config + currentSection = wcstok_s(wszProfilerList, W(";"), &pOuter); + while (currentSection != NULL) + { + // Parse this config "path={guid}" + currentPath = wcstok_s(currentSection, W("="), &pInner); + currentGuid = wcstok_s(NULL, W("="), &pInner); + + CLSID clsid; + hr = ProfilingAPIUtility::ProfilerCLSIDFromString(currentGuid, &clsid); + if (FAILED(hr)) + { + // ProfilerCLSIDFromString already logged an event if there was a failure + storedHr = hr; + goto NextSection; + } + + hr = LoadProfiler( + kStartupLoad, + &clsid, + currentGuid, + currentPath, + NULL, // No client data for startup load + 0); // No client data for startup load + if (FAILED(hr)) + { + // LoadProfiler already logged if there was an error + storedHr = hr; + goto NextSection; + } + +NextSection: + // Get next config + currentSection = wcstok_s(NULL, W(";"), &pOuter); + } + + return storedHr; +} //--------------------------------------------------------------------------------------- // @@ -1060,6 +1093,12 @@ HRESULT ProfilingAPIUtility::LoadProfiler( // Client data is currently only specified on attach _ASSERTE((pvClientData == NULL) || (loadType == kAttachLoad)); + ProfilerInfo profilerInfo; + // RAII type that will deregister if we bail at any point + ProfilerInfoHolder profilerInfoHolder(&profilerInfo); + profilerInfo.Init(); + profilerInfo.inUse = TRUE; + HRESULT hr = PerformDeferredInit(); if (FAILED(hr)) { @@ -1073,19 +1112,10 @@ HRESULT ProfilingAPIUtility::LoadProfiler( } { - // To prevent race conditions we need to signal that a load is already happening. - // The diagnostics server is single threaded, but it can potentially be - // racing with the startup path, or theoretically in the future it could be - // racing with another attach request if the diagnostic server becomes - // multithreaded. - CRITSEC_Holder csh(s_csStatus); - - if (g_profControlBlock.curProfStatus.Get() != kProfStatusNone) - { - return CORPROF_E_PROFILER_ALREADY_ACTIVE; - } - - g_profControlBlock.curProfStatus.Set(kProfStatusPreInitialize); + // Usually we need to take the lock when modifying profiler status, but at this + // point no one else could have a pointer to this ProfilerInfo so we don't + // need to synchronize. Once we store it in g_profControlBlock we need to. + profilerInfo.curProfStatus.Set(kProfStatusPreInitialize); } NewHolder<EEToProfInterfaceImpl> pEEProf(new (nothrow) EEToProfInterfaceImpl()); @@ -1100,17 +1130,13 @@ HRESULT ProfilingAPIUtility::LoadProfiler( hr = DoPreInitialization(pEEProf, pClsid, wszClsid, wszProfilerDLL, loadType, dwConcurrentGCWaitTimeoutInMs); if (FAILED(hr)) { - CRITSEC_Holder csh(s_csStatus); - g_profControlBlock.curProfStatus.Set(kProfStatusNone); return hr; } { - // All modification of the profiler's status and - // g_profControlBlock.pProfInterface need to be serialized against each other, - // in particular, this code should be serialized against detach and unloading - // code. - CRITSEC_Holder csh(s_csStatus); + // Usually we need to take the lock when modifying profiler status, but at this + // point no one else could have a pointer to this ProfilerInfo so we don't + // need to synchronize. Once we store it in g_profControlBlock we need to. // We've successfully allocated and initialized the callback wrapper object and the // Info interface implementation objects. The profiler DLL is therefore also @@ -1122,18 +1148,64 @@ HRESULT ProfilingAPIUtility::LoadProfiler( // callback (which we do immediately below), and have it successfully call // back into us via the Info interface (ProfToEEInterfaceImpl) to perform its // initialization. - g_profControlBlock.pProfInterface = pEEProf.GetValue(); + profilerInfo.pProfInterface = pEEProf.GetValue(); pEEProf.SuppressRelease(); pEEProf = NULL; // Set global status to reflect the proper type of Init we're doing (attach vs // startup) - g_profControlBlock.curProfStatus.Set( + profilerInfo.curProfStatus.Set( (loadType == kStartupLoad) ? kProfStatusInitializingForStartupLoad : kProfStatusInitializingForAttachLoad); } + ProfilerInfo *pProfilerInfo = NULL; + { + // Now we register the profiler, from this point on we need to worry about + // synchronization + CRITSEC_Holder csh(s_csStatus); + + // Check if this profiler is notification only and load as appropriate + BOOL notificationOnly = FALSE; + { + EvacuationCounterHolder holder(&profilerInfo); + HRESULT callHr = profilerInfo.pProfInterface->LoadAsNotficationOnly(¬ificationOnly); + if (FAILED(callHr)) + { + notificationOnly = FALSE; + } + } + + if (notificationOnly) + { + pProfilerInfo = g_profControlBlock.FindNextFreeProfilerInfoSlot(); + if (pProfilerInfo == NULL) + { + LogProfError(IDS_E_PROF_NOTIFICATION_LIMIT_EXCEEDED); + return CORPROF_E_PROFILER_ALREADY_ACTIVE; + } + + *pProfilerInfo = profilerInfo; + } + else + { + // "main" profiler, there can only be one + if (g_profControlBlock.mainProfilerInfo.curProfStatus.Get() != kProfStatusNone) + { + LogProfError(IDS_PROF_ALREADY_LOADED); + return CORPROF_E_PROFILER_ALREADY_ACTIVE; + } + + // This profiler cannot be a notification only profiler, copy it over to the + // main slot and the ProfilerInfoHolder above will clear out the notification slot + g_profControlBlock.mainProfilerInfo = profilerInfo; + pProfilerInfo = &(g_profControlBlock.mainProfilerInfo); + } + + pProfilerInfo->pProfInterface->SetProfilerInfo(pProfilerInfo); + } + // Now that the profiler is officially loaded and in Init status, call into the // profiler's appropriate Initialize() callback. Note that if the profiler fails this // call, we should abort the rest of the profiler loading, and reset our state so we @@ -1141,13 +1213,25 @@ HRESULT ProfilingAPIUtility::LoadProfiler( if (loadType == kStartupLoad) { - hr = g_profControlBlock.pProfInterface->Initialize(); + // This EvacuationCounterHolder is just to make asserts in EEToProfInterfaceImpl happy. + // Using it like this without the dirty read/evac counter increment/clean read pattern + // is not safe generally, but in this specific case we can skip all that since we haven't + // published it yet, so we are the only thread that can access it. + EvacuationCounterHolder holder(pProfilerInfo); + hr = pProfilerInfo->pProfInterface->Initialize(); } else { + // This EvacuationCounterHolder is just to make asserts in EEToProfInterfaceImpl happy. + // Using it like this without the dirty read/evac counter increment/clean read pattern + // is not safe generally, but in this specific case we can skip all that since we haven't + // published it yet, so we are the only thread that can access it. + EvacuationCounterHolder holder(pProfilerInfo); + _ASSERTE(loadType == kAttachLoad); - _ASSERTE(g_profControlBlock.pProfInterface->IsCallback3Supported()); - hr = g_profControlBlock.pProfInterface->InitializeForAttach(pvClientData, cbClientData); + _ASSERTE(pProfilerInfo->pProfInterface->IsCallback3Supported()); + + hr = pProfilerInfo->pProfInterface->InitializeForAttach(pvClientData, cbClientData); } if (FAILED(hr)) @@ -1162,7 +1246,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler( // the reason InitializeForAttach callback failed even though we cannot be sure and we cannot // cannot assume hr is going to be CORPROF_E_TIMEOUT_WAITING_FOR_CONCURRENT_GC. // The best we can do in this case is to report this failure anyway. - if (g_profControlBlock.pProfInterface->HasTimedOutWaitingForConcurrentGC()) + if (pProfilerInfo->pProfInterface->HasTimedOutWaitingForConcurrentGC()) { ProfilingAPIUtility::LogProfError(IDS_E_PROF_TIMEOUT_WAITING_FOR_CONCURRENT_GC, dwConcurrentGCWaitTimeoutInMs, wszClsid); } @@ -1171,7 +1255,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler( if ((loadType == kAttachLoad) && ((hr == CORPROF_E_PROFILER_NOT_ATTACHABLE) || (hr == E_NOTIMPL))) { - _ASSERTE(g_profControlBlock.pProfInterface->IsCallback3Supported()); + _ASSERTE(pProfilerInfo->pProfInterface->IsCallback3Supported()); // Profiler supports ICorProfilerCallback3, but explicitly doesn't support // Attach loading. So log specialized event @@ -1196,14 +1280,14 @@ HRESULT ProfilingAPIUtility::LoadProfiler( // Profiler failed; reset everything. This will automatically reset // g_profControlBlock and will unload the profiler's DLL. - TerminateProfiling(); + TerminateProfiling(pProfilerInfo); return hr; } #ifdef FEATURE_MULTICOREJIT // Disable multicore JIT when profiling is enabled - if (g_profControlBlock.dwEventMask & COR_PRF_MONITOR_JIT_COMPILATION) + if (pProfilerInfo->eventMask.IsEventMaskSet(COR_PRF_MONITOR_JIT_COMPILATION)) { MulticoreJitManager::DisableMulticoreJit(); } @@ -1213,7 +1297,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler( // Indicate that profiling is properly initialized. On an attach-load, this will // force a FlushStoreBuffers(), which is important for catch-up synchronization (see // code:#ProfCatchUpSynchronization) - g_profControlBlock.curProfStatus.Set(kProfStatusActive); + pProfilerInfo->curProfStatus.Set(kProfStatusActive); LOG(( LF_CORPROF, @@ -1229,7 +1313,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler( // For startup profilers only: If the profiler is interested in tracking GC // events, then we must disable concurrent GC since concurrent GC can allocate // and kill objects without relocating and thus not doing a heap walk. - if (CORProfilerTrackGC()) + if (pProfilerInfo->eventMask.IsEventMaskSet(COR_PRF_MONITOR_GC)) { LOG((LF_CORPROF, LL_INFO10, "**PROF: Turning off concurrent GC at startup.\n")); // Previously we would use SetGCConcurrent(0) to indicate to the GC that it shouldn't even @@ -1303,11 +1387,17 @@ HRESULT ProfilingAPIUtility::LoadProfiler( // code:ProfilerFunctionEnum::Init#ProfilerEnumGeneral { - BEGIN_PIN_PROFILER(CORProfilerPresent()); - g_profControlBlock.pProfInterface->ProfilerAttachComplete(); - END_PIN_PROFILER(); + // This EvacuationCounterHolder is just to make asserts in EEToProfInterfaceImpl happy. + // Using it like this without the dirty read/evac counter increment/clean read pattern + // is not safe generally, but in this specific case we can skip all that since we haven't + // published it yet, so we are the only thread that can access it. + EvacuationCounterHolder holder(pProfilerInfo); + pProfilerInfo->pProfInterface->ProfilerAttachComplete(); } } + + // Yay, the profiler is started up. Don't deregister it if we get to this point + profilerInfoHolder.SuppressRelease(); return S_OK; } @@ -1323,7 +1413,7 @@ HRESULT ProfilingAPIUtility::LoadProfiler( // // static -BOOL ProfilingAPIUtility::IsProfilerEvacuated() +BOOL ProfilingAPIUtility::IsProfilerEvacuated(ProfilerInfo *pProfilerInfo) { CONTRACTL { @@ -1334,64 +1424,36 @@ BOOL ProfilingAPIUtility::IsProfilerEvacuated() } CONTRACTL_END; - _ASSERTE(g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching); - - // Check evacuation counters on all the threads (see + _ASSERTE(pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching); + + // Note that threads are still in motion as we check its evacuation counter. + // This is ok, because we've already changed the profiler status to + // kProfStatusDetaching and flushed CPU buffers. So at this point the counter + // will typically only go down to 0 (and not increment anymore), with one + // small exception (below). So if we get a read of 0 below, the counter will + // typically stay there. Specifically: + // * Profiler is most likely not about to increment its evacuation counter + // from 0 to 1 because pThread sees that the status is + // kProfStatusDetaching. + // * Note that there is a small race where pThread might actually + // increment its evac counter from 0 to 1 (if it dirty-read the + // profiler status a tad too early), but that implies that when + // pThread rechecks the profiler status (clean read) then pThread + // will immediately decrement the evac counter back to 0 and avoid + // calling into the EEToProfInterfaceImpl pointer. + // + // (see // code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization - // for details). Doing this under the thread store lock not only ensures we can - // iterate through the Thread objects safely, but also forces us to serialize with - // the GC. The latter is important, as server GC enters the profiler on non-EE - // Threads, and so no evacuation counters might be incremented during server GC even - // though control could be entering the profiler. + // for details) + DWORD dwEvacCounter = pProfilerInfo->dwProfilerEvacuationCounter; + if (dwEvacCounter != 0) { - ThreadStoreLockHolder TSLockHolder; - - Thread * pThread = ThreadStore::GetAllThreadList( - NULL, // cursor thread; always NULL to begin with - 0, // mask to AND with Thread::m_State to filter returned threads - 0); // bits to match the result of the above AND. (m_State & 0 == 0, - // so we won't filter out any threads) - - // Note that, by not filtering out any of the threads, we're intentionally including - // stuff like TS_Dead or TS_Unstarted. But that keeps us on the safe - // side. If an EE Thread object exists, we want to check its counters to be - // absolutely certain it isn't executing in a profiler. - - while (pThread != NULL) - { - // Note that pThread is still in motion as we check its evacuation counter. - // This is ok, because we've already changed the profiler status to - // kProfStatusDetaching and flushed CPU buffers. So at this point the counter - // will typically only go down to 0 (and not increment anymore), with one - // small exception (below). So if we get a read of 0 below, the counter will - // typically stay there. Specifically: - // * pThread is most likely not about to increment its evacuation counter - // from 0 to 1 because pThread sees that the status is - // kProfStatusDetaching. - // * Note that there is a small race where pThread might actually - // increment its evac counter from 0 to 1 (if it dirty-read the - // profiler status a tad too early), but that implies that when - // pThread rechecks the profiler status (clean read) then pThread - // will immediately decrement the evac counter back to 0 and avoid - // calling into the EEToProfInterfaceImpl pointer. - // - // (see - // code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization - // for details) - DWORD dwEvacCounter = pThread->GetProfilerEvacuationCounter(); - if (dwEvacCounter != 0) - { - LOG(( - LF_CORPROF, - LL_INFO100, - "**PROF: Profiler not yet evacuated because OS Thread ID 0x%x has evac counter of %d (decimal).\n", - pThread->GetOSThreadId(), - dwEvacCounter)); - return FALSE; - } - - pThread = ThreadStore::GetAllThreadList(pThread, 0, 0); - } + LOG(( + LF_CORPROF, + LL_INFO100, + "**PROF: Profiler not yet evacuated because it has evac counter of %d (decimal).\n", + dwEvacCounter)); + return FALSE; } // FUTURE: When rejit feature crew complete, add code to verify all rejitted @@ -1412,7 +1474,7 @@ BOOL ProfilingAPIUtility::IsProfilerEvacuated() // // static -void ProfilingAPIUtility::TerminateProfiling() +void ProfilingAPIUtility::TerminateProfiling(ProfilerInfo *pProfilerInfo) { CONTRACTL { @@ -1439,7 +1501,7 @@ void ProfilingAPIUtility::TerminateProfiling() #ifdef FEATURE_PROFAPI_ATTACH_DETACH - if (ProfilingAPIDetach::GetEEToProfPtr() != NULL) + if (pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching && pProfilerInfo->pProfInterface.Load() != NULL) { // The profiler is still being referenced by // ProfilingAPIDetach::s_profilerDetachInfo, so don't try to release and @@ -1461,9 +1523,9 @@ void ProfilingAPIUtility::TerminateProfiling() } #endif // FEATURE_PROFAPI_ATTACH_DETACH - if (g_profControlBlock.curProfStatus.Get() == kProfStatusActive) + if (pProfilerInfo->curProfStatus.Get() == kProfStatusActive) { - g_profControlBlock.curProfStatus.Set(kProfStatusDetaching); + pProfilerInfo->curProfStatus.Set(kProfStatusDetaching); // Profiler was active when TerminateProfiling() was called, so we're unloading // it due to shutdown. But other threads may still be trying to enter profiler @@ -1471,7 +1533,7 @@ void ProfilingAPIUtility::TerminateProfiling() // that the status has been changed to kProfStatusDetaching, no new threads will // attempt to enter the profiler. But use the detach evacuation counters to see // if other threads already began to enter the profiler. - if (!ProfilingAPIUtility::IsProfilerEvacuated()) + if (!ProfilingAPIUtility::IsProfilerEvacuated(pProfilerInfo)) { // Other threads might be entering the profiler, so just skip cleanup return; @@ -1482,34 +1544,40 @@ void ProfilingAPIUtility::TerminateProfiling() // If we have a profiler callback wrapper and / or info implementation // active, then terminate them. - if (g_profControlBlock.pProfInterface.Load() != NULL) + if (pProfilerInfo->pProfInterface.Load() != NULL) { // This destructor takes care of releasing the profiler's ICorProfilerCallback* // interface, and unloading the DLL when we're not in process teardown. - delete g_profControlBlock.pProfInterface; - g_profControlBlock.pProfInterface.Store(NULL); + delete pProfilerInfo->pProfInterface; + pProfilerInfo->pProfInterface.Store(NULL); } // NOTE: Intentionally not destroying / NULLing s_csStatus. If // s_csStatus is already initialized, we can reuse it each time we do another // attach / detach, so no need to destroy it. + // Attach/Load/Detach are all synchronized with the Status Crst, don't need to worry about races // If we disabled concurrent GC and somehow failed later during the initialization - if (g_profControlBlock.fConcurrentGCDisabledForAttach) + if (g_profControlBlock.fConcurrentGCDisabledForAttach.Load() && g_profControlBlock.IsMainProfiler(pProfilerInfo->pProfInterface)) { + g_profControlBlock.fConcurrentGCDisabledForAttach = FALSE; + // We know for sure GC has been fully initialized as we've turned off concurrent GC before _ASSERTE(IsGarbageCollectorFullyInitialized()); GCHeapUtilities::GetGCHeap()->TemporaryEnableConcurrentGC(); - g_profControlBlock.fConcurrentGCDisabledForAttach = FALSE; } // #ProfileResetSessionStatus Reset all the status variables that are for the current // profiling attach session. // When you are adding new status in g_profControlBlock, you need to think about whether // your new status is per-session, or consistent across sessions - g_profControlBlock.ResetPerSessionStatus(); + pProfilerInfo->ResetPerSessionStatus(); - g_profControlBlock.curProfStatus.Set(kProfStatusNone); + pProfilerInfo->curProfStatus.Set(kProfStatusNone); + + g_profControlBlock.DeRegisterProfilerInfo(pProfilerInfo); + + g_profControlBlock.UpdateGlobalEventMask(); } } diff --git a/src/coreclr/vm/profilinghelper.h b/src/coreclr/vm/profilinghelper.h index 4c8ed1dc5c2..1cf7ea4ab50 100644 --- a/src/coreclr/vm/profilinghelper.h +++ b/src/coreclr/vm/profilinghelper.h @@ -64,52 +64,13 @@ public: UINT cbClientData, DWORD dwConcurrentGCWaitTimeoutInMs); - static BOOL IsProfilerEvacuated(); - static void TerminateProfiling(); + static BOOL IsProfilerEvacuated(ProfilerInfo *pDetachInfo); + static void TerminateProfiling(ProfilerInfo *pProfilerInfo); static void LogProfError(int iStringResourceID, ...); static void LogProfInfo(int iStringResourceID, ...); static void LogNoInterfaceError(REFIID iidRequested, LPCWSTR wszClsid); INDEBUG(static BOOL ShouldInjectProfAPIFault(ProfAPIFaultFlags faultFlag);) -#ifdef FEATURE_PROFAPI_ATTACH_DETACH - // ---------------------------------------------------------------------------- - // ProfilingAPIUtility::IncEvacuationCounter - // - // Description: - // Simple helper to increase the evacuation counter inside an EE thread by one - // - // Arguments: - // * pThread - pointer to an EE Thread - // - template<typename ThreadType> - static FORCEINLINE void IncEvacuationCounter(ThreadType * pThread) - { - LIMITED_METHOD_CONTRACT; - - if (pThread) - pThread->IncProfilerEvacuationCounter(); - } - - // ---------------------------------------------------------------------------- - // ProfilingAPIUtility::DecEvacuationCounter - // - // Description: - // Simple helper to decrease the evacuation counter inside an EE thread by one - // - // Arguments: - // * pThread - pointer to an EE Thread - // - template<typename ThreadType> - static FORCEINLINE void DecEvacuationCounter(ThreadType * pThread) - { - LIMITED_METHOD_CONTRACT; - - if (pThread) - pThread->DecProfilerEvacuationCounter(); - } - -#endif // FEATURE_PROFAPI_ATTACH_DETACH - // See code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization static CRITSEC_COOKIE GetStatusCrst(); @@ -147,6 +108,8 @@ private: DWORD dwConcurrentGCWaitTimeoutInMs = INFINITE); static HRESULT ProfilerCLSIDFromString(__inout_z LPWSTR wszClsid, CLSID * pClsid); static HRESULT AttemptLoadProfilerForStartup(); + static HRESULT AttemptLoadDelayedStartupProfilers(); + static HRESULT AttemptLoadProfilerList(); static void AppendSupplementaryInformation(int iStringResource, SString * pString); @@ -173,4 +136,11 @@ private: DWORD m_dwOriginalFullState; }; +FORCEINLINE void DeregisterProfilerIfNotificationOnly(ProfilerInfo *pProfilerInfo) +{ + g_profControlBlock.DeRegisterProfilerInfo(pProfilerInfo); +} + +typedef Wrapper<ProfilerInfo *, DoNothing, DeregisterProfilerIfNotificationOnly> ProfilerInfoHolder; + #endif //__PROFILING_HELPER_H__ diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp index 94161378380..c1e98330498 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -177,7 +177,7 @@ enum ProfToClrEntrypointFlags do \ { \ if ((((p2eeFlags) & kP2EEAllowableAfterAttach) == 0) && \ - (g_profControlBlock.pProfInterface->IsLoadedViaAttach())) \ + (m_pProfilerInfo->pProfInterface->IsLoadedViaAttach())) \ { \ LOG((LF_CORPROF, \ LL_ERROR, \ @@ -214,10 +214,10 @@ enum ProfToClrEntrypointFlags do \ { \ INCONTRACT(AssertTriggersContract(((p2eeFlags) & kP2EETriggers))); \ - _ASSERTE(g_profControlBlock.curProfStatus.Get() != kProfStatusNone); \ + _ASSERTE(m_pProfilerInfo->curProfStatus.Get() != kProfStatusNone); \ LOG(logParams); \ /* If profiler was neutered, disallow call */ \ - if (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching) \ + if (m_pProfilerInfo->curProfStatus.Get() == kProfStatusDetaching) \ { \ LOG((LF_CORPROF, \ LL_ERROR, \ @@ -256,8 +256,8 @@ enum ProfToClrEntrypointFlags do \ { \ PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams); \ - if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad && \ - g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForAttachLoad) \ + if (m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForStartupLoad && \ + m_pProfilerInfo->curProfStatus.Get() != kProfStatusInitializingForAttachLoad) \ { \ return CORPROF_E_CALL_ONLY_FROM_INIT; \ } \ @@ -622,13 +622,13 @@ void __stdcall ProfilerObjectAllocatedCallback(OBJECTREF objref, ClassID classId // Notify the profiler of the allocation { - BEGIN_PIN_PROFILER(CORProfilerTrackAllocations() || CORProfilerTrackLargeAllocations()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAllocations() || CORProfilerTrackLargeAllocations()); // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs. // Thus we strip any instantiations of the ClassID (which is really a type handle) here. - g_profControlBlock.pProfInterface->ObjectAllocated( + g_profControlBlock.ObjectAllocated( (ObjectID) OBJECTREFToObject(objref), classId); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED } @@ -661,18 +661,18 @@ void __stdcall GarbageCollectionStartedCallback(int generation, BOOL induced) // Notify the profiler of start of the collection { - BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC() || CORProfilerTrackBasicGC()); BOOL generationCollected[COR_PRF_GC_PINNED_OBJECT_HEAP+1]; if (generation == COR_PRF_GC_GEN_2) generation = COR_PRF_GC_PINNED_OBJECT_HEAP; for (int gen = 0; gen <= COR_PRF_GC_PINNED_OBJECT_HEAP; gen++) generationCollected[gen] = gen <= generation; - g_profControlBlock.pProfInterface->GarbageCollectionStarted( + g_profControlBlock.GarbageCollectionStarted( COR_PRF_GC_PINNED_OBJECT_HEAP+1, generationCollected, induced ? COR_PRF_GC_INDUCED : COR_PRF_GC_OTHER); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED } @@ -695,9 +695,9 @@ void __stdcall GarbageCollectionFinishedCallback() #ifdef PROFILING_SUPPORTED // Notify the profiler of end of the collection { - BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC()); - g_profControlBlock.pProfInterface->GarbageCollectionFinished(); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackGC() || CORProfilerTrackBasicGC()); + g_profControlBlock.GarbageCollectionFinished(); + END_PROFILER_CALLBACK(); } // Mark that GC is finished. @@ -1131,7 +1131,7 @@ bool HeapWalkHelper(Object * pBO, void * pvContext) // It is not safe and could be overflowed to downcast size_t to ULONG on WIN64. // However, we have to do this dangerous downcast here to comply with the existing Profiling COM interface. // We are currently evaluating ways to fix this potential overflow issue. - hr = g_profControlBlock.pProfInterface->ObjectReference( + hr = g_profControlBlock.ObjectReference( (ObjectID) pBO, SafeGetClassIDFromObject(pBO), (ULONG) cNumRefs, @@ -1210,13 +1210,13 @@ bool AllocByClassHelper(Object * pBO, void * pv) _ASSERTE(pv != NULL); { - BEGIN_PIN_PROFILER(CORProfilerPresent()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackAllocations()); // Pass along the call - g_profControlBlock.pProfInterface->AllocByClass( + g_profControlBlock.AllocByClass( (ObjectID) pBO, SafeGetClassIDFromObject(pBO), pv); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } return TRUE; @@ -1286,8 +1286,7 @@ void ScanRootsHelper(Object* pObj, Object ** ppRoot, ScanContext *pSC, uint32_t if (pPSC->fProfilerPinned) { // Let the profiling code know about this root reference - g_profControlBlock.pProfInterface-> - RootReference2((BYTE *)pObj, pPSC->dwEtwRootKind, (EtwGCRootFlags)dwEtwRootFlags, (BYTE *)rootID, &((pPSC)->pHeapId)); + g_profControlBlock.RootReference2((BYTE *)pObj, pPSC->dwEtwRootKind, (EtwGCRootFlags)dwEtwRootFlags, (BYTE *)rootID, &((pPSC)->pHeapId)); } #endif @@ -1451,7 +1450,7 @@ HRESULT ProfToEEInterfaceImpl::SetEventMask(DWORD dwEventMask) _ASSERTE(CORProfilerPresentOrInitializing()); - return g_profControlBlock.pProfInterface->SetEventMask(dwEventMask, 0 /* No high bits */); + return m_pProfilerInfo->pProfInterface->SetEventMask(dwEventMask, 0 /* No high bits */); } HRESULT ProfToEEInterfaceImpl::SetEventMask2(DWORD dwEventsLow, DWORD dwEventsHigh) @@ -1483,7 +1482,7 @@ HRESULT ProfToEEInterfaceImpl::SetEventMask2(DWORD dwEventsLow, DWORD dwEventsHi _ASSERTE(CORProfilerPresentOrInitializing()); - return g_profControlBlock.pProfInterface->SetEventMask(dwEventsLow, dwEventsHigh); + return m_pProfilerInfo->pProfInterface->SetEventMask(dwEventsLow, dwEventsHigh); } @@ -2571,7 +2570,7 @@ HRESULT ProfToEEInterfaceImpl::GetEventMask(DWORD * pdwEvents) return E_INVALIDARG; } - *pdwEvents = g_profControlBlock.dwEventMask; + *pdwEvents = m_pProfilerInfo->eventMask.GetEventMask(); return S_OK; } @@ -2608,8 +2607,8 @@ HRESULT ProfToEEInterfaceImpl::GetEventMask2(DWORD *pdwEventsLow, DWORD *pdwEven return E_INVALIDARG; } - *pdwEventsLow = g_profControlBlock.dwEventMask; - *pdwEventsHigh = g_profControlBlock.dwEventMaskHigh; + *pdwEventsLow = m_pProfilerInfo->eventMask.GetEventMask(); + *pdwEventsHigh = m_pProfilerInfo->eventMask.GetEventMaskHigh(); return S_OK; } @@ -4462,6 +4461,11 @@ HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId, return E_INVALIDARG; } + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + Module *pModule; // Working pointer for real class. HRESULT hr = S_OK; @@ -4478,7 +4482,7 @@ HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID moduleId, } // Remember the profiler is doing this, as that means we must never detach it! - g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag(); + g_profControlBlock.mainProfilerInfo.pProfInterface->SetUnrevertiblyModifiedILFlag(); // This action is not temporary! // If the profiler want to be able to revert, they need to use @@ -5751,7 +5755,12 @@ HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncE pFuncLeave, pFuncTailcall)); - return g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks(pFuncEnter, pFuncLeave, pFuncTailcall); + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + + return g_profControlBlock.mainProfilerInfo.pProfInterface->SetEnterLeaveFunctionHooks(pFuncEnter, pFuncLeave, pFuncTailcall); } @@ -5787,8 +5796,13 @@ HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFun pFuncLeave, pFuncTailcall)); + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + return - g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks2(pFuncEnter, pFuncLeave, pFuncTailcall); + g_profControlBlock.mainProfilerInfo.pProfInterface->SetEnterLeaveFunctionHooks2(pFuncEnter, pFuncLeave, pFuncTailcall); } @@ -5824,8 +5838,13 @@ HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFun pFuncLeave3, pFuncTailcall3)); + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + return - g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3(pFuncEnter3, + g_profControlBlock.mainProfilerInfo.pProfInterface->SetEnterLeaveFunctionHooks3(pFuncEnter3, pFuncLeave3, pFuncTailcall3); } @@ -5864,8 +5883,13 @@ HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter pFuncLeave3WithInfo, pFuncTailcall3WithInfo)); + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + return - g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3WithInfo(pFuncEnter3WithInfo, + g_profControlBlock.mainProfilerInfo.pProfInterface->SetEnterLeaveFunctionHooks3WithInfo(pFuncEnter3WithInfo, pFuncLeave3WithInfo, pFuncTailcall3WithInfo); } @@ -5898,7 +5922,12 @@ HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper(FunctionIDMapper *pFunc) "**PROF: SetFunctionIDMapper 0x%p.\n", pFunc)); - g_profControlBlock.pProfInterface->SetFunctionIDMapper(pFunc); + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + + g_profControlBlock.mainProfilerInfo.pProfInterface->SetFunctionIDMapper(pFunc); return (S_OK); } @@ -5931,7 +5960,12 @@ HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper2(FunctionIDMapper2 *pFunc, vo pFunc, clientData)); - g_profControlBlock.pProfInterface->SetFunctionIDMapper2(pFunc, clientData); + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + + g_profControlBlock.mainProfilerInfo.pProfInterface->SetFunctionIDMapper2(pFunc, clientData); return (S_OK); } @@ -6709,7 +6743,12 @@ HRESULT ProfToEEInterfaceImpl::RequestReJITWithInliners( LL_INFO1000, "**PROF: RequestReJITWithInliners.\n")); - if (!g_profControlBlock.pProfInterface->IsCallback4Supported()) + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + + if (!m_pProfilerInfo->pProfInterface->IsCallback4Supported()) { return CORPROF_E_CALLBACK4_REQUIRED; } @@ -6737,7 +6776,7 @@ HRESULT ProfToEEInterfaceImpl::RequestReJITWithInliners( } // Remember the profiler is doing this, as that means we must never detach it! - g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag(); + g_profControlBlock.mainProfilerInfo.pProfInterface->SetUnrevertiblyModifiedILFlag(); HRESULT hr = SetupThreadForReJIT(); if (FAILED(hr)) @@ -7067,7 +7106,8 @@ HRESULT ProfToEEInterfaceImpl::EventPipeStartSession( EP_SERIALIZATION_FORMAT_NETTRACE_V4, requestRundown, NULL, - reinterpret_cast<EventPipeSessionSynchronousCallback>(&ProfToEEInterfaceImpl::EventPipeCallbackHelper)); + reinterpret_cast<EventPipeSessionSynchronousCallback>(&ProfToEEInterfaceImpl::EventPipeCallbackHelper), + reinterpret_cast<void *>(m_pProfilerInfo)); if (sessionID != 0) { EventPipeAdapter::StartStreaming(sessionID); @@ -7378,28 +7418,33 @@ void ProfToEEInterfaceImpl::EventPipeCallbackHelper(EventPipeProvider *provider, LPCGUID pRelatedActivityId, Thread *pEventThread, ULONG numStackFrames, - UINT_PTR stackFrames[]) -{ - // If we got here we know a profiler has started an EventPipe session - BEGIN_PIN_PROFILER(true); - // But, a profiler could always register for a session and then detach without - // closing the session. So check if we have an interface before proceeding. - if (g_profControlBlock.pProfInterface != nullptr) - { - g_profControlBlock.pProfInterface->EventPipeEventDelivered(provider, - eventId, - eventVersion, - cbMetadataBlob, - metadataBlob, - cbEventData, - eventData, - pActivityId, - pRelatedActivityId, - pEventThread, - numStackFrames, - stackFrames); - } - END_PIN_PROFILER(); + UINT_PTR stackFrames[], + void *additionalData) +{ + _ASSERTE(additionalData != NULL); + ProfilerInfo *pProfilerInfo = reinterpret_cast<ProfilerInfo *>(additionalData); + + _ASSERTE(pProfilerInfo->pProfInterface.Load() != NULL); + { + EvacuationCounterHolder holder(pProfilerInfo); + // But, a profiler could always register for a session and then detach without + // closing the session. So check if we have an interface before proceeding. + if (pProfilerInfo->pProfInterface.Load() != NULL) + { + pProfilerInfo->pProfInterface->EventPipeEventDelivered(provider, + eventId, + eventVersion, + cbMetadataBlob, + metadataBlob, + cbEventData, + eventData, + pActivityId, + pRelatedActivityId, + pEventThread, + numStackFrames, + stackFrames); + } + } }; @@ -9116,7 +9161,12 @@ HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG cFunctions, // in LL_INFO1000, "**PROF: RequestReJIT.\n")); - if (!g_profControlBlock.pProfInterface->IsCallback4Supported()) + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + + if (!m_pProfilerInfo->pProfInterface->IsCallback4Supported()) { return CORPROF_E_CALLBACK4_REQUIRED; } @@ -9133,7 +9183,7 @@ HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG cFunctions, // in } // Remember the profiler is doing this, as that means we must never detach it! - g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag(); + g_profControlBlock.mainProfilerInfo.pProfInterface->SetUnrevertiblyModifiedILFlag(); HRESULT hr = SetupThreadForReJIT(); if (FAILED(hr)) @@ -9178,6 +9228,11 @@ HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG cFunctions, // in LL_INFO1000, "**PROF: RequestRevert.\n")); + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + if (!CORProfilerEnableRejit()) { return CORPROF_E_REJIT_NOT_ENABLED; @@ -9190,7 +9245,7 @@ HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG cFunctions, // in } // Remember the profiler is doing this, as that means we must never detach it! - g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag(); + g_profControlBlock.mainProfilerInfo.pProfInterface->SetUnrevertiblyModifiedILFlag(); // Initialize the status array if (rgHrStatuses != NULL) @@ -9497,7 +9552,7 @@ HRESULT ProfToEEInterfaceImpl::RequestProfilerDetach(DWORD dwExpectedCompletionM "**PROF: RequestProfilerDetach.\n")); #ifdef FEATURE_PROFAPI_ATTACH_DETACH - return ProfilingAPIDetach::RequestProfilerDetach(dwExpectedCompletionMilliseconds); + return ProfilingAPIDetach::RequestProfilerDetach(g_profControlBlock.GetProfilerInfo(this), dwExpectedCompletionMilliseconds); #else // FEATURE_PROFAPI_ATTACH_DETACH return E_NOTIMPL; #endif // FEATURE_PROFAPI_ATTACH_DETACH @@ -9710,7 +9765,12 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionEnter3Info(FunctionID functionId, LL_INFO1000, "**PROF: GetFunctionEnter3Info.\n")); - _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL); + _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3WithInfoHook() != NULL); + + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } if (!CORProfilerELT3SlowPathEnterEnabled()) { @@ -9868,7 +9928,12 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionLeave3Info(FunctionID functionId, LL_INFO1000, "**PROF: GetFunctionLeave3Info.\n")); - _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL); + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } + + _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3WithInfoHook() != NULL); if (!CORProfilerELT3SlowPathLeaveEnabled()) { @@ -10000,7 +10065,12 @@ HRESULT ProfToEEInterfaceImpl::GetFunctionTailcall3Info(FunctionID functionId, LL_INFO1000, "**PROF: GetFunctionTailcall3Info.\n")); - _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL); + _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3WithInfoHook() != NULL); + + if (!g_profControlBlock.IsMainProfiler(this)) + { + return E_INVALIDARG; + } if (!CORProfilerELT3SlowPathTailcallEnabled()) { @@ -10409,10 +10479,9 @@ void __stdcall ProfilerManagedToUnmanagedTransitionMD(MethodDesc *pMD, // Do not notify the profiler about QCalls if (pMD == NULL || !pMD->IsQCall()) { - BEGIN_PIN_PROFILER(CORProfilerPresent()); - g_profControlBlock.pProfInterface->ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD), - reason); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackTransitions()); + g_profControlBlock.ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD), reason); + END_PROFILER_CALLBACK(); } } @@ -10444,10 +10513,9 @@ void __stdcall ProfilerUnmanagedToManagedTransitionMD(MethodDesc *pMD, // Do not notify the profiler about QCalls if (pMD == NULL || !pMD->IsQCall()) { - BEGIN_PIN_PROFILER(CORProfilerPresent()); - g_profControlBlock.pProfInterface->UnmanagedToManagedTransition(MethodDescToFunctionID(pMD), - reason); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackTransitions()); + g_profControlBlock.UnmanagedToManagedTransition(MethodDescToFunctionID(pMD), reason); + END_PROFILER_CALLBACK(); } } @@ -10472,12 +10540,12 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi // code:ProfControlBlock#TestOnlyELT if (g_profControlBlock.fTestOnlyForceEnterLeave) { - if ((g_profControlBlock.pProfInterface.Load() == NULL) || + if ((g_profControlBlock.mainProfilerInfo.pProfInterface.Load() == NULL) || ( - (g_profControlBlock.pProfInterface->GetEnterHook() == NULL) && - (g_profControlBlock.pProfInterface->GetEnter2Hook() == NULL) && - (g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL) && - (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() == NULL) + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnterHook() == NULL) && + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter2Hook() == NULL) && + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3Hook() == NULL) && + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3WithInfoHook() == NULL) ) ) { @@ -10487,7 +10555,7 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi #endif // PROF_TEST_ONLY_FORCE_ELT // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used. - _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL); + _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3Hook() == NULL); _ASSERTE(GetThread()->PreemptiveGCDisabled()); _ASSERTE(platformSpecificHandle != NULL); @@ -10505,21 +10573,21 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi // // CLR v4 Slow-Path ELT // - if (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL) + if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3WithInfoHook() != NULL) { FunctionIDOrClientID functionIDOrClientID; functionIDOrClientID.clientID = clientData; - g_profControlBlock.pProfInterface->GetEnter3WithInfoHook()( + g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter3WithInfoHook()( functionIDOrClientID, (COR_PRF_ELT_INFO)&eltInfo); goto LExit; } - if (g_profControlBlock.pProfInterface->GetEnter2Hook() != NULL) + if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter2Hook() != NULL) { // We have run out of heap memory, so the content of the mapping table becomes stale. // All Whidbey ETL hooks must be turned off. - if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled()) + if (!g_profControlBlock.mainProfilerInfo.pProfInterface->IsClientIDToFunctionIDMappingEnabled()) { goto LExit; } @@ -10531,14 +10599,14 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi // key to retrieve the corresponding clientID from the internal FunctionID hash table. FunctionID functionId = clientData; _ASSERTE(functionId != NULL); - clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId); + clientData = g_profControlBlock.mainProfilerInfo.pProfInterface->LookupClientIDFromCache(functionId); // // Whidbey Fast-Path ELT // if (CORProfilerELT2FastPathEnterEnabled()) { - g_profControlBlock.pProfInterface->GetEnter2Hook()( + g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter2Hook()( functionId, clientData, NULL, @@ -10594,7 +10662,7 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi HRESULT hr = ProfilingGetFunctionEnter3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &ulArgInfoSize, pArgumentInfo); _ASSERTE(hr == S_OK); - g_profControlBlock.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo); + g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo); goto LExit; } @@ -10606,7 +10674,7 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi // in the first place. (Note that SetEnterLeaveFunctionHooks* will return // an error unless it's called in the profiler's Initialize(), so a profiler can't change // its mind about where the hooks are.) - _ASSERTE(g_profControlBlock.pProfInterface->GetEnterHook() != NULL); + _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnterHook() != NULL); // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether @@ -10618,7 +10686,7 @@ HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecifi // Everett ELT // { - g_profControlBlock.pProfInterface->GetEnterHook()((FunctionID)clientData); + g_profControlBlock.mainProfilerInfo.pProfInterface->GetEnterHook()((FunctionID)clientData); } LExit: @@ -10644,12 +10712,12 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi // code:ProfControlBlock#TestOnlyELT if (g_profControlBlock.fTestOnlyForceEnterLeave) { - if ((g_profControlBlock.pProfInterface.Load() == NULL) || + if ((g_profControlBlock.mainProfilerInfo.pProfInterface.Load() == NULL) || ( - (g_profControlBlock.pProfInterface->GetLeaveHook() == NULL) && - (g_profControlBlock.pProfInterface->GetLeave2Hook() == NULL) && - (g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL) && - (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() == NULL) + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeaveHook() == NULL) && + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave2Hook() == NULL) && + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3Hook() == NULL) && + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3WithInfoHook() == NULL) ) ) { @@ -10659,7 +10727,7 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi #endif // PROF_TEST_ONLY_FORCE_ELT // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used. - _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL); + _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3Hook() == NULL); _ASSERTE(GetThread()->PreemptiveGCDisabled()); _ASSERTE(platformSpecificHandle != NULL); @@ -10677,21 +10745,21 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi // // CLR v4 Slow-Path ELT // - if (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL) + if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3WithInfoHook() != NULL) { FunctionIDOrClientID functionIDOrClientID; functionIDOrClientID.clientID = clientData; - g_profControlBlock.pProfInterface->GetLeave3WithInfoHook()( + g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave3WithInfoHook()( functionIDOrClientID, (COR_PRF_ELT_INFO)&eltInfo); goto LExit; } - if (g_profControlBlock.pProfInterface->GetLeave2Hook() != NULL) + if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave2Hook() != NULL) { // We have run out of heap memory, so the content of the mapping table becomes stale. // All Whidbey ETL hooks must be turned off. - if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled()) + if (!g_profControlBlock.mainProfilerInfo.pProfInterface->IsClientIDToFunctionIDMappingEnabled()) { goto LExit; } @@ -10703,14 +10771,14 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi // key to retrieve the corresponding clientID from the internal FunctionID hash table. FunctionID functionId = clientData; _ASSERTE(functionId != NULL); - clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId); + clientData = g_profControlBlock.mainProfilerInfo.pProfInterface->LookupClientIDFromCache(functionId); // // Whidbey Fast-Path ELT // if (CORProfilerELT2FastPathLeaveEnabled()) { - g_profControlBlock.pProfInterface->GetLeave2Hook()( + g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave2Hook()( functionId, clientData, NULL, @@ -10727,7 +10795,7 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi HRESULT hr = ProfilingGetFunctionLeave3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &argumentRange); _ASSERTE(hr == S_OK); - g_profControlBlock.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange); + g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange); goto LExit; } @@ -10737,7 +10805,7 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi // in the first place. (Note that SetEnterLeaveFunctionHooks* will return // an error unless it's called in the profiler's Initialize(), so a profiler can't change // its mind about where the hooks are.) - _ASSERTE(g_profControlBlock.pProfInterface->GetLeaveHook() != NULL); + _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeaveHook() != NULL); // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether @@ -10749,7 +10817,7 @@ HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecifi // Everett ELT // { - g_profControlBlock.pProfInterface->GetLeaveHook()((FunctionID)clientData); + g_profControlBlock.mainProfilerInfo.pProfInterface->GetLeaveHook()((FunctionID)clientData); } LExit: @@ -10776,12 +10844,12 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec // code:ProfControlBlock#TestOnlyELT if (g_profControlBlock.fTestOnlyForceEnterLeave) { - if ((g_profControlBlock.pProfInterface.Load() == NULL) || + if ((g_profControlBlock.mainProfilerInfo.pProfInterface.Load() == NULL) || ( - (g_profControlBlock.pProfInterface->GetTailcallHook() == NULL) && - (g_profControlBlock.pProfInterface->GetTailcall2Hook() == NULL) && - (g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL) && - (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() == NULL) + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcallHook() == NULL) && + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall2Hook() == NULL) && + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3Hook() == NULL) && + (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3WithInfoHook() == NULL) ) ) { @@ -10791,7 +10859,7 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec #endif // PROF_TEST_ONLY_FORCE_ELT // ELT3 fast-path hooks should be NULL when ELT intermediary is used. - _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL); + _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3Hook() == NULL); _ASSERTE(GetThread()->PreemptiveGCDisabled()); _ASSERTE(platformSpecificHandle != NULL); @@ -10809,21 +10877,21 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec // // CLR v4 Slow-Path ELT // - if (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL) + if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3WithInfoHook() != NULL) { FunctionIDOrClientID functionIDOrClientID; functionIDOrClientID.clientID = clientData; - g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook()( + g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall3WithInfoHook()( functionIDOrClientID, (COR_PRF_ELT_INFO)&eltInfo); goto LExit; } - if (g_profControlBlock.pProfInterface->GetTailcall2Hook() != NULL) + if (g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall2Hook() != NULL) { // We have run out of heap memory, so the content of the mapping table becomes stale. // All Whidbey ETL hooks must be turned off. - if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled()) + if (!g_profControlBlock.mainProfilerInfo.pProfInterface->IsClientIDToFunctionIDMappingEnabled()) { goto LExit; } @@ -10835,14 +10903,14 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec // key to retrieve the corresponding clientID from the internal FunctionID hash table. FunctionID functionId = clientData; _ASSERTE(functionId != NULL); - clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId); + clientData = g_profControlBlock.mainProfilerInfo.pProfInterface->LookupClientIDFromCache(functionId); // // Whidbey Fast-Path ELT // if (CORProfilerELT2FastPathTailcallEnabled()) { - g_profControlBlock.pProfInterface->GetTailcall2Hook()( + g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall2Hook()( functionId, clientData, NULL); @@ -10857,7 +10925,7 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec HRESULT hr = ProfilingGetFunctionTailcall3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo); _ASSERTE(hr == S_OK); - g_profControlBlock.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo); + g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo); goto LExit; } @@ -10867,7 +10935,7 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec // in the first place. (Note that SetEnterLeaveFunctionHooks* will return // an error unless it's called in the profiler's Initialize(), so a profiler can't change // its mind about where the hooks are.) - _ASSERTE(g_profControlBlock.pProfInterface->GetTailcallHook() != NULL); + _ASSERTE(g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcallHook() != NULL); // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether @@ -10878,7 +10946,7 @@ HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpec // // Everett ELT // - g_profControlBlock.pProfInterface->GetTailcallHook()((FunctionID)clientData); + g_profControlBlock.mainProfilerInfo.pProfInterface->GetTailcallHook()((FunctionID)clientData); LExit: diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.h b/src/coreclr/vm/proftoeeinterfaceimpl.h index de5b75a3434..1cb340713ac 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.h +++ b/src/coreclr/vm/proftoeeinterfaceimpl.h @@ -145,6 +145,9 @@ typedef struct _PROFILER_STACK_WALK_DATA PROFILER_STACK_WALK_DATA; class ProfToEEInterfaceImpl : public ICorProfilerInfo12 { +private: + ProfilerInfo *m_pProfilerInfo; + public: // Internal Housekeeping @@ -156,6 +159,12 @@ public: virtual ~ProfToEEInterfaceImpl(); HRESULT Init(); + void SetProfilerInfo(ProfilerInfo *pProfilerInfo) + { + LIMITED_METHOD_CONTRACT; + m_pProfilerInfo = pProfilerInfo; + } + // IUnknown ULONG STDMETHODCALLTYPE AddRef(); ULONG STDMETHODCALLTYPE Release(); @@ -694,7 +703,6 @@ public: protected: // Internal Helper Functions - static void EventPipeCallbackHelper(EventPipeProvider *provider, DWORD eventId, DWORD eventVersion, @@ -706,7 +714,8 @@ protected: LPCGUID pRelatedActivityId, Thread *pEventThread, ULONG numStackFrames, - UINT_PTR stackFrames[]); + UINT_PTR stackFrames[], + void *additionalData); HRESULT GetCodeInfoHelper(FunctionID functionId, ReJITID reJitId, diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp index a7a7e0394a1..cf2803dec93 100644 --- a/src/coreclr/vm/readytoruninfo.cpp +++ b/src/coreclr/vm/readytoruninfo.cpp @@ -946,10 +946,10 @@ PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, PrepareCodeConfig* pConfig #ifndef CROSSGEN_COMPILE #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches()); - g_profControlBlock.pProfInterface-> + BEGIN_PROFILER_CALLBACK(CORProfilerTrackCacheSearches()); + (&g_profControlBlock)-> JITCachedFunctionSearchStarted((FunctionID)pMD, &fShouldSearchCache); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } if (!fShouldSearchCache) { @@ -1001,10 +1001,10 @@ PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, PrepareCodeConfig* pConfig #ifndef CROSSGEN_COMPILE #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackCacheSearches()); - g_profControlBlock.pProfInterface-> + BEGIN_PROFILER_CALLBACK(CORProfilerTrackCacheSearches()); + (&g_profControlBlock)-> JITCachedFunctionSearchFinished((FunctionID)pMD, COR_PRF_CACHED_FUNCTION_FOUND); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED #endif // CROSSGEN_COMPILE diff --git a/src/coreclr/vm/rejit.cpp b/src/coreclr/vm/rejit.cpp index ff180ceba33..d66c999c7ce 100644 --- a/src/coreclr/vm/rejit.cpp +++ b/src/coreclr/vm/rejit.cpp @@ -1079,12 +1079,12 @@ HRESULT ReJitManager::ConfigureILCodeVersion(ILCodeVersion ilCodeVersion) } else { - BEGIN_PIN_PROFILER(CORProfilerPresent()); - hr = g_profControlBlock.pProfInterface->GetReJITParameters( + BEGIN_PROFILER_CALLBACK(CORProfilerPresent()); + hr = (&g_profControlBlock)->GetReJITParameters( (ModuleID)pModule, methodDef, pFuncControl); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } } diff --git a/src/coreclr/vm/rejit.inl b/src/coreclr/vm/rejit.inl index b69b63d9f55..f59c536af78 100644 --- a/src/coreclr/vm/rejit.inl +++ b/src/coreclr/vm/rejit.inl @@ -68,17 +68,17 @@ inline void ReJitManager::ReportReJITError(Module* pModule, mdMethodDef methodDe CONTRACTL_END; { - BEGIN_PIN_PROFILER(CORProfilerPresent()); + BEGIN_PROFILER_CALLBACK(CORProfilerEnableRejit()); _ASSERTE(CORProfilerEnableRejit()); { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ReJITError( + (&g_profControlBlock)->mainProfilerInfo.pProfInterface->ReJITError( reinterpret_cast< ModuleID > (pModule), methodDef, reinterpret_cast< FunctionID > (pMD), hrStatus); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED } diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 401be0abd27..a8851f307ed 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -2304,9 +2304,9 @@ void QCALLTYPE RuntimeMethodHandle::Destroy(MethodDesc * pMethod) // Fire Unload Dynamic Method Event here ETW::MethodLog::DynamicMethodDestroyed(pMethod); - BEGIN_PIN_PROFILER(CORProfilerIsMonitoringDynamicFunctionUnloads()); - g_profControlBlock.pProfInterface->DynamicMethodUnloaded((FunctionID)pMethod); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackDynamicFunctionUnloads()); + (&g_profControlBlock)->DynamicMethodUnloaded((FunctionID)pMethod); + END_PROFILER_CALLBACK(); pDynamicMethodDesc->Destroy(); diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index ee66f3ebe63..4dfa4a22b3f 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -762,17 +762,17 @@ Thread* SetupThread() // thread has been created. if (!IsGCSpecialThread()) { - BEGIN_PIN_PROFILER(CORProfilerTrackThreads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackThreads()); { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ThreadCreated( + (&g_profControlBlock)->ThreadCreated( (ThreadID)pThread); } DWORD osThreadId = ::GetCurrentThreadId(); - g_profControlBlock.pProfInterface->ThreadAssignedToOSThread( + (&g_profControlBlock)->ThreadAssignedToOSThread( (ThreadID)pThread, osThreadId); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -1429,9 +1429,6 @@ Thread::Thread() m_debuggerFilterContext = NULL; m_fInteropDebuggingHijacked = FALSE; m_profilerCallbackState = 0; -#if defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA) - m_dwProfilerEvacuationCounter = 0; -#endif // defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA) m_pProfilerFilterContext = NULL; @@ -1871,20 +1868,20 @@ BOOL Thread::HasStarted() // information if (!IsGCSpecial()) { - BEGIN_PIN_PROFILER(CORProfilerTrackThreads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackThreads()); BOOL gcOnTransition = GC_ON_TRANSITIONS(FALSE); // disable GCStress 2 to avoid the profiler receiving a RuntimeThreadSuspended notification even before the ThreadCreated notification - + { GCX_PREEMP(); - g_profControlBlock.pProfInterface->ThreadCreated((ThreadID) this); + (&g_profControlBlock)->ThreadCreated((ThreadID) this); } GC_ON_TRANSITIONS(gcOnTransition); DWORD osThreadId = ::GetCurrentThreadId(); - g_profControlBlock.pProfInterface->ThreadAssignedToOSThread( + (&g_profControlBlock)->ThreadAssignedToOSThread( (ThreadID) this, osThreadId); - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -3009,10 +3006,10 @@ void Thread::OnThreadTerminate(BOOL holdingLock) #ifdef PROFILING_SUPPORTED // If a profiler is present, then notify the profiler of thread destroy { - BEGIN_PIN_PROFILER(CORProfilerTrackThreads()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackThreads()); GCX_PREEMP(); - g_profControlBlock.pProfInterface->ThreadDestroyed((ThreadID) this); - END_PIN_PROFILER(); + (&g_profControlBlock)->ThreadDestroyed((ThreadID) this); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index 5fe312d8e86..0aadbf40260 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -3623,16 +3623,6 @@ private: //--------------------------------------------------------------- DWORD m_profilerCallbackState; -#if defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA) - //--------------------------------------------------------------- - // m_dwProfilerEvacuationCounter keeps track of how many profiler - // callback calls remain on the stack - //--------------------------------------------------------------- - // Why volatile? - // See code:ProfilingAPIUtility::InitializeProfiling#LoadUnloadCallbackSynchronization. - Volatile<DWORD> m_dwProfilerEvacuationCounter; -#endif // defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA) - private: UINT32 m_workerThreadPoolCompletionCount; static UINT64 s_workerThreadPoolCompletionCountOverflow; @@ -3802,30 +3792,6 @@ public: return m_pProfilerFilterContext; } -#ifdef PROFILING_SUPPORTED - - FORCEINLINE DWORD GetProfilerEvacuationCounter(void) - { - LIMITED_METHOD_CONTRACT; - return m_dwProfilerEvacuationCounter; - } - - FORCEINLINE void IncProfilerEvacuationCounter(void) - { - LIMITED_METHOD_CONTRACT; - m_dwProfilerEvacuationCounter++; - _ASSERTE(m_dwProfilerEvacuationCounter != 0U); - } - - FORCEINLINE void DecProfilerEvacuationCounter(void) - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(m_dwProfilerEvacuationCounter != 0U); - m_dwProfilerEvacuationCounter--; - } - -#endif // PROFILING_SUPPORTED - //------------------------------------------------------------------------- // The hijack lock enforces that a thread on which a profiler is currently // performing a stack walk cannot be hijacked. diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp index d9d2c9b0ee7..cf09d505b1c 100644 --- a/src/coreclr/vm/threadsuspend.cpp +++ b/src/coreclr/vm/threadsuspend.cpp @@ -401,12 +401,12 @@ retry: #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackSuspends()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends()); if (str == STR_Success) { - g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)this); + (&g_profControlBlock)->RuntimeThreadSuspended((ThreadID)this); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -456,12 +456,12 @@ DWORD Thread::ResumeThread() } #ifdef PROFILING_SUPPORTED { - BEGIN_PIN_PROFILER(CORProfilerTrackSuspends()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends()); if ((res != 0) && (res != (DWORD)-1)) { - g_profControlBlock.pProfInterface->RuntimeThreadResumed((ThreadID)this); + (&g_profControlBlock)->RuntimeThreadResumed((ThreadID)this); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif return res; @@ -2142,12 +2142,12 @@ void Thread::RareDisablePreemptiveGC() // If profiler desires GC events, notify it that this thread is waiting until the GC is over // Do not send suspend notifications for debugger suspensions { - BEGIN_PIN_PROFILER(CORProfilerTrackSuspends()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends()); if (!(m_State & TS_DebugSuspendPending)) { - g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)this); + (&g_profControlBlock)->RuntimeThreadSuspended((ThreadID)this); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -2168,9 +2168,9 @@ void Thread::RareDisablePreemptiveGC() #ifdef PROFILING_SUPPORTED // Let the profiler know that this thread is resuming { - BEGIN_PIN_PROFILER(CORProfilerTrackSuspends()); - g_profControlBlock.pProfInterface->RuntimeThreadResumed((ThreadID)this); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends()); + (&g_profControlBlock)->RuntimeThreadResumed((ThreadID)this); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED } @@ -3226,12 +3226,12 @@ void ThreadSuspend::SuspendRuntime(ThreadSuspend::SUSPEND_REASON reason) // If the profiler desires information about GCs, then let it know that one // is starting. { - BEGIN_PIN_PROFILER(CORProfilerTrackSuspends()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends()); _ASSERTE(reason != ThreadSuspend::SUSPEND_FOR_DEBUGGER); _ASSERTE(reason != ThreadSuspend::SUSPEND_FOR_DEBUGGER_SWEEP); { - g_profControlBlock.pProfInterface->RuntimeSuspendStarted( + (&g_profControlBlock)->RuntimeSuspendStarted( GCSuspendReasonToProfSuspendReason(reason)); } if (pCurThread) @@ -3239,9 +3239,9 @@ void ThreadSuspend::SuspendRuntime(ThreadSuspend::SUSPEND_REASON reason) // Notify the profiler that the thread that is actually doing the GC is 'suspended', // meaning that it is doing stuff other than run the managed code it was before the // GC started. - g_profControlBlock.pProfInterface->RuntimeThreadSuspended((ThreadID)pCurThread); + (&g_profControlBlock)->RuntimeThreadSuspended((ThreadID)pCurThread); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -3588,9 +3588,9 @@ void ThreadSuspend::SuspendRuntime(ThreadSuspend::SUSPEND_REASON reason) #ifdef PROFILING_SUPPORTED // If a profiler is keeping track of GC events, notify it { - BEGIN_PIN_PROFILER(CORProfilerTrackSuspends()); - g_profControlBlock.pProfInterface->RuntimeSuspendFinished(); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends()); + (&g_profControlBlock)->RuntimeSuspendFinished(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -3711,12 +3711,12 @@ void ThreadSuspend::ResumeRuntime(BOOL bFinishedGC, BOOL SuspendSucceded) #ifdef PROFILING_SUPPORTED // Need to give resume event for the GC thread { - BEGIN_PIN_PROFILER(CORProfilerTrackSuspends()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends()); if (pCurThread) { - g_profControlBlock.pProfInterface->RuntimeThreadResumed((ThreadID)pCurThread); + (&g_profControlBlock)->RuntimeThreadResumed((ThreadID)pCurThread); } - END_PIN_PROFILER(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -3739,10 +3739,10 @@ void ThreadSuspend::ResumeRuntime(BOOL bFinishedGC, BOOL SuspendSucceded) // This thread is logically "resuming" from a GC now. Tell the profiler. // { - BEGIN_PIN_PROFILER(CORProfilerTrackSuspends()); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends()); GCX_PREEMP(); - g_profControlBlock.pProfInterface->RuntimeResumeFinished(); - END_PIN_PROFILER(); + (&g_profControlBlock)->RuntimeResumeFinished(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED @@ -5481,9 +5481,9 @@ void ThreadSuspend::RestartEE(BOOL bFinishedGC, BOOL SuspendSucceded) // corresponding call to RuntimeSuspendStarted is done at a lower architectural layer, // in ThreadSuspend::SuspendRuntime. { - BEGIN_PIN_PROFILER(CORProfilerTrackSuspends()); - g_profControlBlock.pProfInterface->RuntimeResumeStarted(); - END_PIN_PROFILER(); + BEGIN_PROFILER_CALLBACK(CORProfilerTrackSuspends()); + (&g_profControlBlock)->RuntimeResumeStarted(); + END_PROFILER_CALLBACK(); } #endif // PROFILING_SUPPORTED |