Skip to content

Commit 845dc11

Browse files
JIT: Move profile consistency checks to after morph (#111253)
Part of #107749. Enables profile checks for morph and post-morph phases. For benchmarks.run_pgo, 45383 methods are consistent before inlining; after, we're down to 37215, or 82%. By the time we make it to morph, 33461 methods (~74% of the original) are consistent; after morph, we're down to 29402 (~65%). The decline isn't too dramatic for this collection, though I imagine we fare worse elsewhere. --------- Co-authored-by: Andy Ayers <[email protected]>
1 parent bbe2cb9 commit 845dc11

File tree

6 files changed

+125
-87
lines changed

6 files changed

+125
-87
lines changed

src/coreclr/jit/compiler.cpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -4779,11 +4779,6 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
47794779
//
47804780
DoPhase(this, PHASE_MORPH_IMPBYREF, &Compiler::fgRetypeImplicitByRefArgs);
47814781

4782-
// Drop back to just checking profile likelihoods.
4783-
//
4784-
activePhaseChecks &= ~PhaseChecks::CHECK_PROFILE;
4785-
activePhaseChecks |= PhaseChecks::CHECK_LIKELIHOODS;
4786-
47874782
#ifdef DEBUG
47884783
// Now that locals have address-taken and implicit byref marked, we can safely apply stress.
47894784
lvaStressLclFld();
@@ -4819,6 +4814,11 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl
48194814
//
48204815
DoPhase(this, PHASE_GS_COOKIE, &Compiler::gsPhase);
48214816

4817+
// Drop back to just checking profile likelihoods.
4818+
//
4819+
activePhaseChecks &= ~PhaseChecks::CHECK_PROFILE;
4820+
activePhaseChecks |= PhaseChecks::CHECK_LIKELIHOODS;
4821+
48224822
if (opts.OptimizationEnabled())
48234823
{
48244824
// Compute the block weights

src/coreclr/jit/fgbasic.cpp

+19-4
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,29 @@ void Compiler::fgConvertBBToThrowBB(BasicBlock* block)
156156
}
157157

158158
// Scrub this block from the pred lists of any successors
159-
fgRemoveBlockAsPred(block);
159+
bool profileInconsistent = false;
160+
161+
for (BasicBlock* const succBlock : block->Succs(this))
162+
{
163+
FlowEdge* const succEdge = fgRemoveAllRefPreds(succBlock, block);
164+
165+
if (block->hasProfileWeight() && succBlock->hasProfileWeight())
166+
{
167+
succBlock->decreaseBBProfileWeight(succEdge->getLikelyWeight());
168+
profileInconsistent |= (succBlock->NumSucc() > 0);
169+
}
170+
}
171+
172+
if (profileInconsistent)
173+
{
174+
JITDUMP("Flow removal of " FMT_BB " needs to be propagated. Data %s inconsistent.\n", block->bbNum,
175+
fgPgoConsistent ? "is now" : "was already");
176+
fgPgoConsistent = false;
177+
}
160178

161179
// Update jump kind after the scrub.
162180
block->SetKindAndTargetEdge(BBJ_THROW);
163181
block->RemoveFlags(BBF_RETLESS_CALL); // no longer a BBJ_CALLFINALLY
164-
165-
// Any block with a throw is rare
166-
block->bbSetRunRarely();
167182
}
168183

