Ignore:
Timestamp:
Jul 10, 2012, 2:18:47 AM (13 years ago)
Author:
[email protected]
Message:

DFG recompilation heuristics should be based on count, not rate
https://bugs.webkit.org/show_bug.cgi?id=90146

Reviewed by Oliver Hunt.

Rolling r121511 back in after fixing the DFG's interpretation of op_div
profiling, with Gavin's rubber stamp.

This removes a bunch of code that was previously trying to prevent spurious
reoptimizations if a large enough majority of executions of a code block did
not result in OSR exit. It turns out that this code was purely harmful. This
patch removes all of that logic and replaces it with a dead-simple
heuristic: if you exit more than N times (where N is an exponential function
of the number of times the code block has already been recompiled) then we
will recompile.

This appears to be a broad ~1% win on many benchmarks large and small.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::CodeBlock):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::couldTakeSpecialFastCase):
(CodeBlock):
(JSC::CodeBlock::osrExitCounter):
(JSC::CodeBlock::countOSRExit):
(JSC::CodeBlock::addressOfOSRExitCounter):
(JSC::CodeBlock::offsetOfOSRExitCounter):
(JSC::CodeBlock::adjustedExitCountThreshold):
(JSC::CodeBlock::exitCountThresholdForReoptimization):
(JSC::CodeBlock::exitCountThresholdForReoptimizationFromLoop):
(JSC::CodeBlock::shouldReoptimizeNow):
(JSC::CodeBlock::shouldReoptimizeFromLoopNow):

  • bytecode/ExecutionCounter.cpp:

(JSC::ExecutionCounter::setThreshold):

  • bytecode/ExecutionCounter.h:

(ExecutionCounter):
(JSC::ExecutionCounter::clippedThreshold):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::makeDivSafe):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::compileBody):

  • dfg/DFGOSRExit.cpp:

(JSC::DFG::OSRExit::considerAddingAsFrequentExitSiteSlow):

  • dfg/DFGOSRExitCompiler.cpp:

(JSC::DFG::OSRExitCompiler::handleExitCounts):

  • dfg/DFGOperations.cpp:
  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • runtime/Options.h:

