Changeset 187125 in webkit


Ignore:
Timestamp:
Jul 21, 2015 2:41:30 PM (9 years ago)
Author:
fpizlo@apple.com
Message:

Fixed VM pool allocation should have a reserve for allocations that cannot fail
https://bugs.webkit.org/show_bug.cgi?id=147154
rdar://problem/21847618

Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

This adds the notion of a JIT pool reserve fraction. Some fraction, currently 1/4, of
the JIT pool is reserved for allocations that cannot fail. It makes sense to make this
a fraction rather than a constant because each allocation that can fail may cause some
number of allocations that cannot fail (for example, the OSR exit thunks that we
compile when we exit from some CodeBlock cannot fail).

I've tested this by adding a test mode where we artificially limit the JIT pool size.
Prior to the fix, we had >20 failures. Now we have none.

  • heap/GCLogging.cpp:

(WTF::printInternal): I needed a dump method on Options members when debugging this.

  • heap/GCLogging.h:
  • jit/ExecutableAllocator.h: Raise the ARM64 limit to 32MB because 16MB is cutting it too close.
  • jit/ExecutableAllocatorFixedVMPool.cpp:

(JSC::FixedVMPoolExecutableAllocator::FixedVMPoolExecutableAllocator): Add the ability to artificially limit JIT pool size for testing.
(JSC::ExecutableAllocator::memoryPressureMultiplier): Implement the reserve when computing memory pressure for JIT tier-up heuristics.
(JSC::ExecutableAllocator::allocate): Implement the reserve when allocating can-fail things.

  • jsc.cpp: Rewire some options parsing so that CommandLine happens before we create the JIT pool.

(main):
(CommandLine::parseArguments):
(jscmain):

  • runtime/Options.cpp:

(JSC::OptionRange::dump): I needed a dump method on Options members when debugging this.
(JSC::Options::initialize): This can now be called more than once.

  • runtime/Options.h:

Tools:

