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/jit/JITStubs.cpp

    r121215 r121511  
    19291929
    19301930#if ENABLE(JIT_VERBOSE_OSR)
    1931     dataLog("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %s, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u\n", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter().status(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter());
     1931    dataLog("%p: Entered optimize with bytecodeIndex = %u, executeCounter = %s, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, exitCounter = ", codeBlock, bytecodeIndex, codeBlock->jitExecuteCounter().status(), codeBlock->reoptimizationRetryCounter(), codeBlock->optimizationDelayCounter());
     1932    if (codeBlock->hasOptimizedReplacement())
     1933        dataLog("%u", codeBlock->replacement()->osrExitCounter());
     1934    else
     1935        dataLog("N/A");
     1936    dataLog("\n");
    19321937#endif
    19331938
     
    19391944    if (codeBlock->hasOptimizedReplacement()) {
    19401945#if ENABLE(JIT_VERBOSE_OSR)
    1941         dataLog("Considering OSR into %p(%p) with success/fail %u/%u.\n", codeBlock, codeBlock->replacement(), codeBlock->replacement()->speculativeSuccessCounter(), codeBlock->replacement()->speculativeFailCounter());
     1946        dataLog("Considering OSR into %p(%p).\n", codeBlock, codeBlock->replacement());
    19421947#endif
     1948        // If we have an optimized replacement, then it must be the case that we entered
     1949        // cti_optimize from a loop. That's because is there's an optimized replacement,
     1950        // then all calls to this function will be relinked to the replacement and so
     1951        // the prologue OSR will never fire.
     1952       
     1953        // This is an interesting threshold check. Consider that a function OSR exits
     1954        // in the middle of a loop, while having a relatively low exit count. The exit
     1955        // will reset the execution counter to some target threshold, meaning that this
     1956        // code won't be reached until that loop heats up for >=1000 executions. But then
     1957        // we do a second check here, to see if we should either reoptimize, or just
     1958        // attempt OSR entry. Hence it might even be correct for
     1959        // shouldReoptimizeFromLoopNow() to always return true. But we make it do some
     1960        // additional checking anyway, to reduce the amount of recompilation thrashing.
    19431961        if (codeBlock->replacement()->shouldReoptimizeFromLoopNow()) {
    19441962#if ENABLE(JIT_VERBOSE_OSR)
     
    19862004
    19872005        codeBlock->optimizeSoon();
    1988         optimizedCodeBlock->countSpeculationSuccess();
    19892006        STUB_SET_RETURN_ADDRESS(address);
    19902007        return;
     
    19972014    // Count the OSR failure as a speculation failure. If this happens a lot, then
    19982015    // reoptimize.
    1999     optimizedCodeBlock->countSpeculationFailure();
     2016    optimizedCodeBlock->countOSRExit();
    20002017   
    20012018#if ENABLE(JIT_VERBOSE_OSR)
    2002     dataLog("Encountered OSR failure into %p(%p) with success/fail %u/%u.\n", codeBlock, codeBlock->replacement(), codeBlock->replacement()->speculativeSuccessCounter(), codeBlock->replacement()->speculativeFailCounter());
     2019    dataLog("Encountered OSR failure into %p(%p).\n", codeBlock, codeBlock->replacement());
    20032020#endif
    20042021
Note: See TracChangeset for help on using the changeset viewer.