(JSC):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r122182 r122206  
    717717        }
    718718       
     719        bool couldTakeSpecialFastCase(int bytecodeOffset)
     720        {
     721            if (!numberOfRareCaseProfiles())
     722                return false;
     723            unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter;
     724            return specialFastCaseCount >= Options::couldTakeSlowCaseMinimumCount() && static_cast<double>(specialFastCaseCount) / m_executionEntryCount >= Options::couldTakeSlowCaseThreshold();
     725        }
     726       
    719727        bool likelyToTakeDeepestSlowCase(int bytecodeOffset)
    720728        {
     
    10931101        }
    10941102       
    1095         // The speculative JIT tracks its success rate, so that we can
    1096         // decide when to reoptimize. It's interesting to note that these
    1097         // counters may overflow without any protection. The success
    1098         // counter will overflow before the fail one does, becuase the
    1099         // fail one is used as a trigger to reoptimize. So the worst case
    1100         // is that the success counter overflows and we reoptimize without
    1101         // needing to. But this is harmless. If a method really did
    1102         // execute 2^32 times then compiling it again probably won't hurt
    1103         // anyone.
    1104        
    1105         void countSpeculationSuccess()
    1106         {
    1107             m_speculativeSuccessCounter++;
    1108         }
    1109        
    1110         void countSpeculationFailure()
    1111         {
    1112             m_speculativeFailCounter++;
    1113         }
    1114        
    1115         uint32_t speculativeSuccessCounter() const { return m_speculativeSuccessCounter; }
    1116         uint32_t speculativeFailCounter() const { return m_speculativeFailCounter; }
    1117         uint32_t forcedOSRExitCounter() const { return m_forcedOSRExitCounter; }
    1118        
    1119         uint32_t* addressOfSpeculativeSuccessCounter() { return &m_speculativeSuccessCounter; }
    1120         uint32_t* addressOfSpeculativeFailCounter() { return &m_speculativeFailCounter; }
    1121         uint32_t* addressOfForcedOSRExitCounter() { return &m_forcedOSRExitCounter; }
    1122        
    1123         static ptrdiff_t offsetOfSpeculativeSuccessCounter() { return OBJECT_OFFSETOF(CodeBlock, m_speculativeSuccessCounter); }
    1124         static ptrdiff_t offsetOfSpeculativeFailCounter() { return OBJECT_OFFSETOF(CodeBlock, m_speculativeFailCounter); }
    1125         static ptrdiff_t offsetOfForcedOSRExitCounter() { return OBJECT_OFFSETOF(CodeBlock, m_forcedOSRExitCounter); }
     1103        uint32_t osrExitCounter() const { return m_osrExitCounter; }
     1104       
     1105        void countOSRExit() { m_osrExitCounter++; }
     1106       
     1107        uint32_t* addressOfOSRExitCounter() { return &m_osrExitCounter; }
     1108       
     1109        static ptrdiff_t offsetOfOSRExitCounter() { return OBJECT_OFFSETOF(CodeBlock, m_osrExitCounter); }
    11261110
    11271111#if ENABLE(JIT)
    1128         // The number of failures that triggers the use of the ratio.
    1129         unsigned largeFailCountThreshold() { return Options::largeFailCountThresholdBase() << baselineVersion()->reoptimizationRetryCounter(); }
    1130         unsigned largeFailCountThresholdForLoop() { return Options::largeFailCountThresholdBaseForLoop() << baselineVersion()->reoptimizationRetryCounter(); }
     1112        uint32_t adjustedExitCountThreshold(uint32_t desiredThreshold)
     1113        {
     1114            ASSERT(getJITType() == JITCode::DFGJIT);
     1115            // Compute this the lame way so we don't saturate. This is called infrequently
     1116            // enough that this loop won't hurt us.
     1117            unsigned result = desiredThreshold;
     1118            for (unsigned n = baselineVersion()->reoptimizationRetryCounter(); n--;) {
     1119                unsigned newResult = result << 1;
     1120                if (newResult < result)
     1121                    return std::numeric_limits<uint32_t>::max();
     1122                result = newResult;
     1123            }
     1124            return result;
     1125        }
     1126       
     1127        uint32_t exitCountThresholdForReoptimization()
     1128        {
     1129            return adjustedExitCountThreshold(Options::osrExitCountForReoptimization());
     1130        }
     1131       
     1132        uint32_t exitCountThresholdForReoptimizationFromLoop()
     1133        {
     1134            return adjustedExitCountThreshold(Options::osrExitCountForReoptimizationFromLoop());
     1135        }
    11311136
    11321137        bool shouldReoptimizeNow()
    11331138        {
    1134             return (Options::desiredSpeculativeSuccessFailRatio() *
    1135                         speculativeFailCounter() >= speculativeSuccessCounter()
    1136                     && speculativeFailCounter() >= largeFailCountThreshold())
    1137                 || forcedOSRExitCounter() >=
    1138                        Options::forcedOSRExitCountForReoptimization();
    1139         }
    1140 
     1139            return osrExitCounter() >= exitCountThresholdForReoptimization();
     1140        }
     1141       
    11411142        bool shouldReoptimizeFromLoopNow()
    11421143        {
    1143             return (Options::desiredSpeculativeSuccessFailRatio() *
    1144                         speculativeFailCounter() >= speculativeSuccessCounter()
    1145                     && speculativeFailCounter() >= largeFailCountThresholdForLoop())
    1146                 || forcedOSRExitCounter() >=
    1147                        Options::forcedOSRExitCountForReoptimization();
     1144            return osrExitCounter() >= exitCountThresholdForReoptimizationFromLoop();
    11481145        }
    11491146#endif
     
    13481345        ExecutionCounter m_jitExecuteCounter;
    13491346        int32_t m_totalJITExecutions;
    1350         uint32_t m_speculativeSuccessCounter;
    1351         uint32_t m_speculativeFailCounter;
    1352         uint32_t m_forcedOSRExitCounter;
     1347        uint32_t m_osrExitCounter;
    13531348        uint16_t m_optimizationDelayCounter;
    13541349        uint16_t m_reoptimizationRetryCounter;
Note: See TracChangeset for help on using the changeset viewer.