Add a new test mode where we artificially limit JIT memory to 50KB. If our JIT OOM
mitigations work, these should all pass. Prior to this patch there were >20 failures.

  • Scripts/run-jsc-stress-tests:
Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r187119 r187125  
     12015-07-21  Filip Pizlo  <fpizlo@apple.com>
     2
     3        Fixed VM pool allocation should have a reserve for allocations that cannot fail
     4        https://bugs.webkit.org/show_bug.cgi?id=147154
     5        rdar://problem/21847618
     6
     7        Reviewed by Geoffrey Garen.
     8       
     9        This adds the notion of a JIT pool reserve fraction. Some fraction, currently 1/4, of
     10        the JIT pool is reserved for allocations that cannot fail. It makes sense to make this
     11        a fraction rather than a constant because each allocation that can fail may cause some
     12        number of allocations that cannot fail (for example, the OSR exit thunks that we
     13        compile when we exit from some CodeBlock cannot fail).
     14       
     15        I've tested this by adding a test mode where we artificially limit the JIT pool size.
     16        Prior to the fix, we had >20 failures. Now we have none.
     17
     18        * heap/GCLogging.cpp:
     19        (WTF::printInternal): I needed a dump method on Options members when debugging this.
     20        * heap/GCLogging.h:
     21        * jit/ExecutableAllocator.h: Raise the ARM64 limit to 32MB because 16MB is cutting it too close.
     22        * jit/ExecutableAllocatorFixedVMPool.cpp:
     23        (JSC::FixedVMPoolExecutableAllocator::FixedVMPoolExecutableAllocator): Add the ability to artificially limit JIT pool size for testing.
     24        (JSC::ExecutableAllocator::memoryPressureMultiplier): Implement the reserve when computing memory pressure for JIT tier-up heuristics.
     25        (JSC::ExecutableAllocator::allocate): Implement the reserve when allocating can-fail things.
     26        * jsc.cpp: Rewire some options parsing so that CommandLine happens before we create the JIT pool.
     27        (main):
     28        (CommandLine::parseArguments):
     29        (jscmain):
     30        * runtime/Options.cpp:
     31        (JSC::OptionRange::dump): I needed a dump method on Options members when debugging this.
     32        (JSC::Options::initialize): This can now be called more than once.
     33        * runtime/Options.h:
     34
    1352015-07-21  Saam barati  <saambarati1@gmail.com>
    236
  • trunk/Source/JavaScriptCore/heap/GCLogging.cpp

    r183124 r187125  
    11/*
    2  * Copyright (C) 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3232#include "JSCell.h"
    3333#include "JSCellInlines.h"
     34#include <wtf/PrintStream.h>
    3435
    3536namespace JSC {
     
    114115
    115116} // namespace JSC
     117
     118namespace WTF {
     119
     120void printInternal(PrintStream& out, JSC::GCLogging::Level level)
     121{
     122    switch (level) {
     123    case JSC::GCLogging::Level::None:
     124        out.print("None");
     125        return;
     126    case JSC::GCLogging::Level::Basic:
     127        out.print("Basic");
     128        return;
     129    case JSC::GCLogging::Level::Verbose:
     130        out.print("Verbose");
     131        return;
     132    default:
     133        out.print("Level=", level - JSC::GCLogging::Level::None);
     134        return;
     135    }
     136}
     137
     138} // namespace WTF
     139
  • trunk/Source/JavaScriptCore/heap/GCLogging.h

    r166838 r187125  
    11/*
    2  * Copyright (C) 2014 Apple Inc. All rights reserved.
     2 * Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    4949} // namespace JSC
    5050
     51namespace WTF {
     52
     53class PrintStream;
     54
     55void printInternal(PrintStream&, JSC::GCLogging::Level);
     56
     57} // namespace WTF
     58
    5159#endif // GCLogging_h
  • trunk/Source/JavaScriptCore/jit/ExecutableAllocator.h

    r185532 r187125  
    8181
    8282#if ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
    83 #if CPU(ARM) || CPU(ARM64)
     83#if CPU(ARM)
    8484static const size_t fixedExecutableMemoryPoolSize = 16 * 1024 * 1024;
     85#elif CPU(ARM64)
     86static const size_t fixedExecutableMemoryPoolSize = 32 * 1024 * 1024;
    8587#elif CPU(X86_64)
    8688static const size_t fixedExecutableMemoryPoolSize = 1024 * 1024 * 1024;
     
    8890static const size_t fixedExecutableMemoryPoolSize = 32 * 1024 * 1024;
    8991#endif
     92static const double executablePoolReservationFraction = 0.25;
    9093
    9194extern uintptr_t startOfFixedExecutableMemoryPool;
  • trunk/Source/JavaScriptCore/jit/ExecutableAllocatorFixedVMPool.cpp

    r185532 r187125  
    11/*
    2  * Copyright (C) 2009 Apple Inc. All rights reserved.
     2 * Copyright (C) 2009, 2015 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    6161        : MetaAllocator(jitAllocationGranule) // round up all allocations to 32 bytes
    6262    {
    63         m_reservation = PageReservation::reserveWithGuardPages(fixedExecutableMemoryPoolSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
     63        size_t reservationSize;
     64        if (Options::jitMemoryReservationSize())
     65            reservationSize = Options::jitMemoryReservationSize();
     66        else
     67            reservationSize = fixedExecutableMemoryPoolSize;
     68        m_reservation = PageReservation::reserveWithGuardPages(reservationSize, OSAllocator::JSJITCodePages, EXECUTABLE_POOL_WRITABLE, true);
    6469        if (m_reservation) {
    65             ASSERT(m_reservation.size() == fixedExecutableMemoryPoolSize);
     70            ASSERT(m_reservation.size() == reservationSize);
    6671            addFreshFreeSpace(m_reservation.base(), m_reservation.size());
    6772           
     
    149154    ASSERT(statistics.bytesAllocated <= statistics.bytesReserved);
    150155    size_t bytesAllocated = statistics.bytesAllocated + addedMemoryUsage;
    151     if (bytesAllocated >= statistics.bytesReserved)
    152         bytesAllocated = statistics.bytesReserved;
     156    size_t bytesAvailable = static_cast<size_t>(
     157        statistics.bytesReserved * (1 - executablePoolReservationFraction));
     158    if (bytesAllocated >= bytesAvailable)
     159        bytesAllocated = bytesAvailable;
    153160    double result = 1.0;
    154     size_t divisor = statistics.bytesReserved - bytesAllocated;
     161    size_t divisor = bytesAvailable - bytesAllocated;
    155162    if (divisor)
    156         result = static_cast<double>(statistics.bytesReserved) / divisor;
     163        result = static_cast<double>(bytesAvailable) / divisor;
    157164    if (result < 1.0)
    158165        result = 1.0;
     
    170177        && doExecutableAllocationFuzzingIfEnabled() == PretendToFailExecutableAllocation)
    171178        return nullptr;
     179   
     180    if (effort == JITCompilationCanFail) {
     181        // Don't allow allocations if we are down to reserve.
     182        MetaAllocator::Statistics statistics = allocator->currentStatistics();
     183        size_t bytesAllocated = statistics.bytesAllocated + sizeInBytes;
     184        size_t bytesAvailable = static_cast<size_t>(
     185            statistics.bytesReserved * (1 - executablePoolReservationFraction));
     186        if (bytesAllocated > bytesAvailable)
     187            return nullptr;
     188    }
    172189   
    173190    RefPtr<ExecutableMemoryHandle> result = allocator->allocate(sizeInBytes, ownerUID);
  • trunk/Source/JavaScriptCore/jsc.cpp

    r186966 r187125  
    12491249#endif
    12501250
    1251     // Initialize JSC before getting VM.
    1252 #if ENABLE(SAMPLING_REGIONS)
    1253     WTF::initializeMainThread();
    1254 #endif
    1255     JSC::initializeThreading();
    1256 
    12571251    if (char* timeoutString = getenv("JSC_timeout")) {
    12581252        if (sscanf(timeoutString, "%lf", &s_desiredTimeout) != 1) {
     
    14311425void CommandLine::parseArguments(int argc, char** argv)
    14321426{
     1427    Options::initialize();
     1428   
    14331429    int i = 1;
    14341430    bool needToDumpOptions = false;
     
    14951491
    14961492        // See if the -- option is a JSC VM option.
    1497         // NOTE: At this point, we know that the arg starts with "--". Skip it.
    1498         if (JSC::Options::setOption(&arg[2])) {
     1493        if (strstr(arg, "--") == arg && JSC::Options::setOption(&arg[2])) {
    14991494            // The arg was recognized as a VM option and has been parsed.
    15001495            continue; // Just continue with the next arg.
     
    15241519    // comes first.
    15251520    CommandLine options(argc, argv);
     1521
     1522    // Initialize JSC before getting VM.
     1523#if ENABLE(SAMPLING_REGIONS)
     1524    WTF::initializeMainThread();
     1525#endif
     1526    JSC::initializeThreading();
     1527
    15261528    VM* vm = &VM::create(LargeHeap).leakRef();
    15271529    int result;
  • trunk/Source/JavaScriptCore/runtime/Options.cpp

    r186688 r187125  
    3131#include <limits>
    3232#include <math.h>
     33#include <mutex>
    3334#include <stdlib.h>
    3435#include <string.h>
     
    200201
    201202    return m_state == Normal ? false : true;
     203}
     204
     205void OptionRange::dump(PrintStream& out) const
     206{
     207    out.print(m_rangeString);
    202208}
    203209
     
    319325void Options::initialize()
    320326{
    321     // Initialize each of the options with their default values:
    322 #define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
    323     name_() = defaultValue_; \
    324     name_##Default() = defaultValue_;
    325     JSC_OPTIONS(FOR_EACH_OPTION)
     327    static std::once_flag initializeOptionsOnceFlag;
     328   
     329    std::call_once(
     330        initializeOptionsOnceFlag,
     331        [] {
     332            // Initialize each of the options with their default values:
     333#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_)      \
     334            name_() = defaultValue_;                                    \
     335            name_##Default() = defaultValue_;
     336            JSC_OPTIONS(FOR_EACH_OPTION)
    326337#undef FOR_EACH_OPTION
    327338   
    328     // It *probably* makes sense for other platforms to enable this.
     339                // It *probably* makes sense for other platforms to enable this.
    329340#if PLATFORM(IOS) && CPU(ARM64)
    330     enableLLVMFastISel() = true;
     341                enableLLVMFastISel() = true;
    331342#endif
    332343       
    333     // Allow environment vars to override options if applicable.
    334     // The evn var should be the name of the option prefixed with
    335     // "JSC_".
    336 #define FOR_EACH_OPTION(type_, name_, defaultValue_, description_) \
    337     overrideOptionWithHeuristic(name_(), "JSC_" #name_);
    338     JSC_OPTIONS(FOR_EACH_OPTION)
     344            // Allow environment vars to override options if applicable.
     345            // The evn var should be the name of the option prefixed with
     346            // "JSC_".
     347#define FOR_EACH_OPTION(type_, name_, defaultValue_, description_)      \
     348            overrideOptionWithHeuristic(name_(), "JSC_" #name_);
     349            JSC_OPTIONS(FOR_EACH_OPTION)
    339350#undef FOR_EACH_OPTION
    340351
    341352#if 0
    342     ; // Deconfuse editors that do auto indentation
     353                ; // Deconfuse editors that do auto indentation
    343354#endif
    344355   
    345     recomputeDependentOptions();
    346 
    347     // Do range checks where needed and make corrections to the options:
    348     ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp());
    349     ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon());
    350     ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0);
    351 
    352     if (Options::showOptions()) {
    353         DumpLevel level = static_cast<DumpLevel>(Options::showOptions());
    354         if (level > DumpLevel::Verbose)
    355             level = DumpLevel::Verbose;
    356 
    357         const char* title = nullptr;
    358         switch (level) {
    359         case DumpLevel::None:
    360             break;
    361         case DumpLevel::Overridden:
    362             title = "Overridden JSC options:";
    363             break;
    364         case DumpLevel::All:
    365             title = "All JSC options:";
    366             break;
    367         case DumpLevel::Verbose:
    368             title = "All JSC options with descriptions:";
    369             break;
    370         }
    371         dumpAllOptions(level, title);
    372     }
    373 
    374     ensureOptionsAreCoherent();
     356            recomputeDependentOptions();
     357
     358            // Do range checks where needed and make corrections to the options:
     359            ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp());
     360            ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon());
     361            ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0);
     362
     363            if (Options::showOptions()) {
     364                DumpLevel level = static_cast<DumpLevel>(Options::showOptions());
     365                if (level > DumpLevel::Verbose)
     366                    level = DumpLevel::Verbose;
     367
     368                const char* title = nullptr;
     369                switch (level) {
     370                case DumpLevel::None:
     371                    break;
     372                case DumpLevel::Overridden:
     373                    title = "Overridden JSC options:";
     374                    break;
     375                case DumpLevel::All:
     376                    title = "All JSC options:";
     377                    break;
     378                case DumpLevel::Verbose:
     379                    title = "All JSC options with descriptions:";
     380                    break;
     381                }
     382                dumpAllOptions(level, title);
     383            }
     384
     385            ensureOptionsAreCoherent();
     386        });
    375387}
    376388
  • trunk/Source/JavaScriptCore/runtime/Options.h

    r186701 r187125  
    3131#include <stdint.h>
    3232#include <stdio.h>
     33#include <wtf/PrintStream.h>
    3334#include <wtf/StdLibExtras.h>
    3435
     
    8182    bool isInRange(unsigned);
    8283    const char* rangeString() const { return (m_state > InitError) ? m_rangeString : "<null>"; }
     84   
     85    void dump(PrintStream& out) const;
    8386
    8487private:
     
    107110    \
    108111    v(bool, crashIfCantAllocateJITMemory, false, nullptr) \
     112    v(unsigned, jitMemoryReservationSize, 0, nullptr) \
    109113    \
    110114    v(bool, forceDFGCodeBlockLiveness, false, nullptr) \
     
    351355    };
    352356
    353     static void initialize();
     357    JS_EXPORT_PRIVATE static void initialize();
    354358
    355359    // Parses a single command line option in the format "<optionName>=<value>"
  • trunk/Tools/ChangeLog

    r187100 r187125  
     12015-07-21  Filip Pizlo  <fpizlo@apple.com>
     2
     3        Fixed VM pool allocation should have a reserve for allocations that cannot fail
     4        https://bugs.webkit.org/show_bug.cgi?id=147154
     5        rdar://problem/21847618
     6
     7        Reviewed by Geoffrey Garen.
     8       
     9        Add a new test mode where we artificially limit JIT memory to 50KB. If our JIT OOM
     10        mitigations work, these should all pass. Prior to this patch there were >20 failures.
     11
     12        * Scripts/run-jsc-stress-tests:
     13
    1142015-07-20  Carlos Garcia Campos  <cgarcia@igalia.com>
    215
  • trunk/Tools/Scripts/run-jsc-stress-tests

    r185833 r187125  
    759759end
    760760
     761def runFTLNoCJITSmallPool
     762    run("ftl-no-cjit-small-pool", "--jitMemoryReservationSize=50000", *(FTL_OPTIONS + NO_CJIT_OPTIONS)) if $enableFTL
     763end
     764
    761765def defaultRun
    762766    runDefault
     
    772776        runFTLEager
    773777        runFTLEagerNoCJITValidate
     778        runFTLNoCJITSmallPool
    774779    end
    775780end
Note: See TracChangeset for help on using the changeset viewer.