summaryrefslogtreecommitdiff
path: root/src/vm/eventtrace.cpp
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-04-07 17:23:32 -0700
committerdotnet-bot <dotnet-bot@microsoft.com>2015-04-07 17:23:32 -0700
commitf1c0c7d95164abbbc4dfbd5bc312ef543256b0e0 (patch)
tree7a7156b56e9b9283ae0668491157bf1526077a3a /src/vm/eventtrace.cpp
parent1afe5ce4f45045d724a4e129df4b816655d486fb (diff)
downloadcoreclr-f1c0c7d95164abbbc4dfbd5bc312ef543256b0e0.tar.gz
coreclr-f1c0c7d95164abbbc4dfbd5bc312ef543256b0e0.tar.bz2
coreclr-f1c0c7d95164abbbc4dfbd5bc312ef543256b0e0.zip
Merge changes from parent branch
[tfs-changeset: 1448103]
Diffstat (limited to 'src/vm/eventtrace.cpp')
-rw-r--r--src/vm/eventtrace.cpp241
1 files changed, 162 insertions, 79 deletions
diff --git a/src/vm/eventtrace.cpp b/src/vm/eventtrace.cpp
index ccbd32d46b..c55c378005 100644
--- a/src/vm/eventtrace.cpp
+++ b/src/vm/eventtrace.cpp
@@ -4741,6 +4741,27 @@ VOID ETW::InfoLog::RuntimeInformation(INT32 type)
#ifndef FEATURE_CORECLR
startupFlags = CorHost2::GetStartupFlags();
+
+ // Some of the options specified by the startup flags can be overwritten by config files.
+ // Strictly speaking since the field in this event is called StartupFlags there's nothing
+ // wrong with just showing the actual startup flags but it makes it less useful (a more
+ // appropriate name for the field is StartupOptions).
+ startupFlags &= ~STARTUP_CONCURRENT_GC;
+ if (g_pConfig->GetGCconcurrent())
+ startupFlags |= STARTUP_CONCURRENT_GC;
+
+ if (g_pConfig->DefaultSharePolicy() != AppDomain::SHARE_POLICY_UNSPECIFIED)
+ {
+ startupFlags &= ~STARTUP_LOADER_OPTIMIZATION_MASK;
+ startupFlags |= g_pConfig->DefaultSharePolicy() << 1;
+ }
+
+ startupFlags &= ~STARTUP_LEGACY_IMPERSONATION;
+ startupFlags &= ~STARTUP_ALWAYSFLOW_IMPERSONATION;
+ if (g_pConfig->ImpersonationMode() == IMP_NOFLOW)
+ startupFlags |= STARTUP_LEGACY_IMPERSONATION;
+ else if (g_pConfig->ImpersonationMode() == IMP_ALWAYSFLOW)
+ startupFlags |= STARTUP_ALWAYSFLOW_IMPERSONATION;
#endif //!FEATURE_CORECLR
// Determine the startupmode
@@ -6391,12 +6412,105 @@ VOID ETW::MethodLog::SendEventsForNgenMethods(Module *pModule, DWORD dwEventOpti
#endif // FEATURE_PREJIT
}
+// Called be ETW::MethodLog::SendEventsForJitMethods
+// Sends the ETW events once our caller determines whether or not rejit locks can be acquired
+VOID ETW::MethodLog::SendEventsForJitMethodsHelper(BaseDomain *pDomainFilter,
+ LoaderAllocator *pLoaderAllocatorFilter,
+ DWORD dwEventOptions,
+ BOOL fLoadOrDCStart,
+ BOOL fUnloadOrDCEnd,
+ BOOL fSendMethodEvent,
+ BOOL fSendILToNativeMapEvent,
+ BOOL fGetReJitIDs)
+{
+ CONTRACTL{
+ THROWS;
+ GC_NOTRIGGER;
+ } CONTRACTL_END;
+
+ EEJitManager::CodeHeapIterator heapIterator(pDomainFilter, pLoaderAllocatorFilter);
+ while (heapIterator.Next())
+ {
+ MethodDesc * pMD = heapIterator.GetMethod();
+ if (pMD == NULL)
+ continue;
+
+ TADDR codeStart = heapIterator.GetMethodCode();
+
+ // Grab rejitID from the rejit manager. In some cases, such as collectible loader
+ // allocators, we don't support rejit so we need to short circuit the call.
+ // This also allows our caller to avoid having to pre-enter the rejit
+ // manager locks.
+ // see code:#TableLockHolder
+ ReJITID rejitID =
+ fGetReJitIDs ? pMD->GetReJitManager()->GetReJitIdNoLock(pMD, codeStart) : 0;
+
+ // There are small windows of time where the heap iterator may come across a
+ // codeStart that is not yet published to the MethodDesc. This may happen if
+ // we're JITting the method right now on another thread, and have not completed
+ // yet. Detect the race, and skip the method if appropriate. (If rejitID is
+ // nonzero, there is no race, as GetReJitIdNoLock will not return a nonzero
+ // rejitID if the codeStart has not yet been published for that rejitted version
+ // of the method.) This check also catches recompilations due to EnC, which we do
+ // not want to issue events for, in order to ensure xperf's assumption that
+ // MethodDesc* + ReJITID + extent (hot vs. cold) form a unique key for code
+ // ranges of methods
+ if ((rejitID == 0) && (codeStart != PCODEToPINSTR(pMD->GetNativeCode())))
+ continue;
+
+ // When we're called to announce loads, then the methodload event itself must
+ // precede any supplemental events, so that the method load or method jitting
+ // event is the first event the profiler sees for that MethodID (and not, say,
+ // the MethodILToNativeMap event.)
+ if (fLoadOrDCStart)
+ {
+ if (fSendMethodEvent)
+ {
+ ETW::MethodLog::SendMethodEvent(
+ pMD,
+ dwEventOptions,
+ TRUE, // bIsJit
+ NULL, // namespaceOrClassName
+ NULL, // methodName
+ NULL, // methodSignature
+ codeStart,
+ rejitID);
+ }
+ }
+
+ // Send any supplemental events requested for this MethodID
+ if (fSendILToNativeMapEvent)
+ ETW::MethodLog::SendMethodILToNativeMapEvent(pMD, dwEventOptions, rejitID);
+
+ // When we're called to announce unloads, then the methodunload event itself must
+ // come after any supplemental events, so that the method unload event is the
+ // last event the profiler sees for this MethodID
+ if (fUnloadOrDCEnd)
+ {
+ if (fSendMethodEvent)
+ {
+ ETW::MethodLog::SendMethodEvent(
+ pMD,
+ dwEventOptions,
+ TRUE, // bIsJit
+ NULL, // namespaceOrClassName
+ NULL, // methodName
+ NULL, // methodSignature
+ codeStart,
+ rejitID);
+ }
+ }
+ }
+}
+
/****************************************************************************/
/* This routine sends back method events of type 'dwEventOptions', for all
JITed methods in either a given LoaderAllocator (if pLoaderAllocatorFilter is non NULL)
or in a given Domain (if pDomainFilter is non NULL) or for
all methods (if both filters are null) */
/****************************************************************************/
+// Code review indicates this method is never called with both filters NULL. Ideally we would
+// assert this and change the comment above, but given I am making a change late in the release I am being cautious
VOID ETW::MethodLog::SendEventsForJitMethods(BaseDomain *pDomainFilter, LoaderAllocator *pLoaderAllocatorFilter, DWORD dwEventOptions)
{
CONTRACTL {
@@ -6424,9 +6538,6 @@ VOID ETW::MethodLog::SendEventsForJitMethods(BaseDomain *pDomainFilter, LoaderAl
(ETW::EnumerationLog::EnumerationStructs::MethodDCStartILToNativeMap |
ETW::EnumerationLog::EnumerationStructs::MethodDCEndILToNativeMap)) != 0;
- BOOL fCollectibleLoaderAllocatorFilter =
- ((pLoaderAllocatorFilter != NULL) && (pLoaderAllocatorFilter->IsCollectible()));
-
if (fSendILToNativeMapEvent)
{
// The call to SendMethodILToNativeMapEvent assumes that the debugger's lazy
@@ -6439,83 +6550,48 @@ VOID ETW::MethodLog::SendEventsForJitMethods(BaseDomain *pDomainFilter, LoaderAl
g_pDebugInterface->InitializeLazyDataIfNecessary();
}
- // GetRejitIdNoLock requires that the rejit lock is taken already. We need to take
- // it here, before CodeHeapIterator takes the SingleUseLock because that is defined
- // ordering.
- ReJitManager::TableLockHolder lksharedRejitMgrModule(SharedDomain::GetDomain()->GetReJitManager());
- ReJitManager::TableLockHolder lkRejitMgrModule(pDomainFilter->GetReJitManager());
- EEJitManager::CodeHeapIterator heapIterator(pDomainFilter, pLoaderAllocatorFilter);
- while(heapIterator.Next())
+ // #TableLockHolder:
+ //
+ // A word about ReJitManager::TableLockHolder... As we enumerate through the functions,
+ // we may need to grab their ReJITIDs. The ReJitManager grabs its table Crst in order to
+ // fetch these. However, several other kinds of locks are being taken during this
+ // enumeration, such as the SystemDomain lock and the EEJitManager::CodeHeapIterator's
+ // lock. In order to avoid lock-leveling issues, we grab the appropriate ReJitManager
+ // table locks after SystemDomain and before CodeHeapIterator. In particular, we need to
+ // grab the SharedDomain's ReJitManager table lock as well as the specific AppDomain's
+ // ReJitManager table lock for the current AppDomain we're iterating. Why the SharedDomain's
+ // ReJitManager lock? For any given AppDomain we're iterating over, the MethodDescs we
+ // find may be managed by that AppDomain's ReJitManger OR the SharedDomain's ReJitManager.
+ // (This is due to generics and whether given instantiations may be shared based on their
+ // arguments.) Therefore, we proactively take the SharedDomain's ReJitManager's table
+ // lock up front, and then individually take the appropriate AppDomain's ReJitManager's
+ // table lock that corresponds to the domain or module we're currently iterating over.
+ //
+
+ // We only support getting rejit IDs when filtering by domain.
+ if (pDomainFilter)
+ {
+ ReJitManager::TableLockHolder lkRejitMgrSharedDomain(SharedDomain::GetDomain()->GetReJitManager());
+ ReJitManager::TableLockHolder lkRejitMgrModule(pDomainFilter->GetReJitManager());
+ SendEventsForJitMethodsHelper(pDomainFilter,
+ pLoaderAllocatorFilter,
+ dwEventOptions,
+ fLoadOrDCStart,
+ fUnloadOrDCEnd,
+ fSendMethodEvent,
+ fSendILToNativeMapEvent,
+ TRUE);
+ }
+ else
{
- MethodDesc * pMD = heapIterator.GetMethod();
- if (pMD == NULL)
- continue;
-
- TADDR codeStart = heapIterator.GetMethodCode();
-
- // Grab rejitID from the rejit manager. Short-circuit the call if we're filtering
- // by a collectible loader allocator, since rejit is not supported on RefEmit
- // assemblies.
- ReJITID rejitID =
- fCollectibleLoaderAllocatorFilter ?
- 0 :
- pMD->GetReJitManager()->GetReJitIdNoLock(pMD, codeStart);
-
- // There are small windows of time where the heap iterator may come across a
- // codeStart that is not yet published to the MethodDesc. This may happen if
- // we're JITting the method right now on another thread, and have not completed
- // yet. Detect the race, and skip the method if appropriate. (If rejitID is
- // nonzero, there is no race, as GetReJitIdNoLock will not return a nonzero
- // rejitID if the codeStart has not yet been published for that rejitted version
- // of the method.) This check also catches recompilations due to EnC, which we do
- // not want to issue events for, in order to ensure xperf's assumption that
- // MethodDesc* + ReJITID + extent (hot vs. cold) form a unique key for code
- // ranges of methods
- if ((rejitID == 0) && (codeStart != PCODEToPINSTR(pMD->GetNativeCode())))
- continue;
-
- // When we're called to announce loads, then the methodload event itself must
- // precede any supplemental events, so that the method load or method jitting
- // event is the first event the profiler sees for that MethodID (and not, say,
- // the MethodILToNativeMap event.)
- if (fLoadOrDCStart)
- {
- if (fSendMethodEvent)
- {
- ETW::MethodLog::SendMethodEvent(
- pMD,
- dwEventOptions,
- TRUE, // bIsJit
- NULL, // namespaceOrClassName
- NULL, // methodName
- NULL, // methodSignature
- codeStart,
- rejitID);
- }
- }
-
- // Send any supplemental events requested for this MethodID
- if (fSendILToNativeMapEvent)
- ETW::MethodLog::SendMethodILToNativeMapEvent(pMD, dwEventOptions, rejitID);
-
- // When we're called to announce unloads, then the methodunload event itself must
- // come after any supplemental events, so that the method unload event is the
- // last event the profiler sees for this MethodID
- if (fUnloadOrDCEnd)
- {
- if (fSendMethodEvent)
- {
- ETW::MethodLog::SendMethodEvent(
- pMD,
- dwEventOptions,
- TRUE, // bIsJit
- NULL, // namespaceOrClassName
- NULL, // methodName
- NULL, // methodSignature
- codeStart,
- rejitID);
- }
- }
+ SendEventsForJitMethodsHelper(pDomainFilter,
+ pLoaderAllocatorFilter,
+ dwEventOptions,
+ fLoadOrDCStart,
+ fUnloadOrDCEnd,
+ fSendMethodEvent,
+ fSendILToNativeMapEvent,
+ FALSE);
}
} EX_CATCH{} EX_END_CATCH(SwallowAllExceptions);
#endif // !DACCESS_COMPILE
@@ -6859,6 +6935,12 @@ VOID ETW::EnumerationLog::EnumerationHelper(Module *moduleFilter, BaseDomain *do
// Thus hitting a timeout due to a large number of methods will not affect modules rundown.tf g
ETW::EnumerationLog::IterateModule(moduleFilter, enumerationOptions);
+ // As best I can tell from code review, these if statements below are never true. There is
+ // only one caller to this method that specifies a moduleFilter, ETW::LoaderLog::ModuleLoad.
+ // That method never specifies these flags. Because it is late in a release cycle I am not
+ // making a change, but if you see this comment early in the next release cycle consider
+ // deleting this apparently dead code.
+
// DC End or Unload Jit Method events from all Domains
if (enumerationOptions & ETW::EnumerationLog::EnumerationStructs::JitMethodUnloadOrDCEndAny)
{
@@ -6895,6 +6977,7 @@ VOID ETW::EnumerationLog::EnumerationHelper(Module *moduleFilter, BaseDomain *do
ETW::EnumerationLog::IterateAppDomain(pDomain, enumerationOptions);
}
}
+
ETW::EnumerationLog::IterateDomain(SharedDomain::GetDomain(), enumerationOptions);
}
}