Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: add PGO random stress testing support #58294

Merged
merged 3 commits into from
Aug 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions eng/pipelines/common/templates/runtimes/run-test-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,9 @@ jobs:
- defaultpgo
- dynamicpgo
- fullpgo
- fullpgo_random_gdv
- fullpgo_random_edge
- fullpgo_random_gdv_edge
${{ if in(parameters.testGroup, 'gc-longrunning') }}:
longRunningGcTests: true
scenarios:
Expand Down
3 changes: 3 additions & 0 deletions eng/pipelines/libraries/run-test-job.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,7 @@ jobs:
- defaultpgo
- dynamicpgo
- fullpgo
- fullpgo_random_gdv
- fullpgo_random_edge
- fullpgo_random_gdv_edge

88 changes: 77 additions & 11 deletions src/coreclr/jit/fgprofile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2229,6 +2229,14 @@ class EfficientEdgeCountReconstructor : public SpanningTreeVisitor
//
void EfficientEdgeCountReconstructor::Prepare()
{
#ifdef DEBUG
// If we're going to assign random counts we want to make sure
// at least one BBJ_RETURN block has nonzero counts.
//
unsigned nReturns = 0;
unsigned nZeroReturns = 0;
#endif

// Create per-block info, and set up the key to block map.
//
for (BasicBlock* const block : m_comp->Blocks())
Expand All @@ -2241,6 +2249,13 @@ void EfficientEdgeCountReconstructor::Prepare()
//
m_blocks++;
m_unknownBlocks++;

#ifdef DEBUG
if (block->bbJumpKind == BBJ_RETURN)
{
nReturns++;
}
#endif
}

// Create edges for schema entries with edge counts, and set them up in
Expand All @@ -2254,17 +2269,6 @@ void EfficientEdgeCountReconstructor::Prepare()
case ICorJitInfo::PgoInstrumentationKind::EdgeIntCount:
case ICorJitInfo::PgoInstrumentationKind::EdgeLongCount:
{
// Optimization TODO: if profileCount is zero, we can just ignore this edge
// and the right things will happen.
//
uint64_t const profileCount =
schemaEntry.InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::EdgeIntCount
? *(uint32_t*)(m_comp->fgPgoData + schemaEntry.Offset)
: *(uint64_t*)(m_comp->fgPgoData + schemaEntry.Offset);
BasicBlock::weight_t const weight = (BasicBlock::weight_t)profileCount;

m_allWeightsZero &= (profileCount == 0);

// Find the blocks.
//
BasicBlock* sourceBlock = nullptr;
Expand All @@ -2291,6 +2295,68 @@ void EfficientEdgeCountReconstructor::Prepare()
continue;
}

// Optimization TODO: if profileCount is zero, we can just ignore this edge
// and the right things will happen.
//
uint64_t profileCount =
schemaEntry.InstrumentationKind == ICorJitInfo::PgoInstrumentationKind::EdgeIntCount
? *(uint32_t*)(m_comp->fgPgoData + schemaEntry.Offset)
: *(uint64_t*)(m_comp->fgPgoData + schemaEntry.Offset);

#ifdef DEBUG
// Optional stress mode to use a random count. Because edge profile counters have
// little redundancy, random count assignments should generally lead to a consistent
// set of block counts.
//
const bool useRandom = (JitConfig.JitRandomEdgeCounts() != 0) && (nReturns > 0);

if (useRandom)
{
// Reuse the random inliner's random state.
// Config setting will serve as the random seed, if no other seed has been supplied already.
//
CLRRandom* const random =
m_comp->impInlineRoot()->m_inlineStrategy->GetRandom(JitConfig.JitRandomEdgeCounts());

const bool isReturn = sourceBlock->bbJumpKind == BBJ_RETURN;

// We simulate the distribution of counts seen in StdOptimizationData.Mibc.
//
const double rval = random->NextDouble();

// Ensure at least one return has nonzero counts.
//
if ((rval <= 0.5) && (!isReturn || (nZeroReturns < (nReturns - 1))))
{
profileCount = 0;
if (isReturn)
{
nZeroReturns++;
}
}
else if (rval <= 0.85)
{
profileCount = random->Next(1, 101);
}
else if (rval <= 0.96)
{
profileCount = random->Next(101, 10001);
}
else if (rval <= 0.995)
{
profileCount = random->Next(10001, 100001);
}
else
{
profileCount = random->Next(100001, 1000001);
}
}
#endif

