#ifdef FEATURE_PERFMAP
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_PerfMapEnabled, W("PerfMapEnabled"), 0, "This flag is used on Linux to enable writing /tmp/perf-$pid.map. It is disabled by default", CLRConfig::REGUTIL_default)
RETAIL_CONFIG_DWORD_INFO_EX(EXTERNAL_PerfMapIgnoreSignal, W("PerfMapIgnoreSignal"), 0, "When perf map is enabled, this option will configure the specified signal to be accepted and ignored as a marker in the perf logs. It is disabled by default", CLRConfig::REGUTIL_default)
+RETAIL_CONFIG_DWORD_INFO(EXTERNAL_PerfMapShowOptimizationTiers, W("PerfMapShowOptimizationTiers"), 1, "Shows optimization tiers in the perf map for methods, as part of the symbol name. Useful for seeing separate stack frames for different optimization tiers of each method.")
#endif
RETAIL_CONFIG_STRING_INFO(EXTERNAL_StartupDelayMS, W("StartupDelayMS"), "")
}MethodStructs;
- enum class JitOptimizationTier
- {
- Unknown, // to identify older runtimes that would send this value
- MinOptJitted,
- Optimized,
- QuickJitted,
- OptimizedTier1,
-
- Count
- };
-
static const UINT8 MethodFlagsJitOptimizationTierShift = 7;
static const unsigned int MethodFlagsJitOptimizationTierLowMask = 0x7;
if(pMethodDesc->GetMethodTable_NoLogging())
bIsGenericMethod = pMethodDesc->HasClassOrMethodInstantiation_NoLogging();
- int jitOptimizationTier = -1;
NativeCodeVersionId nativeCodeId = 0;
ulMethodFlags = ulMethodFlags |
(bHasSharedGenericCode ? ETW::MethodLog::MethodStructs::SharedGenericCode : 0) |
ulMethodFlags |= ETW::MethodLog::MethodStructs::ReadyToRunRejectedPrecompiledCode;
}
- if (pConfig->JitSwitchedToMinOpt())
- {
- jitOptimizationTier = (int)JitOptimizationTier::MinOptJitted;
- }
-#ifdef FEATURE_TIERED_COMPILATION
- else if (pConfig->JitSwitchedToOptimized())
- {
- _ASSERTE(pMethodDesc->IsEligibleForTieredCompilation());
- _ASSERTE(pConfig->GetCodeVersion().GetOptimizationTier() == NativeCodeVersion::OptimizationTierOptimized);
- jitOptimizationTier = (int)JitOptimizationTier::Optimized;
- }
- else if (pMethodDesc->IsEligibleForTieredCompilation())
- {
- switch (pConfig->GetCodeVersion().GetOptimizationTier())
- {
- case NativeCodeVersion::OptimizationTier0:
- jitOptimizationTier = (int)JitOptimizationTier::QuickJitted;
- break;
-
- case NativeCodeVersion::OptimizationTier1:
- jitOptimizationTier = (int)JitOptimizationTier::OptimizedTier1;
- break;
-
- case NativeCodeVersion::OptimizationTierOptimized:
- jitOptimizationTier = (int)JitOptimizationTier::Optimized;
- break;
-
- default:
- UNREACHABLE();
- }
- }
-#endif
-
#ifdef FEATURE_CODE_VERSIONING
nativeCodeId = pConfig->GetCodeVersion().GetVersionId();
#endif
}
- if (jitOptimizationTier < 0)
- {
- if (pMethodDesc->IsJitOptimizationDisabled())
- {
- jitOptimizationTier = (int)JitOptimizationTier::MinOptJitted;
- }
- else
- {
- jitOptimizationTier = (int)JitOptimizationTier::Optimized;
- }
- }
- static_assert_no_msg((unsigned int)JitOptimizationTier::Count - 1 <= MethodFlagsJitOptimizationTierLowMask);
- _ASSERTE((unsigned int)jitOptimizationTier <= MethodFlagsJitOptimizationTierLowMask);
+ unsigned int jitOptimizationTier = (unsigned int)PrepareCodeConfig::GetJitOptimizationTier(pConfig, pMethodDesc);
+ static_assert_no_msg((unsigned int)PrepareCodeConfig::JitOptimizationTier::Count - 1 <= MethodFlagsJitOptimizationTierLowMask);
+ _ASSERTE(jitOptimizationTier <= MethodFlagsJitOptimizationTierLowMask);
_ASSERTE(((ulMethodFlags >> MethodFlagsJitOptimizationTierShift) & MethodFlagsJitOptimizationTierLowMask) == 0);
- ulMethodFlags |= (unsigned int)jitOptimizationTier << MethodFlagsJitOptimizationTierShift;
+ ulMethodFlags |= jitOptimizationTier << MethodFlagsJitOptimizationTierShift;
// Intentionally set the extent flags (cold vs. hot) only after all the other common
// flags (above) have been set.
void SetReadyToRunRejectedPrecompiledCode();
#ifndef CROSSGEN_COMPILE
+public:
+ enum class JitOptimizationTier : UINT8
+ {
+ Unknown, // to identify older runtimes that would send this value
+ MinOptJitted,
+ Optimized,
+ QuickJitted,
+ OptimizedTier1,
+
+ Count
+ };
+
+ static JitOptimizationTier GetJitOptimizationTier(PrepareCodeConfig *config, MethodDesc *methodDesc);
+ static const char *GetJitOptimizationTierStr(PrepareCodeConfig *config, MethodDesc *methodDesc);
+
bool JitSwitchedToMinOpt() const
{
LIMITED_METHOD_CONTRACT;
}
#ifdef FEATURE_TIERED_COMPILATION
+public:
bool JitSwitchedToOptimized() const
{
LIMITED_METHOD_CONTRACT;
}
#endif
+public:
PrepareCodeConfig *GetNextInSameThread() const
{
LIMITED_METHOD_CONTRACT;
#endif
PerfMap * PerfMap::s_Current = nullptr;
+bool PerfMap::s_ShowOptimizationTiers = false;
// Initialize the map for the process - called from EEStartupHelper.
void PerfMap::Initialize()
{
PAL_IgnoreProfileSignal(signalNum);
}
+
+ if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapShowOptimizationTiers) != 0)
+ {
+ s_ShowOptimizationTiers = true;
+ }
}
}
}
// Log a method to the map.
-void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
+void PerfMap::LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, const char *optimizationTier)
{
CONTRACTL{
THROWS;
// Build the map file line.
StackScratchBuffer scratch;
SString line;
- line.Printf(FMT_CODE_ADDR " %x %s\n", pCode, codeSize, fullMethodSignature.GetANSI(scratch));
+ line.Printf(FMT_CODE_ADDR " %x %s", pCode, codeSize, fullMethodSignature.GetANSI(scratch));
+ if (optimizationTier != nullptr && s_ShowOptimizationTiers)
+ {
+ line.AppendPrintf("[%s]\n", optimizationTier);
+ }
+ else
+ {
+ line.Append(W('\n'));
+ }
// Write the line.
WriteLine(line);
// Log a method to the map.
-void PerfMap::LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize)
+void PerfMap::LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, PrepareCodeConfig *pConfig)
{
LIMITED_METHOD_CONTRACT;
- if (s_Current != nullptr)
+ if (s_Current == nullptr)
+ {
+ return;
+ }
+
+ const char *optimizationTier = nullptr;
+#ifndef CROSSGEN_COMPILE
+ if (s_ShowOptimizationTiers)
{
- s_Current->LogMethod(pMethod, pCode, codeSize);
+ optimizationTier = PrepareCodeConfig::GetJitOptimizationTierStr(pConfig, pMethod);
}
+#endif // CROSSGEN_COMPILE
+
+ s_Current->LogMethod(pMethod, pCode, codeSize, optimizationTier);
}
// Log a set of stub to the map.
MethodDesc *hotDesc = mi.GetMethodDesc();
hotDesc->CheckRestore();
- LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), baseAddr);
+ LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), baseAddr, nullptr);
}
return;
}
{
MethodDesc* hotDesc = mi.GetMethodDesc();
- LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), baseAddr);
+ LogPreCompiledMethod(hotDesc, mi.GetMethodStartAddress(), baseAddr, "ReadyToRun");
}
}
// Log a pre-compiled method to the perfmap.
-void NativeImagePerfMap::LogPreCompiledMethod(MethodDesc * pMethod, PCODE pCode, SIZE_T baseAddr)
+void NativeImagePerfMap::LogPreCompiledMethod(MethodDesc * pMethod, PCODE pCode, SIZE_T baseAddr, const char *optimizationTier)
{
STANDARD_VM_CONTRACT;
// Emit an entry for each section if it is used.
if (methodRegionInfo.hotSize > 0)
{
- LogMethod(pMethod, (PCODE)methodRegionInfo.hotStartAddress - baseAddr, methodRegionInfo.hotSize);
+ LogMethod(pMethod, (PCODE)methodRegionInfo.hotStartAddress - baseAddr, methodRegionInfo.hotSize, optimizationTier);
}
if (methodRegionInfo.coldSize > 0)
{
- LogMethod(pMethod, (PCODE)methodRegionInfo.coldStartAddress - baseAddr, methodRegionInfo.coldSize);
+ LogMethod(pMethod, (PCODE)methodRegionInfo.coldStartAddress - baseAddr, methodRegionInfo.coldSize, optimizationTier);
}
}
// The one and only PerfMap for the process.
static PerfMap * s_Current;
+ // Indicates whether optimization tiers should be shown for methods in perf maps
+ static bool s_ShowOptimizationTiers;
+
// The file stream to write the map to.
CFileStream * m_FileStream;
void OpenFile(SString& path);
// Does the actual work to log a method to the map.
- void LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize);
+ void LogMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, const char *optimizationTier);
// Does the actual work to log an image
void LogImage(PEFile * pFile);
static void LogImageLoad(PEFile * pFile);
// Log a JIT compiled method to the map.
- static void LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize);
+ static void LogJITCompiledMethod(MethodDesc * pMethod, PCODE pCode, size_t codeSize, PrepareCodeConfig *pConfig);
// Log a set of stub to the map.
static void LogStubs(const char* stubType, const char* stubOwner, PCODE pCode, size_t codeSize);
{
private:
// Log a pre-compiled method to the map.
- void LogPreCompiledMethod(MethodDesc * pMethod, PCODE pCode, SIZE_T baseAddr);
+ void LogPreCompiledMethod(MethodDesc * pMethod, PCODE pCode, SIZE_T baseAddr, const char *optimizationTier);
public:
// Construct a new map for a native image.
{
#ifdef FEATURE_PERFMAP
// Save the JIT'd method information so that perf can resolve JIT'd call frames.
- PerfMap::LogJITCompiledMethod(this, pCode, sizeOfCode);
+ PerfMap::LogJITCompiledMethod(this, pCode, sizeOfCode, pConfig);
#endif
}
return m_mayUsePrecompiledCode;
}
+PrepareCodeConfig::JitOptimizationTier PrepareCodeConfig::GetJitOptimizationTier(
+ PrepareCodeConfig *config,
+ MethodDesc *methodDesc)
+{
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(methodDesc != nullptr);
+ _ASSERTE(config == nullptr || methodDesc == config->GetMethodDesc());
+
+ if (config != nullptr)
+ {
+ if (config->JitSwitchedToMinOpt())
+ {
+ return JitOptimizationTier::MinOptJitted;
+ }
+ #ifdef FEATURE_TIERED_COMPILATION
+ else if (config->JitSwitchedToOptimized())
+ {
+ _ASSERTE(methodDesc->IsEligibleForTieredCompilation());
+ _ASSERTE(config->GetCodeVersion().GetOptimizationTier() == NativeCodeVersion::OptimizationTierOptimized);
+ return JitOptimizationTier::Optimized;
+ }
+ else if (methodDesc->IsEligibleForTieredCompilation())
+ {
+ switch (config->GetCodeVersion().GetOptimizationTier())
+ {
+ case NativeCodeVersion::OptimizationTier0:
+ return JitOptimizationTier::QuickJitted;
+
+ case NativeCodeVersion::OptimizationTier1:
+ return JitOptimizationTier::OptimizedTier1;
+
+ case NativeCodeVersion::OptimizationTierOptimized:
+ return JitOptimizationTier::Optimized;
+
+ default:
+ UNREACHABLE();
+ }
+ }
+ #endif
+ }
+
+ return methodDesc->IsJitOptimizationDisabled() ? JitOptimizationTier::MinOptJitted : JitOptimizationTier::Optimized;
+}
+
+const char *PrepareCodeConfig::GetJitOptimizationTierStr(PrepareCodeConfig *config, MethodDesc *methodDesc)
+{
+ WRAPPER_NO_CONTRACT;
+
+ switch (GetJitOptimizationTier(config, methodDesc))
+ {
+ case JitOptimizationTier::Unknown: return "Unknown";
+ case JitOptimizationTier::MinOptJitted: return "MinOptJitted";
+ case JitOptimizationTier::Optimized: return "Optimized";
+ case JitOptimizationTier::QuickJitted: return "QuickJitted";
+ case JitOptimizationTier::OptimizedTier1: return "OptimizedTier1";
+
+ default:
+ UNREACHABLE();
+ }
+}
+
#ifdef FEATURE_CODE_VERSIONING
VersionedPrepareCodeConfig::VersionedPrepareCodeConfig() {}