diff options
author | Andy Ayers <andya@microsoft.com> | 2016-06-09 17:08:39 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-06-09 17:08:39 -0700 |
commit | f2eff33c3b5131248f0b9b428b5850e0cfc568bb (patch) | |
tree | f867889354a0c96ab60063de69860ff10e2715ce /src | |
parent | 713956f3a691026af775ebdf08f7651d682d4ed0 (diff) | |
parent | aed87099a2f5b70676b7bacf18f696d772b862b9 (diff) | |
download | coreclr-f2eff33c3b5131248f0b9b428b5850e0cfc568bb.tar.gz coreclr-f2eff33c3b5131248f0b9b428b5850e0cfc568bb.tar.bz2 coreclr-f2eff33c3b5131248f0b9b428b5850e0cfc568bb.zip |
Merge pull request #5661 from AndyAyersMS/FirstDraftProfitablityModel
Inliner: implement profitabily side of the ModelPolicy
Diffstat (limited to 'src')
-rw-r--r-- | src/jit/inlinepolicy.cpp | 96 | ||||
-rw-r--r-- | src/jit/inlinepolicy.h | 2 |
2 files changed, 89 insertions, 9 deletions
diff --git a/src/jit/inlinepolicy.cpp b/src/jit/inlinepolicy.cpp index d63f065580..c5beaa5f2c 100644 --- a/src/jit/inlinepolicy.cpp +++ b/src/jit/inlinepolicy.cpp @@ -1141,6 +1141,7 @@ DiscretionaryPolicy::DiscretionaryPolicy(Compiler* compiler, bool isPrejitRoot) , m_ThrowCount(0) , m_CallCount(0) , m_ModelCodeSizeEstimate(0) + , m_PerCallInstructionEstimate(0) { // Empty } @@ -1535,6 +1536,11 @@ void DiscretionaryPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo // model for actual inlining. EstimateCodeSize(); + // Estimate peformance impact. This is just for model + // evaluation purposes -- we'll still use the legacy policy's + // model for actual inlining. + EstimatePerformanceImpact(); + // Delegate to LegacyPolicy for the rest LegacyPolicy::DetermineProfitability(methodInfo); } @@ -1692,6 +1698,33 @@ void DiscretionaryPolicy::EstimateCodeSize() } //------------------------------------------------------------------------ +// EstimatePeformanceImpact: produce performance estimates based on +// observations. +// +// Notes: +// Attempts to predict the per-call savings in instructions executed. +// +// A negative value indicates the doing the inline will save instructions +// and likely time. + +void DiscretionaryPolicy::EstimatePerformanceImpact() +{ + // Performance estimate based on GLMNET model. + // R=0.24, RMSE=16.1, MAE=8.9. + double perCallSavingsEstimate = + -7.35 + + (m_CallsiteFrequency == InlineCallsiteFrequency::BORING ? 0.76 : 0) + + (m_CallsiteFrequency == InlineCallsiteFrequency::LOOP ? -2.02 : 0) + + (m_ArgType[0] == CORINFO_TYPE_CLASS ? 3.51 : 0) + + (m_ArgType[3] == CORINFO_TYPE_BOOL ? 20.7 : 0) + + (m_ArgType[4] == CORINFO_TYPE_CLASS ? 0.38 : 0) + + (m_ReturnType == CORINFO_TYPE_CLASS ? 2.32 : 0); + + // Scaled up and reported as an integer value. + m_PerCallInstructionEstimate = (int) (SIZE_SCALE * perCallSavingsEstimate); +} + +//------------------------------------------------------------------------ // CodeSizeEstimate: estimated code size impact of the inline // // Return Value: @@ -1866,12 +1899,19 @@ ModelPolicy::ModelPolicy(Compiler* compiler, bool isPrejitRoot) // // Arguments: // methodInfo -- method info for the callee +// +// Notes: +// There are currently two parameters that are ad-hoc: the +// per-call-site weight and the size/speed threshold. Ideally this +// policy would have just one tunable parameter, the threshold, +// which describes how willing we are to trade size for speed. void ModelPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) { // Do some homework MethodInfoObservations(methodInfo); EstimateCodeSize(); + EstimatePerformanceImpact(); // Preliminary inline model. // @@ -1899,18 +1939,56 @@ void ModelPolicy::DetermineProfitability(CORINFO_METHOD_INFO* methodInfo) } else { - // This is a very crude profitability model, based on what - // the LegacyPolicy does. It will be updated over time. - m_Multiplier = DetermineMultiplier(); - double benefit = SIZE_SCALE * (m_Multiplier / m_ModelCodeSizeEstimate); - double threshold = 0.25; + // We estimate that this inline will increase code size. Only + // inline if the performance win is sufficiently large to + // justify bigger code. + + // First compute the number of instruction executions saved + // via inlining per call to the callee per byte of code size + // impact. + // + // The per call instruction estimate is negative if the inline + // will reduce instruction count. Flip the sign here to make + // positive be better and negative worse. + double perCallBenefit = -((double) m_PerCallInstructionEstimate / (double) m_ModelCodeSizeEstimate); + + // Now estimate the local call frequency. + // + // Todo: use IBC data, or a better local profile estimate, or + // try and incorporate this into the model. For instance if we + // tried to predict the benefit per call to the root method + // then the model would have to incorporate the local call + // frequency, somehow. + double callSiteWeight = 1.0; + + if ((m_CallsiteFrequency == InlineCallsiteFrequency::LOOP) || + (m_CallsiteFrequency == InlineCallsiteFrequency::HOT)) + { + callSiteWeight = 8.0; + } + + // Determine the estimated number of instructions saved per + // call to the root method per byte of code size impact. This + // is our benefit figure of merit. + double benefit = callSiteWeight * perCallBenefit; + + // Compare this to the threshold, and inline if greater. + // + // The threshold is interpretable as a size/speed tradeoff: + // the value of 0.2 below indicates we'll allow inlines that + // grow code by as many as 5 bytes to save 1 instruction + // execution (per call to the root method). + double threshold = 0.20; bool shouldInline = (benefit > threshold); JITLOG_THIS(m_RootCompiler, - (LL_INFO100000, - "Inline %s profitable: benefit=%g (mult=%g / size=%d)\n", - shouldInline ? "is" : "is not", - benefit, m_Multiplier, (double) m_ModelCodeSizeEstimate / SIZE_SCALE)); + (LL_INFO100000, + "Inline %s profitable: benefit=%g (weight=%g, percall=%g, size=%g)\n", + shouldInline ? "is" : "is not", + benefit, callSiteWeight, + (double) m_PerCallInstructionEstimate / SIZE_SCALE, + (double) m_ModelCodeSizeEstimate / SIZE_SCALE)); + if (!shouldInline) { // Fail the inline diff --git a/src/jit/inlinepolicy.h b/src/jit/inlinepolicy.h index 3965b8df87..7f254cadab 100644 --- a/src/jit/inlinepolicy.h +++ b/src/jit/inlinepolicy.h @@ -238,6 +238,7 @@ protected: void ComputeOpcodeBin(OPCODE opcode); void EstimateCodeSize(); + void EstimatePerformanceImpact(); void MethodInfoObservations(CORINFO_METHOD_INFO* methodInfo); enum { MAX_ARGS = 6 }; @@ -279,6 +280,7 @@ protected: unsigned m_ThrowCount; unsigned m_CallCount; int m_ModelCodeSizeEstimate; + int m_PerCallInstructionEstimate; }; // ModelPolicy is an experimental policy that uses the results |