Ignore:
Timestamp:
Jun 28, 2012, 7:40:14 PM (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.

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::osrExitCounter):
(JSC::CodeBlock::countOSRExit):
(CodeBlock):
(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/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.cpp:

(Options):
(JSC::Options::initializeOptions):

  • runtime/Options.h:

(Options):

File:
1 edited

Legend:

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

    r121480 r121511  
    10791079        }
    10801080       
    1081         // The speculative JIT tracks its success rate, so that we can
    1082         // decide when to reoptimize. It's interesting to note that these
    1083         // counters may overflow without any protection. The success
    1084         // counter will overflow before the fail one does, becuase the
    1085         // fail one is used as a trigger to reoptimize. So the worst case
    1086         // is that the success counter overflows and we reoptimize without
    1087         // needing to. But this is harmless. If a method really did
    1088         // execute 2^32 times then compiling it again probably won't hurt
    1089         // anyone.
    1090        
    1091         void countSpeculationSuccess()
    1092         {
    1093             m_speculativeSuccessCounter++;
    1094         }
    1095        
    1096         void countSpeculationFailure()
    1097         {
    1098             m_speculativeFailCounter++;
    1099         }
    1100        
    1101         uint32_t speculativeSuccessCounter() const { return m_speculativeSuccessCounter; }
    1102         uint32_t speculativeFailCounter() const { return m_speculativeFailCounter; }
    1103         uint32_t forcedOSRExitCounter() const { return m_forcedOSRExitCounter; }
    1104        
    1105         uint32_t* addressOfSpeculativeSuccessCounter() { return &m_speculativeSuccessCounter; }
    1106         uint32_t* addressOfSpeculativeFailCounter() { return &m_speculativeFailCounter; }
    1107         uint32_t* addressOfForcedOSRExitCounter() { return &m_forcedOSRExitCounter; }
    1108        
    1109         static ptrdiff_t offsetOfSpeculativeSuccessCounter() { return OBJECT_OFFSETOF(CodeBlock, m_speculativeSuccessCounter); }
    1110         static ptrdiff_t offsetOfSpeculativeFailCounter() { return OBJECT_OFFSETOF(CodeBlock, m_speculativeFailCounter); }
    1111         static ptrdiff_t offsetOfForcedOSRExitCounter() { return OBJECT_OFFSETOF(CodeBlock, m_forcedOSRExitCounter); }
     1081        uint32_t osrExitCounter() const { return m_osrExitCounter; }
     1082       
     1083        void countOSRExit() { m_osrExitCounter++; }
     1084       
     1085        uint32_t* addressOfOSRExitCounter() { return &m_osrExitCounter; }
     1086       
     1087        static ptrdiff_t offsetOfOSRExitCounter() { return OBJECT_OFFSETOF(CodeBlock, m_osrExitCounter); }
    11121088
    11131089#if ENABLE(JIT)
    1114         // The number of failures that triggers the use of the ratio.
    1115         unsigned largeFailCountThreshold() { return Options::largeFailCountThresholdBase << baselineVersion()->reoptimizationRetryCounter(); }
    1116         unsigned largeFailCountThresholdForLoop() { return Options::largeFailCountThresholdBaseForLoop << baselineVersion()->reoptimizationRetryCounter(); }
     1090        uint32_t adjustedExitCountThreshold(uint32_t desiredThreshold)
     1091        {
     1092            ASSERT(getJITType() == JITCode::DFGJIT);
     1093            // Compute this the lame way so we don't saturate. This is called infrequently
     1094            // enough that this loop won't hurt us.
     1095            unsigned result = desiredThreshold;
     1096            for (unsigned n = baselineVersion()->reoptimizationRetryCounter(); n--;) {
     1097                unsigned newResult = result << 1;
     1098                if (newResult < result)
     1099                    return std::numeric_limits<uint32_t>::max();
     1100                result = newResult;
     1101            }
     1102            return result;
     1103        }
     1104       
     1105        uint32_t exitCountThresholdForReoptimization()
     1106        {
     1107            return adjustedExitCountThreshold(Options::osrExitCountForReoptimization);
     1108        }
     1109       
     1110        uint32_t exitCountThresholdForReoptimizationFromLoop()
     1111        {
     1112            return adjustedExitCountThreshold(Options::osrExitCountForReoptimizationFromLoop);
     1113        }
    11171114
    11181115        bool shouldReoptimizeNow()
    11191116        {
    1120             return (Options::desiredSpeculativeSuccessFailRatio *
    1121                         speculativeFailCounter() >= speculativeSuccessCounter()
    1122                     && speculativeFailCounter() >= largeFailCountThreshold())
    1123                 || forcedOSRExitCounter() >=
    1124                        Options::forcedOSRExitCountForReoptimization;
    1125         }
    1126 
     1117            return osrExitCounter() >= exitCountThresholdForReoptimization();
     1118        }
     1119       
    11271120        bool shouldReoptimizeFromLoopNow()
    11281121        {
    1129             return (Options::desiredSpeculativeSuccessFailRatio *
    1130                         speculativeFailCounter() >= speculativeSuccessCounter()
    1131                     && speculativeFailCounter() >= largeFailCountThresholdForLoop())
    1132                 || forcedOSRExitCounter() >=
    1133                        Options::forcedOSRExitCountForReoptimization;
     1122            return osrExitCounter() >= exitCountThresholdForReoptimizationFromLoop();
    11341123        }
    11351124#endif
     
    13321321        ExecutionCounter m_jitExecuteCounter;
    13331322        int32_t m_totalJITExecutions;
    1334         uint32_t m_speculativeSuccessCounter;
    1335         uint32_t m_speculativeFailCounter;
    1336         uint32_t m_forcedOSRExitCounter;
     1323        uint32_t m_osrExitCounter;
    13371324        uint16_t m_optimizationDelayCounter;
    13381325        uint16_t m_reoptimizationRetryCounter;
Note: See TracChangeset for help on using the changeset viewer.