@@ -2606,18 +2606,35 @@ PhaseStatus Compiler::fgIncorporateProfileData()
2606
2606
2607
2607
fgPgoHaveWeights = haveBlockCounts || haveEdgeCounts;
2608
2608
2609
- // We expect not to have both block and edge counts. We may have other
2610
- // forms of profile data even if we do not have any counts.
2611
- //
2612
- assert (!haveBlockCounts || !haveEdgeCounts);
2613
-
2614
- if (haveBlockCounts)
2609
+ if (fgPgoHaveWeights)
2615
2610
{
2616
- fgIncorporateBlockCounts ();
2617
- }
2618
- else if (haveEdgeCounts)
2619
- {
2620
- fgIncorporateEdgeCounts ();
2611
+ // We expect not to have both block and edge counts. We may have other
2612
+ // forms of profile data even if we do not have any counts.
2613
+ //
2614
+ assert (!haveBlockCounts || !haveEdgeCounts);
2615
+
2616
+ bool dataIsGood = false ;
2617
+
2618
+ if (haveBlockCounts)
2619
+ {
2620
+ dataIsGood = fgIncorporateBlockCounts ();
2621
+ }
2622
+ else if (haveEdgeCounts)
2623
+ {
2624
+ dataIsGood = fgIncorporateEdgeCounts ();
2625
+ }
2626
+
2627
+ // Profile incorporation may have tossed out all PGO data if it
2628
+ // encountered major issues. This is perhaps too drastic. Consider
2629
+ // at least keeping the class profile data, or perhaps enable full synthesis.
2630
+ //
2631
+ // If profile incorporation hit fixable problems, run synthesis in repair mode.
2632
+ //
2633
+ if (fgPgoHaveWeights && !dataIsGood)
2634
+ {
2635
+ JITDUMP (" \n Incorporated count data had inconsistencies; repairing profile...\n " );
2636
+ ProfileSynthesis::Run (this , ProfileSynthesisOption::RepairLikelihoods);
2637
+ }
2621
2638
}
2622
2639
2623
2640
#ifdef DEBUG
@@ -2667,6 +2684,9 @@ void Compiler::fgSetProfileWeight(BasicBlock* block, weight_t profileWeight)
2667
2684
// fgIncorporateBlockCounts: read block count based profile data
2668
2685
// and set block weights
2669
2686
//
2687
+ // Returns:
2688
+ // True if data is in good shape
2689
+ //
2670
2690
// Notes:
2671
2691
// Since we are now running before the importer, we do not know which
2672
2692
// blocks will be imported, and we should not see any internal blocks.
@@ -2680,7 +2700,7 @@ void Compiler::fgSetProfileWeight(BasicBlock* block, weight_t profileWeight)
2680
2700
// Find some other mechanism for handling cases where handler entry
2681
2701
// blocks must be in the hot section.
2682
2702
//
2683
- void Compiler::fgIncorporateBlockCounts ()
2703
+ bool Compiler::fgIncorporateBlockCounts ()
2684
2704
{
2685
2705
for (BasicBlock* const block : Blocks ())
2686
2706
{
@@ -2691,6 +2711,10 @@ void Compiler::fgIncorporateBlockCounts()
2691
2711
fgSetProfileWeight (block, profileWeight);
2692
2712
}
2693
2713
}
2714
+
2715
+ // For now assume data is always good.
2716
+ //
2717
+ return true ;
2694
2718
}
2695
2719
2696
2720
// ------------------------------------------------------------------------
@@ -2871,6 +2895,7 @@ class EfficientEdgeCountReconstructor : public SpanningTreeVisitor
2871
2895
bool m_negativeCount;
2872
2896
bool m_failedToConverge;
2873
2897
bool m_allWeightsZero;
2898
+ bool m_entryWeightZero;
2874
2899
2875
2900
public:
2876
2901
EfficientEdgeCountReconstructor (Compiler* comp)
@@ -2889,6 +2914,7 @@ class EfficientEdgeCountReconstructor : public SpanningTreeVisitor
2889
2914
, m_negativeCount(false )
2890
2915
, m_failedToConverge(false )
2891
2916
, m_allWeightsZero(true )
2917
+ , m_entryWeightZero(false )
2892
2918
{
2893
2919
}
2894
2920
@@ -2916,6 +2942,24 @@ class EfficientEdgeCountReconstructor : public SpanningTreeVisitor
2916
2942
m_failedToConverge = true ;
2917
2943
}
2918
2944
2945
+ void EntryWeightZero ()
2946
+ {
2947
+ m_entryWeightZero = true ;
2948
+ }
2949
+
2950
+ // Are there are reparable issues with the reconstruction?
2951
+ //
2952
+ // Ideally we'd also have || !m_negativeCount here, but this
2953
+ // leads to lots of diffs in async methods.
2954
+ //
2955
+ // Looks like we might first need to resolve reconstruction
2956
+ // shortcomings with irreducible loops.
2957
+ //
2958
+ bool IsGood () const
2959
+ {
2960
+ return !m_entryWeightZero;
2961
+ }
2962
+
2919
2963
void VisitBlock (BasicBlock*) override
2920
2964
{
2921
2965
}
@@ -3381,52 +3425,15 @@ void EfficientEdgeCountReconstructor::Solve()
3381
3425
3382
3426
JITDUMP (" \n Solver: converged in %u passes\n " , nPasses);
3383
3427
3384
- // If, after solving, the entry weight ends up as zero, set it to
3385
- // the max of the weight of successor edges or join-free successor
3386
- // block weight. We do this so we can determine a plausible scale
3387
- // count.
3388
- //
3389
- // This can happen for methods that do not return (say they always
3390
- // throw, or had not yet returned when we snapped the counts).
3391
- //
3392
- // Note we know there are nonzero counts elsewhere in the method, otherwise
3393
- // m_allWeightsZero would be true and we would have bailed out above.
3428
+ // If, after solving, the entry weight ends up as zero, note
3429
+ // this so we can run a profile repair immediately.
3394
3430
//
3395
3431
BlockInfo* const firstInfo = BlockToInfo (m_comp->fgFirstBB );
3396
3432
if (firstInfo->m_weight == BB_ZERO_WEIGHT)
3397
3433
{
3398
3434
assert (!m_allWeightsZero);
3399
-
3400
- weight_t newWeight = BB_ZERO_WEIGHT;
3401
-
3402
- for (Edge* edge = firstInfo->m_outgoingEdges ; edge != nullptr ; edge = edge->m_nextOutgoingEdge )
3403
- {
3404
- if (edge->m_weightKnown )
3405
- {
3406
- newWeight = max (newWeight, edge->m_weight );
3407
- }
3408
-
3409
- BlockInfo* const targetBlockInfo = BlockToInfo (edge->m_targetBlock );
3410
- Edge* const targetBlockEdges = targetBlockInfo->m_incomingEdges ;
3411
-
3412
- if (targetBlockInfo->m_weightKnown && (targetBlockEdges->m_nextIncomingEdge == nullptr ))
3413
- {
3414
- newWeight = max (newWeight, targetBlockInfo->m_weight );
3415
- }
3416
- }
3417
-
3418
- if (newWeight == BB_ZERO_WEIGHT)
3419
- {
3420
- // TODO -- throw out profile data or trigger repair/synthesis.
3421
- //
3422
- JITDUMP (" Entry block weight and neighborhood was zero\n " );
3423
- }
3424
- else
3425
- {
3426
- JITDUMP (" Entry block weight was zero, setting entry weight to neighborhood max " FMT_WT " \n " , newWeight);
3427
- }
3428
-
3429
- firstInfo->m_weight = newWeight;
3435
+ JITDUMP (" \n Solver: entry block weight is zero\n " );
3436
+ EntryWeightZero ();
3430
3437
}
3431
3438
}
3432
3439
@@ -3436,9 +3443,6 @@ void EfficientEdgeCountReconstructor::Solve()
3436
3443
//
3437
3444
void EfficientEdgeCountReconstructor::Propagate ()
3438
3445
{
3439
- // We don't expect mismatches or convergence failures.
3440
- //
3441
-
3442
3446
// Mismatches are currently expected as the flow for static pgo doesn't prevent them now.
3443
3447
// assert(!m_mismatch);
3444
3448
@@ -3939,6 +3943,10 @@ void EfficientEdgeCountReconstructor::MarkInterestingSwitches(BasicBlock* block,
3939
3943
// fgIncorporateEdgeCounts: read sparse edge count based profile data
3940
3944
// and set block weights
3941
3945
//
3946
+ // Returns:
3947
+ // true if incorporated profile is in good shape (consistent, etc).
3948
+ // false if some repair seems necessary
3949
+ //
3942
3950
// Notes:
3943
3951
// Because edge counts are sparse, we need to solve for the missing
3944
3952
// edge counts; in the process, we also determine block counts.
@@ -3948,7 +3956,7 @@ void EfficientEdgeCountReconstructor::MarkInterestingSwitches(BasicBlock* block,
3948
3956
// Since we have edge weights here, we might as well set them
3949
3957
// (or likelihoods)
3950
3958
//
3951
- void Compiler::fgIncorporateEdgeCounts ()
3959
+ bool Compiler::fgIncorporateEdgeCounts ()
3952
3960
{
3953
3961
JITDUMP (" \n Reconstructing block counts from sparse edge instrumentation\n " );
3954
3962
@@ -3957,6 +3965,8 @@ void Compiler::fgIncorporateEdgeCounts()
3957
3965
WalkSpanningTree (&e);
3958
3966
e.Solve ();
3959
3967
e.Propagate ();
3968
+
3969
+ return e.IsGood ();
3960
3970
}
3961
3971
3962
3972
// ------------------------------------------------------------------------
0 commit comments