Inliner: updates to ModelPolicy
authorAndy Ayers <andya@microsoft.com>
Fri, 8 Jul 2016 00:53:43 +0000 (17:53 -0700)
committerAndy Ayers <andya@microsoft.com>
Sat, 9 Jul 2016 00:14:52 +0000 (17:14 -0700)
Updates to bring CS and TP impact of the ModelPolicy into more acceptable
ranges.

For CS, reduce the call site weights to values that are more in keeping
with the legacy policy weights. Local test runs show this does not
drastically alter CQ and brings CS down below LegacyPolicy levels, on
average.

Implement an early out rejection based solely on ILSize. The threshold
value is set by conservatively determining when ILSize alone indicates
the method in question will never be inlined (note the policy itself
does not have an explicit ILSize cutoff). See comments for
`ModelPolicy::NoteInt` for details. Note if we adjust the model's size
and profitability estimates, this threshould will also need updating.

CQ (as measured by the CoreCLR perf tests) continues to show about a
2.5% geomean improvement over LegacyPolicy.

src/jit/inlinepolicy.cpp
src/jit/inlinepolicy.h

index 30ec8f593d205d5ba93b5d15a8ff262a638b8587..2d044cc80420e74555cafab18b1486b4f2364b19 100644 (file)
@@ -1913,6 +1913,60 @@ ModelPolicy::ModelPolicy(Compiler* compiler, bool isPrejitRoot)
     // Empty
 }
 
+//------------------------------------------------------------------------
+// NoteInt: handle an observed integer value
+//
+// Arguments:
+//    obs      - the current obsevation
+//    value    - the value being observed
+//
+// Notes:
+//    The ILSize threshold used here should be large enough that
+//    it does not generally influence inlining decisions -- it only
+//    helps to make them faster.
+//
+//    The value is determined as follows. We figure out the maximum
+//    possible code size estimate that will lead to an inline. This is
+//    found by determining the maximum possible inline benefit and
+//    working backwards.
+//
+//    In the current ModelPolicy, the maximum benefit is -28.1, which
+//    comes from a CallSiteWeight of 3 and a per call benefit of
+//    -9.37.  This implies that any candidate with code size larger
+//    than (28.1/0.2) will not pass the threshold. So maximum code
+//    size estimate (in bytes) for any inlinee is 140.55, and hence
+//    maximum estimate is 1405.
+//
+//    Since we are trying to short circuit early in the evaluation
+//    process we don't have the code size estimate in hand. We need to
+//    estimate the possible code size estimate based on something we
+//    know cheaply and early -- the ILSize. So we use quantile
+//    regression to project how ILSize predicts the model code size
+//    estimate. Note that ILSize does not currently directly enter
+//    into the model.
+//
+//    The median value for the model code size estimate based on
+//    ILSize is given by -107 + 12.6 * ILSize for the V9 data.  This
+//    means an ILSize of 120 is likely to lead to a size estimate of
+//    at least 1405 at least 50% of the time. So we choose this as the
+//    early rejection threshold.
+
+void ModelPolicy::NoteInt(InlineObservation obs, int value)
+{
+    // Let underlying policy do its thing.
+    DiscretionaryPolicy::NoteInt(obs, value);
+
+    // Fail fast for inlinees that are too large to ever inline.
+    // The value of 120 is model-dependent; see notes above.
+    if (!m_IsForceInline &&
+        (obs == InlineObservation::CALLEE_IL_CODE_SIZE) &&
+        (value >= 120))
+    {
+        // Callee too big, not a candidate
+        SetNever(InlineObservation::CALLEE_TOO_MUCH_IL);
+    }
+}
+
 //------------------------------------------------------------------------
 // DetermineProfitability: determine if this inline is profitable
 //
@@ -1980,10 +2034,24 @@ void ModelPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo)
         // frequency, somehow.
         double callSiteWeight = 1.0;
 
-        if ((m_CallsiteFrequency == InlineCallsiteFrequency::LOOP) ||
-            (m_CallsiteFrequency == InlineCallsiteFrequency::HOT))
+        switch (m_CallsiteFrequency)
         {
-            callSiteWeight = 8.0;
+        case InlineCallsiteFrequency::RARE:
+            callSiteWeight = 0.1;
+            break;
+        case InlineCallsiteFrequency::BORING:
+            callSiteWeight = 1.0;
+            break;
+        case InlineCallsiteFrequency::WARM:
+            callSiteWeight = 1.5;
+            break;
+        case InlineCallsiteFrequency::LOOP:
+        case InlineCallsiteFrequency::HOT:
+            callSiteWeight = 3.0;
+            break;
+        default:
+            assert(false);
+            break;
         }
 
         // Determine the estimated number of instructions saved per
index f834577a439b5dabdc8dce47571621947aae31d8..0f5777a1bf9333068348f4ab583f3a5b8af36027 100644 (file)
@@ -297,6 +297,9 @@ public:
     // Construct a ModelPolicy
     ModelPolicy(Compiler* compiler, bool isPrejitRoot);
 
+    // Policy observations
+    void NoteInt(InlineObservation obs, int value) override;
+
     // Policy determinations
     void DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) override;