Bug 777583 - Add caller/callee use count ratio to balance inlining cost. r=djvj
☠☠ backed out by 189a1aaac345 ☠ ☠
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Fri, 28 Sep 2012 16:10:07 -0700
changeset 108684 67f93efc40c81576ebb57965fa973ccf180241ef
parent 108683 b176f299c52c6b792f7c466361f55c156e739876
child 108685 93e76aaf861579f4dea5615605d17b33166576c5
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersdjvj
bugs777583
milestone18.0a1
Bug 777583 - Add caller/callee use count ratio to balance inlining cost. r=djvj
js/src/ion/Ion.h
js/src/ion/IonBuilder.cpp
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -124,16 +124,22 @@ struct IonOptions
     // Default: 4
     uint32 polyInlineMax;
 
     // The maximum total bytecode size of an inline call site.
     //
     // Default: 800
     uint32 inlineMaxTotalBytecodeLength;
 
+    // Minimal ratio between the use counts of the caller and the callee to
+    // enable inlining of functions.
+    //
+    // Default: 128
+    uint32 inlineUseCountRatio;
+
     // Whether functions are compiled immediately.
     //
     // Default: false
     bool eagerCompilation;
 
     // If a function has attempted to make this many calls to
     // functions that are marked "uncompileable", then
     // stop running this function in IonMonkey. (default 512)
@@ -165,16 +171,17 @@ struct IonOptions
         usesBeforeCompileNoJaeger(40),
         usesBeforeInlining(usesBeforeCompile),
         maxStackArgs(4096),
         maxInlineDepth(3),
         smallFunctionMaxBytecodeLength(100),
         smallFunctionUsesBeforeInlining(usesBeforeInlining / 4),
         polyInlineMax(4),
         inlineMaxTotalBytecodeLength(800),
+        inlineUseCountRatio(128),
         eagerCompilation(false),
         slowCallLimit(512)
     {
     }
 };
 
 enum MethodStatus
 {
--- a/js/src/ion/IonBuilder.cpp
+++ b/js/src/ion/IonBuilder.cpp
@@ -2893,32 +2893,42 @@ IonBuilder::makeInliningDecision(AutoObj
     // For "small" functions, we should be more aggressive about inlining.
     // This is based on the following intuition:
     //  1. The call overhead for a small function will likely be a much
     //     higher proportion of the runtime of the function than for larger
     //     functions.
     //  2. The cost of inlining (in terms of size expansion of the SSA graph),
     //     and size expansion of the ultimately generated code, will be
     //     less significant.
+    //  3. Do not inline functions which are not called as frequently as their
+    //     callers.
+
+    uint32_t callerUses = script->getUseCount();
 
     uint32_t totalSize = 0;
     uint32_t checkUses = js_IonOptions.usesBeforeInlining;
     bool allFunctionsAreSmall = true;
     for (size_t i = 0; i < targets.length(); i++) {
         JSFunction *target = targets[i]->toFunction();
         if (!target->isInterpreted())
             return false;
 
         JSScript *script = target->script();
+        uint32_t calleeUses = script->getUseCount();
         totalSize += script->length;
         if (totalSize > js_IonOptions.inlineMaxTotalBytecodeLength)
             return false;
 
         if (script->length > js_IonOptions.smallFunctionMaxBytecodeLength)
             allFunctionsAreSmall = false;
+
+        if (calleeUses * js_IonOptions.inlineUseCountRatio < callerUses) {
+            IonSpew(IonSpew_Inlining, "Not inlining, callee is not hot");
+            return false;
+        }
     }
     if (allFunctionsAreSmall)
         checkUses = js_IonOptions.smallFunctionUsesBeforeInlining;
 
     if (script_->getUseCount() < checkUses) {
         IonSpew(IonSpew_Inlining, "Not inlining, caller is not hot");
         return false;
     }