169184
/*****************************************************************************

src/coreclr/jit/fgehopt.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -2433,7 +2433,7 @@ PhaseStatus Compiler::fgTailMergeThrows()
24332433

24342434
if (canonicalBlock->hasProfileWeight())
24352435
{
2436-
canonicalBlock->setBBProfileWeight(canonicalBlock->bbWeight + removedWeight);
2436+
canonicalBlock->increaseBBProfileWeight(removedWeight);
24372437
modifiedProfile = true;
24382438

24392439
// Don't bother updating flow into nonCanonicalBlock, since it is now unreachable

src/coreclr/jit/fgopt.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -1355,7 +1355,7 @@ bool Compiler::fgOptimizeBranchToEmptyUnconditional(BasicBlock* block, BasicBloc
13551355
//
13561356
if (bDest->hasProfileWeight())
13571357
{
1358-
bDest->setBBProfileWeight(max(0.0, bDest->bbWeight - removedWeight));
1358+
bDest->decreaseBBProfileWeight(removedWeight);
13591359
}
13601360

13611361
return true;
@@ -1620,7 +1620,7 @@ bool Compiler::fgOptimizeSwitchBranches(BasicBlock* block)
16201620
if (bDest->hasProfileWeight())
16211621
{
16221622
weight_t const branchThroughWeight = oldEdge->getLikelyWeight();
1623-
bDest->setBBProfileWeight(max(0.0, bDest->bbWeight - branchThroughWeight));
1623+
bDest->decreaseBBProfileWeight(branchThroughWeight);
16241624
}
16251625

16261626
// Update the switch jump table
@@ -6633,7 +6633,7 @@ PhaseStatus Compiler::fgHeadTailMerge(bool early)
66336633
// crossJumpTarget, so the profile update can be done locally.
66346634
if (crossJumpTarget->hasProfileWeight())
66356635
{
6636-
crossJumpTarget->setBBProfileWeight(crossJumpTarget->bbWeight + predBlock->bbWeight);
6636+
crossJumpTarget->increaseBBProfileWeight(predBlock->bbWeight);
66376637
}
66386638
}
66396639

src/coreclr/jit/jitmetadatalist.h

+2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ JITMETADATAMETRIC(InlineAttempt, int, 0)
6868
JITMETADATAMETRIC(InlineCount, int, 0)
6969
JITMETADATAMETRIC(ProfileConsistentBeforeInline, int, 0)
7070
JITMETADATAMETRIC(ProfileConsistentAfterInline, int, 0)
71+
JITMETADATAMETRIC(ProfileConsistentBeforeMorph, int, 0)
72+
JITMETADATAMETRIC(ProfileConsistentAfterMorph, int, 0)
7173
JITMETADATAMETRIC(ProfileSynthesizedBlendedOrRepaired, int, 0)
7274
JITMETADATAMETRIC(ProfileInconsistentInitially, int, 0)
7375
JITMETADATAMETRIC(ProfileInconsistentResetLeave, int, 0)

src/coreclr/jit/morph.cpp

+95-74
Original file line numberDiff line numberDiff line change
@@ -5366,55 +5366,27 @@ GenTree* Compiler::fgMorphPotentialTailCall(GenTreeCall* call)
53665366
//
53675367
if (compCurBB->KindIs(BBJ_ALWAYS))
53685368
{
5369+
BasicBlock* const curBlock = compCurBB;
5370+
BasicBlock* const targetBlock = curBlock->GetTarget();
5371+
53695372
// Flow no longer reaches the target from here.
53705373
//
5371-
fgRemoveRefPred(compCurBB->GetTargetEdge());
5374+
fgRemoveRefPred(curBlock->GetTargetEdge());
53725375

5373-
// Adjust profile weights of the successor blocks.
5376+
// Adjust profile weights of the successor block.
53745377
//
53755378
// Note if this is a tail call to loop, further updates
53765379
// are needed once we install the loop edge.
53775380
//
5378-
BasicBlock* curBlock = compCurBB;
5379-
if (curBlock->hasProfileWeight())
5381+
if (curBlock->hasProfileWeight() && targetBlock->hasProfileWeight())
53805382
{
5381-
weight_t weightLoss = curBlock->bbWeight;
5382-
BasicBlock* nextBlock = curBlock->GetTarget();
5383+
targetBlock->decreaseBBProfileWeight(curBlock->bbWeight);
53835384

5384-
while (nextBlock->hasProfileWeight())
5385+
if (targetBlock->NumSucc() > 0)
53855386
{
5386-
// Since we have linear flow we can update the next block weight.
5387-
//
5388-
weight_t const nextWeight = nextBlock->bbWeight;
5389-
weight_t const newNextWeight = nextWeight - weightLoss;
5390-
5391-
// If the math would result in a negative weight then there's
5392-
// no local repair we can do; just leave things inconsistent.
5393-
//
5394-
if (newNextWeight >= 0)
5395-
{
5396-
// Note if we'd already morphed the IR in nextblock we might
5397-
// have done something profile sensitive that we should arguably reconsider.
5398-
//
5399-
JITDUMP("Reducing profile weight of " FMT_BB " from " FMT_WT " to " FMT_WT "\n", nextBlock->bbNum,
5400-
nextWeight, newNextWeight);
5401-
5402-
nextBlock->setBBProfileWeight(newNextWeight);
5403-
}
5404-
else
5405-
{
5406-
JITDUMP("Not reducing profile weight of " FMT_BB " as its weight " FMT_WT
5407-
" is less than direct flow pred " FMT_BB " weight " FMT_WT "\n",
5408-
nextBlock->bbNum, nextWeight, compCurBB->bbNum, weightLoss);
5409-
}
5410-
5411-
if (!nextBlock->KindIs(BBJ_ALWAYS))
5412-
{
5413-
break;
5414-
}
5415-
5416-
curBlock = nextBlock;
5417-
nextBlock = curBlock->GetTarget();
5387+
JITDUMP("Flow removal out of " FMT_BB " needs to be propagated. Data %s inconsistent.\n",
5388+
curBlock->bbNum, fgPgoConsistent ? "is now" : "was already");
5389+
fgPgoConsistent = false;
54185390
}
54195391
}
54205392
}
@@ -6755,12 +6727,12 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa
67556727
fgRemoveStmt(block, lastStmt);
67566728

67576729
// Set the loop edge.
6730+
BasicBlock* entryBB;
67586731
if (opts.IsOSR())
67596732
{
67606733
// Todo: this may not look like a viable loop header.
67616734
// Might need the moral equivalent of an init BB.
6762-
FlowEdge* const newEdge = fgAddRefPred(fgEntryBB, block);
6763-
block->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge);
6735+
entryBB = fgEntryBB;
67646736
}
67656737
else
67666738
{
@@ -6769,9 +6741,19 @@ void Compiler::fgMorphRecursiveFastTailCallIntoLoop(BasicBlock* block, GenTreeCa
67696741
// TODO-Cleanup: We should really be expanding tailcalls into loops
67706742
// much earlier than this, at a place where we do not need to have
67716743
// hacky workarounds to figure out what the actual IL entry block is.
6772-
BasicBlock* firstILBB = fgGetFirstILBlock();
6773-
FlowEdge* const newEdge = fgAddRefPred(firstILBB, block);
6774-
block->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge);
6744+
entryBB = fgGetFirstILBlock();
6745+
}
6746+
6747+
FlowEdge* const newEdge = fgAddRefPred(entryBB, block);
6748+
block->SetKindAndTargetEdge(BBJ_ALWAYS, newEdge);
6749+
6750+
// Update profile
6751+
if (block->hasProfileWeight() && entryBB->hasProfileWeight())
6752+
{
6753+
entryBB->increaseBBProfileWeight(block->bbWeight);
6754+
JITDUMP("Flow into entry BB " FMT_BB " increased. Data %s inconsistent.\n", entryBB->bbNum,
6755+
fgPgoConsistent ? "is now" : "was already");
6756+
fgPgoConsistent = false;
67756757
}
67766758

67776759
// Finish hooking things up.
@@ -12741,24 +12723,38 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block)
1274112723
// modify the flow graph
1274212724

1274312725
// Find the actual jump target
12744-
size_t switchVal = (size_t)cond->AsIntCon()->gtIconVal;
12745-
unsigned jumpCnt = block->GetSwitchTargets()->bbsCount;
12746-
FlowEdge** jumpTab = block->GetSwitchTargets()->bbsDstTab;
12747-
bool foundVal = false;
12726+
size_t switchVal = (size_t)cond->AsIntCon()->gtIconVal;
12727+
unsigned jumpCnt = block->GetSwitchTargets()->bbsCount;
12728+
FlowEdge** jumpTab = block->GetSwitchTargets()->bbsDstTab;
12729+
bool foundVal = false;
12730+
bool profileInconsistent = false;
1274812731

1274912732
for (unsigned val = 0; val < jumpCnt; val++, jumpTab++)
1275012733
{
1275112734
FlowEdge* curEdge = *jumpTab;
1275212735

1275312736
assert(curEdge->getDestinationBlock()->countOfInEdges() > 0);
1275412737

12738+
BasicBlock* const targetBlock = curEdge->getDestinationBlock();
12739+
if (block->hasProfileWeight() && targetBlock->hasProfileWeight())
12740+
{
12741+
targetBlock->decreaseBBProfileWeight(curEdge->getLikelyWeight());
12742+
profileInconsistent |= (targetBlock->NumSucc() > 0);
12743+
}
12744+
1275512745
// If val matches switchVal or we are at the last entry and
1275612746
// we never found the switch value then set the new jump dest
1275712747

1275812748
if ((val == switchVal) || (!foundVal && (val == jumpCnt - 1)))
1275912749
{
1276012750
block->SetKindAndTargetEdge(BBJ_ALWAYS, curEdge);
1276112751
foundVal = true;
12752+
12753+
if (block->hasProfileWeight() && targetBlock->hasProfileWeight())
12754+
{
12755+
targetBlock->increaseBBProfileWeight(block->bbWeight);
12756+
profileInconsistent |= (targetBlock->NumSucc() > 0);
12757+
}
1276212758
}
1276312759
else
1276412760
{
@@ -12767,6 +12763,13 @@ Compiler::FoldResult Compiler::fgFoldConditional(BasicBlock* block)
1276712763
}
1276812764
}
1276912765

12766+
if (profileInconsistent)
12767+
{
12768+
JITDUMP("Flow change out of " FMT_BB " needs to be propagated. Data %s inconsistent.\n", block->bbNum,
12769+
fgPgoConsistent ? "is now" : "was already");
12770+
fgPgoConsistent = false;
12771+
}
12772+
1277012773
assert(foundVal);
1277112774
#ifdef DEBUG
1277212775
if (verbose)
@@ -13408,6 +13411,11 @@ PhaseStatus Compiler::fgMorphBlocks()
1340813411
//
1340913412
fgGlobalMorph = true;
1341013413

13414+
if (fgPgoConsistent)
13415+
{
13416+
Metrics.ProfileConsistentBeforeMorph = 1;
13417+
}
13418+
1341113419
if (opts.OptimizationEnabled())
1341213420
{
1341313421
// Local assertion prop is enabled if we are optimizing.
@@ -13505,6 +13513,25 @@ PhaseStatus Compiler::fgMorphBlocks()
1350513513
fgEntryBB->bbRefs--;
1350613514
fgEntryBBExtraRefs = 0;
1350713515

13516+
// The original method entry will now be checked for profile consistency.
13517+
// If the entry has inconsistent incoming weight, flag the profile as inconsistent.
13518+
//
13519+
if (fgEntryBB->hasProfileWeight())
13520+
{
13521+
weight_t incomingWeight = BB_ZERO_WEIGHT;
13522+
for (FlowEdge* const predEdge : fgEntryBB->PredEdges())
13523+
{
13524+
incomingWeight += predEdge->getLikelyWeight();
13525+
}
13526+
13527+
if (!fgProfileWeightsConsistent(incomingWeight, fgEntryBB->bbWeight))
13528+
{
13529+
JITDUMP("OSR: Original method entry " FMT_BB " has inconsistent weight. Data %s inconsistent.\n",
13530+
fgPgoConsistent ? "is now" : "was already");
13531+
fgPgoConsistent = false;
13532+
}
13533+
}
13534+
1350813535
// We don't need to remember this block anymore.
1350913536
fgEntryBB = nullptr;
1351013537
}
@@ -13544,6 +13571,11 @@ PhaseStatus Compiler::fgMorphBlocks()
1354413571
// may no longer be canonical.
1354513572
fgCanonicalizeFirstBB();
1354613573

13574+
if (fgPgoConsistent)
13575+
{
13576+
Metrics.ProfileConsistentAfterMorph = 1;
13577+
}
13578+
1354713579
INDEBUG(fgPostGlobalMorphChecks();)
1354813580

1354913581
return PhaseStatus::MODIFIED_EVERYTHING;
@@ -14263,6 +14295,15 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
1426314295
BasicBlock* condBlock = fgNewBBafter(BBJ_ALWAYS, block, true);
1426414296
BasicBlock* elseBlock = fgNewBBafter(BBJ_ALWAYS, condBlock, true);
1426514297

14298+
// Update flowgraph
14299+
fgRedirectTargetEdge(block, condBlock);
14300+
condBlock->SetTargetEdge(fgAddRefPred(elseBlock, condBlock));
14301+
elseBlock->SetTargetEdge(fgAddRefPred(remainderBlock, elseBlock));
14302+
14303+
// Propagate flow from block into condBlock.
14304+
// Leave flow out of remainderBlock intact, as it will post-dominate block.
14305+
condBlock->inheritWeight(block);
14306+
1426614307
// These blocks are only internal if 'block' is (but they've been set as internal by fgNewBBafter).
1426714308
// If they're not internal, mark them as imported to avoid asserts about un-imported blocks.
1426814309
if (!block->HasFlag(BBF_INTERNAL))
@@ -14276,27 +14317,6 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
1427614317
block->RemoveFlags(BBF_NEEDS_GCPOLL);
1427714318
remainderBlock->SetFlags(propagateFlagsToRemainder | propagateFlagsToAll);
1427814319

14279-
condBlock->inheritWeight(block);
14280-
14281-
// Make sure remainderBlock gets exactly the same weight as block after split
14282-
assert(condBlock->bbWeight == remainderBlock->bbWeight);
14283-
14284-
assert(block->KindIs(BBJ_ALWAYS));
14285-
fgRedirectTargetEdge(block, condBlock);
14286-
14287-
{
14288-
FlowEdge* const newEdge = fgAddRefPred(elseBlock, condBlock);
14289-
condBlock->SetTargetEdge(newEdge);
14290-
}
14291-
14292-
{
14293-
FlowEdge* const newEdge = fgAddRefPred(remainderBlock, elseBlock);
14294-
elseBlock->SetTargetEdge(newEdge);
14295-
}
14296-
14297-
assert(condBlock->JumpsToNext());
14298-
assert(elseBlock->JumpsToNext());
14299-
1430014320
condBlock->SetFlags(propagateFlagsToAll);
1430114321
elseBlock->SetFlags(propagateFlagsToAll);
1430214322

@@ -14311,6 +14331,7 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
1431114331
// +--->--------+
1431214332
// bbj_cond(true)
1431314333
//
14334+
// TODO: Remove unnecessary condition reversal
1431414335
gtReverseCond(condExpr);
1431514336

1431614337
thenBlock = fgNewBBafter(BBJ_ALWAYS, condBlock, true);
@@ -14324,13 +14345,12 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
1432414345
const unsigned thenLikelihood = qmark->ThenNodeLikelihood();
1432514346
const unsigned elseLikelihood = qmark->ElseNodeLikelihood();
1432614347

14327-
FlowEdge* const newEdge = fgAddRefPred(remainderBlock, thenBlock);
14328-
thenBlock->SetTargetEdge(newEdge);
14348+
thenBlock->SetTargetEdge(fgAddRefPred(remainderBlock, thenBlock));
1432914349

1433014350
assert(condBlock->TargetIs(elseBlock));
14331-
FlowEdge* const elseEdge = fgAddRefPred(thenBlock, condBlock);
14332-
FlowEdge* const thenEdge = condBlock->GetTargetEdge();
14333-
condBlock->SetCond(thenEdge, elseEdge);
14351+
FlowEdge* const thenEdge = fgAddRefPred(thenBlock, condBlock);
14352+
FlowEdge* const elseEdge = condBlock->GetTargetEdge();
14353+
condBlock->SetCond(elseEdge, thenEdge);
1433414354
thenBlock->inheritWeightPercentage(condBlock, thenLikelihood);
1433514355
elseBlock->inheritWeightPercentage(condBlock, elseLikelihood);
1433614356
thenEdge->setLikelihood(thenLikelihood / 100.0);
@@ -14344,6 +14364,7 @@ bool Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt)
1434414364
// +-->-------------+
1434514365
// bbj_cond(true)
1434614366
//
14367+
// TODO: Remove unnecessary condition reversal
1434714368
gtReverseCond(condExpr);
1434814369

1434914370
const unsigned thenLikelihood = qmark->ThenNodeLikelihood();

0 commit comments

Comments
 (0)