BasicBlock::weight_t const weight = (BasicBlock::weight_t)profileCount;

m_allWeightsZero &= (profileCount == 0);

Edge* const edge = new (m_allocator) Edge(sourceBlock, targetBlock);

JITDUMP("... adding known edge " FMT_BB " -> " FMT_BB ": weight " FMT_WT "\n",
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/jit/jitconfigvalues.h
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,8 @@ CONFIG_INTEGER(JitCollect64BitCounts, W("JitCollect64BitCounts"), 0) // Collect
// Profile consumption options
CONFIG_INTEGER(JitDisablePgo, W("JitDisablePgo"), 0) // Ignore pgo data for all methods
#if defined(DEBUG)
CONFIG_STRING(JitEnablePgoRange, W("JitEnablePgoRange")) // Enable pgo data for only some methods
CONFIG_STRING(JitEnablePgoRange, W("JitEnablePgoRange")) // Enable pgo data for only some methods
CONFIG_INTEGER(JitRandomEdgeCounts, W("JitRandomEdgeCounts"), 0) // Substitute random values for edge counts
CONFIG_INTEGER(JitCrossCheckDevirtualizationAndPGO, W("JitCrossCheckDevirtualizationAndPGO"), 0)
CONFIG_INTEGER(JitNoteFailedExactDevirtualization, W("JitNoteFailedExactDevirtualization"), 0)
#endif // debug
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/jit/likelyclass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ CORINFO_CLASS_HANDLE Compiler::getRandomClass(ICorJitInfo::PgoInstrumentationSch

// Choose an entry at random.
//
unsigned randomEntryIndex = random->Next(0, h.countHistogramElements - 1);
unsigned randomEntryIndex = random->Next(0, h.countHistogramElements);
LikelyClassHistogramEntry randomEntry = h.HistogramEntryAt(randomEntryIndex);

if (ICorJitInfo::IsUnknownTypeHandle(randomEntry.m_mt))
Expand Down
5 changes: 5 additions & 0 deletions src/tests/Common/testenvironment.proj
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
COMPlus_JitInlinePolicyProfile;
COMPlus_JitClassProfiling;
COMPlus_JitEdgeProfiling;
COMPlus_JitRandomGuardedDevirtualization;
COMPlus_JitRandomEdgeCounts;
RunningIlasmRoundTrip
</COMPlusVariables>
</PropertyGroup>
Expand Down Expand Up @@ -157,6 +159,9 @@
<TestEnvironment Include="defaultpgo" TieredPGO="1" TieredCompilation="1" />
<TestEnvironment Include="dynamicpgo" TieredPGO="1" TieredCompilation="1" TC_QuickJitForLoops="1" />
<TestEnvironment Include="fullpgo" TieredPGO="1" TieredCompilation="1" TC_QuickJitForLoops="1" ReadyToRun="0"/>
<TestEnvironment Include="fullpgo_random_gdv" TieredPGO="1" TieredCompilation="1" TC_QuickJitForLoops="1" ReadyToRun="0" JitRandomGuardedDevirtualization="1"/>
<TestEnvironment Include="fullpgo_random_edge" TieredPGO="1" TieredCompilation="1" TC_QuickJitForLoops="1" ReadyToRun="0" JitRandomEdgeCounts="1"/>
<TestEnvironment Include="fullpgo_random_gdv_edge" TieredPGO="1" TieredCompilation="1" TC_QuickJitForLoops="1" ReadyToRun="0" JitRandomGuardedDevirtualization="1" JitRandomEdgeCounts="1"/>
<TestEnvironment Include="gcstandalone" Condition="'$(TargetsWindows)' == 'true'" GCName="clrgc.dll"/>
<TestEnvironment Include="gcstandalone" Condition="'$(TargetsWindows)' != 'true'" GCName="libclrgc.so"/>
<TestEnvironment Include="gcstandaloneserver" Condition="'$(TargetsWindows)' == 'true'" gcServer="1" GCName="clrgc.dll"/>
Expand Down