Changeset 249670 in webkit


Ignore:
Timestamp:
Sep 9, 2019 3:38:40 PM (5 years ago)
Author:
msaboff@apple.com
Message:

Revert to pre-r243144 scavenging behavior for macOS
https://bugs.webkit.org/show_bug.cgi?id=201555

Reviewed by Saam Barati.

The change in r243144 regressed internal power metrics for some Mac models.

  • bmalloc/Heap.cpp:

(bmalloc::Heap::scavenge):
(bmalloc::Heap::scavengeToHighWatermark):
(bmalloc::Heap::allocateSmallChunk):
(bmalloc::Heap::allocateSmallPage):
(bmalloc::Heap::allocateLarge):

  • bmalloc/Heap.h:
  • bmalloc/IsoDirectory.h:
  • bmalloc/IsoDirectoryInlines.h:

(bmalloc::passedNumPages>::takeFirstEligible):
(bmalloc::passedNumPages>::scavenge):
(bmalloc::passedNumPages>::scavengeToHighWatermark):

  • bmalloc/IsoHeapImpl.h:
  • bmalloc/IsoHeapImplInlines.h:

(bmalloc::IsoHeapImpl<Config>::scavengeToHighWatermark):

  • bmalloc/LargeMap.cpp:

(bmalloc::LargeMap::add):

  • bmalloc/LargeRange.h:

(bmalloc::LargeRange::LargeRange):
(bmalloc::merge):

  • bmalloc/Scavenger.cpp:

(bmalloc::Scavenger::Scavenger):
(bmalloc::Scavenger::timeSinceLastPartialScavenge):
(bmalloc::Scavenger::scavenge):
(bmalloc::Scavenger::partialScavenge):
(bmalloc::Scavenger::threadRunLoop):

  • bmalloc/Scavenger.h:
  • bmalloc/SmallPage.h:
Location:
trunk/Source/bmalloc
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/bmalloc/ChangeLog

    r249621 r249670  
     12019-09-09  Michael Saboff  <msaboff@apple.com>
     2
     3        Revert to pre-r243144 scavenging behavior for macOS
     4        https://bugs.webkit.org/show_bug.cgi?id=201555
     5
     6        Reviewed by Saam Barati.
     7
     8        The change in r243144 regressed internal power metrics for some Mac models.
     9
     10        * bmalloc/Heap.cpp:
     11        (bmalloc::Heap::scavenge):
     12        (bmalloc::Heap::scavengeToHighWatermark):
     13        (bmalloc::Heap::allocateSmallChunk):
     14        (bmalloc::Heap::allocateSmallPage):
     15        (bmalloc::Heap::allocateLarge):
     16        * bmalloc/Heap.h:
     17        * bmalloc/IsoDirectory.h:
     18        * bmalloc/IsoDirectoryInlines.h:
     19        (bmalloc::passedNumPages>::takeFirstEligible):
     20        (bmalloc::passedNumPages>::scavenge):
     21        (bmalloc::passedNumPages>::scavengeToHighWatermark):
     22        * bmalloc/IsoHeapImpl.h:
     23        * bmalloc/IsoHeapImplInlines.h:
     24        (bmalloc::IsoHeapImpl<Config>::scavengeToHighWatermark):
     25        * bmalloc/LargeMap.cpp:
     26        (bmalloc::LargeMap::add):
     27        * bmalloc/LargeRange.h:
     28        (bmalloc::LargeRange::LargeRange):
     29        (bmalloc::merge):
     30        * bmalloc/Scavenger.cpp:
     31        (bmalloc::Scavenger::Scavenger):
     32        (bmalloc::Scavenger::timeSinceLastPartialScavenge):
     33        (bmalloc::Scavenger::scavenge):
     34        (bmalloc::Scavenger::partialScavenge):
     35        (bmalloc::Scavenger::threadRunLoop):
     36        * bmalloc/Scavenger.h:
     37        * bmalloc/SmallPage.h:
     38
    1392019-09-07  Mark Lam  <mark.lam@apple.com>
    240
  • trunk/Source/bmalloc/bmalloc/Heap.cpp

    r249578 r249670  
    176176}
    177177
     178#if BPLATFORM(MAC)
     179void Heap::scavenge(std::lock_guard<Mutex>& lock, BulkDecommit& decommitter)
     180#else
    178181void Heap::scavenge(std::lock_guard<Mutex>& lock, BulkDecommit& decommitter, size_t& deferredDecommits)
     182#endif
    179183{
    180184    for (auto& list : m_freePages) {
     
    183187                if (!page->hasPhysicalPages())
    184188                    continue;
     189#if !BPLATFORM(MAC)
    185190                if (page->usedSinceLastScavenge()) {
    186191                    page->clearUsedSinceLastScavenge();
     
    188193                    continue;
    189194                }
     195#endif
    190196
    191197                size_t pageSize = bmalloc::pageSize(&list - &m_freePages[0]);
     
    208214
    209215    for (LargeRange& range : m_largeFree) {
     216#if BPLATFORM(MAC)
     217        m_highWatermark = std::min(m_highWatermark, static_cast<void*>(range.begin()));
     218#else
    210219        if (range.usedSinceLastScavenge()) {
    211220            range.clearUsedSinceLastScavenge();
     
    213222            continue;
    214223        }
     224#endif
    215225        decommitLargeRange(lock, range, decommitter);
    216226    }
    217 }
     227
     228#if BPLATFORM(MAC)
     229    m_freeableMemory = 0;
     230#endif
     231}
     232
     233#if BPLATFORM(MAC)
     234void Heap::scavengeToHighWatermark(std::lock_guard<Mutex>& lock, BulkDecommit& decommitter)
     235{
     236    void* newHighWaterMark = nullptr;
     237    for (LargeRange& range : m_largeFree) {
     238        if (range.begin() <= m_highWatermark)
     239            newHighWaterMark = std::min(newHighWaterMark, static_cast<void*>(range.begin()));
     240        else
     241            decommitLargeRange(lock, range, decommitter);
     242    }
     243    m_highWatermark = newHighWaterMark;
     244}
     245#endif
    218246
    219247void Heap::deallocateLineCache(std::unique_lock<Mutex>&, LineCache& lineCache)
     
    249277        forEachPage(chunk, pageSize, [&](SmallPage* page) {
    250278            page->setHasPhysicalPages(true);
     279#if !BPLATFORM(MAC)
    251280            page->setUsedSinceLastScavenge();
     281#endif
    252282            page->setHasFreeLines(lock, true);
    253283            chunk->freePages().push(page);
     
    332362#endif
    333363        }
     364#if !BPLATFORM(MAC)
    334365        page->setUsedSinceLastScavenge();
     366#endif
    335367
    336368        return page;
     
    608640
    609641    void* result = splitAndAllocate(lock, range, alignment, size).begin();
     642#if BPLATFORM(MAC)
     643    m_highWatermark = std::max(m_highWatermark, result);
     644#endif
    610645    ASSERT_OR_RETURN_ON_FAILURE(result);
    611646    return result;
  • trunk/Source/bmalloc/bmalloc/Heap.h

    r249578 r249670  
    7777    void shrinkLarge(std::unique_lock<Mutex>&, const Range&, size_t);
    7878
     79#if BPLATFORM(MAC)
     80    void scavengeToHighWatermark(std::lock_guard<Mutex>&, BulkDecommit&);
     81    void scavenge(std::lock_guard<Mutex>&, BulkDecommit&);
     82#else
    7983    void scavenge(std::lock_guard<Mutex>&, BulkDecommit&, size_t& deferredDecommits);
     84#endif
    8085    void scavenge(std::lock_guard<Mutex>&, BulkDecommit&, size_t& freed, size_t goal);
    8186
     
    153158    PhysicalPageMap m_physicalPageMap;
    154159#endif
     160   
     161#if BPLATFORM(MAC)
     162    void* m_highWatermark { nullptr };
     163#endif
    155164};
    156165
  • trunk/Source/bmalloc/bmalloc/IsoDirectory.h

    r245908 r249670  
    7676    // pages as being decommitted. It's the caller's job to do the actual decommitting.
    7777    void scavenge(Vector<DeferredDecommit>&);
     78#if BPLATFORM(MAC)
     79    void scavengeToHighWatermark(Vector<DeferredDecommit>&);
     80#endif
    7881
    7982    template<typename Func>
     
    9093    std::array<IsoPage<Config>*, numPages> m_pages;
    9194    unsigned m_firstEligibleOrDecommitted { 0 };
     95#if BPLATFORM(MAC)
     96    unsigned m_highWatermark { 0 };
     97#endif
    9298};
    9399
  • trunk/Source/bmalloc/bmalloc/IsoDirectoryInlines.h

    r245908 r249670  
    5252    if (pageIndex >= numPages)
    5353        return EligibilityKind::Full;
     54
     55#if BPLATFORM(MAC)
     56    m_highWatermark = std::max(pageIndex, m_highWatermark);
     57#endif
    5458
    5559    Scavenger& scavenger = *Scavenger::get();
     
    145149            scavengePage(index, decommits);
    146150        });
     151#if BPLATFORM(MAC)
     152    m_highWatermark = 0;
     153#endif
    147154}
     155
     156#if BPLATFORM(MAC)
     157template<typename Config, unsigned passedNumPages>
     158void IsoDirectory<Config, passedNumPages>::scavengeToHighWatermark(Vector<DeferredDecommit>& decommits)
     159{
     160    (m_empty & m_committed).forEachSetBit(
     161        [&] (size_t index) {
     162            if (index > m_highWatermark)
     163                scavengePage(index, decommits);
     164        });
     165    m_highWatermark = 0;
     166}
     167#endif
    148168
    149169template<typename Config, unsigned passedNumPages>
  • trunk/Source/bmalloc/bmalloc/IsoHeapImpl.h

    r249461 r249670  
    4949   
    5050    virtual void scavenge(Vector<DeferredDecommit>&) = 0;
     51#if BPLATFORM(MAC)
     52    virtual void scavengeToHighWatermark(Vector<DeferredDecommit>&) = 0;
     53#endif
    5154    virtual size_t freeableMemory() = 0;
    5255    virtual size_t footprint() = 0;
     
    8891   
    8992    void scavenge(Vector<DeferredDecommit>&) override;
     93#if BPLATFORM(MAC)
     94    void scavengeToHighWatermark(Vector<DeferredDecommit>&) override;
     95#endif
    9096
    9197    size_t freeableMemory() override;
  • trunk/Source/bmalloc/bmalloc/IsoHeapImplInlines.h

    r249461 r249670  
    111111}
    112112
     113#if BPLATFORM(MAC)
     114template<typename Config>
     115void IsoHeapImpl<Config>::scavengeToHighWatermark(Vector<DeferredDecommit>& decommits)
     116{
     117    std::lock_guard<Mutex> locker(this->lock);
     118    if (!m_directoryHighWatermark)
     119        m_inlineDirectory.scavengeToHighWatermark(decommits);
     120    for (IsoDirectoryPage<Config>* page = m_headDirectory; page; page = page->next) {
     121        if (page->index() >= m_directoryHighWatermark)
     122            page->payload.scavengeToHighWatermark(decommits);
     123    }
     124    m_directoryHighWatermark = 0;
     125}
     126#endif
     127
    113128template<typename Config>
    114129size_t IsoHeapImpl<Config>::freeableMemory()
  • trunk/Source/bmalloc/bmalloc/LargeMap.cpp

    r243144 r249670  
    7777    }
    7878
     79#if !BPLATFORM(MAC)
    7980    merged.setUsedSinceLastScavenge();
     81#endif
    8082    m_free.push(merged);
    8183}
  • trunk/Source/bmalloc/bmalloc/LargeRange.h

    r243144 r249670  
    3838        , m_startPhysicalSize(0)
    3939        , m_totalPhysicalSize(0)
     40#if !BPLATFORM(MAC)
    4041        , m_isEligible(true)
    4142        , m_usedSinceLastScavenge(false)
     43#endif
    4244    {
    4345    }
     
    4749        , m_startPhysicalSize(startPhysicalSize)
    4850        , m_totalPhysicalSize(totalPhysicalSize)
     51#if !BPLATFORM(MAC)
    4952        , m_isEligible(true)
    5053        , m_usedSinceLastScavenge(false)
     54#endif
    5155    {
    5256        BASSERT(this->size() >= this->totalPhysicalSize());
     
    5458    }
    5559
     60#if BPLATFORM(MAC)
     61    LargeRange(void* begin, size_t size, size_t startPhysicalSize, size_t totalPhysicalSize)
     62        : Range(begin, size)
     63        , m_startPhysicalSize(startPhysicalSize)
     64        , m_totalPhysicalSize(totalPhysicalSize)
     65    {
     66        BASSERT(this->size() >= this->totalPhysicalSize());
     67        BASSERT(this->totalPhysicalSize() >= this->startPhysicalSize());
     68    }
     69#else
    5670    LargeRange(void* begin, size_t size, size_t startPhysicalSize, size_t totalPhysicalSize, bool usedSinceLastScavenge = false)
    5771        : Range(begin, size)
     
    6478        BASSERT(this->totalPhysicalSize() >= this->startPhysicalSize());
    6579    }
     80#endif
    6681
    6782    // Returns a lower bound on physical size at the start of the range. Ranges that
     
    90105    bool isEligibile() const { return m_isEligible; }
    91106
     107#if !BPLATFORM(MAC)
    92108    bool usedSinceLastScavenge() const { return m_usedSinceLastScavenge; }
    93109    void clearUsedSinceLastScavenge() { m_usedSinceLastScavenge = false; }
    94110    void setUsedSinceLastScavenge() { m_usedSinceLastScavenge = true; }
     111#endif
    95112
    96113    bool operator<(const void* other) const { return begin() < other; }
     
    100117    size_t m_startPhysicalSize;
    101118    size_t m_totalPhysicalSize;
     119#if BPLATFORM(MAC)
     120    bool m_isEligible { true };
     121#else
    102122    unsigned m_isEligible: 1;
    103123    unsigned m_usedSinceLastScavenge: 1;
     124#endif
    104125};
    105126
     
    124145{
    125146    const LargeRange& left = std::min(a, b);
     147#if !BPLATFORM(MAC)
    126148    bool mergedUsedSinceLastScavenge = a.usedSinceLastScavenge() || b.usedSinceLastScavenge();
     149#endif
    127150    if (left.size() == left.startPhysicalSize()) {
    128151        return LargeRange(
     
    130153            a.size() + b.size(),
    131154            a.startPhysicalSize() + b.startPhysicalSize(),
    132             a.totalPhysicalSize() + b.totalPhysicalSize(),
    133             mergedUsedSinceLastScavenge);
     155            a.totalPhysicalSize() + b.totalPhysicalSize()
     156#if !BPLATFORM(MAC)
     157            , mergedUsedSinceLastScavenge
     158#endif
     159        );
     160       
    134161    }
    135162
     
    138165        a.size() + b.size(),
    139166        left.startPhysicalSize(),
    140         a.totalPhysicalSize() + b.totalPhysicalSize(),
    141         mergedUsedSinceLastScavenge);
     167        a.totalPhysicalSize() + b.totalPhysicalSize()
     168#if !BPLATFORM(MAC)
     169        , mergedUsedSinceLastScavenge
     170#endif
     171    );
    142172}
    143173
  • trunk/Source/bmalloc/bmalloc/Scavenger.cpp

    r244497 r249670  
    8181    dispatch_release(queue);
    8282#endif
     83#if BPLATFORM(MAC)
     84    m_waitTime = std::chrono::milliseconds(m_isInMiniMode ? 200 : 2000);
     85#else
    8386    m_waitTime = std::chrono::milliseconds(10);
     87#endif
    8488
    8589    m_thread = std::thread(&threadEntryPoint, this);
     
    179183}
    180184
     185#if BPLATFORM(MAC)
     186std::chrono::milliseconds Scavenger::timeSinceLastPartialScavenge()
     187{
     188    std::unique_lock<Mutex> lock(mutex());
     189    return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_lastPartialScavengeTime);
     190}
     191#endif
     192
    181193void Scavenger::enableMiniMode()
    182194{
     
    201213        {
    202214            PrintTime printTime("\nfull scavenge under lock time");
     215#if !BPLATFORM(MAC)
    203216            size_t deferredDecommits = 0;
     217#endif
    204218            std::lock_guard<Mutex> lock(Heap::mutex());
    205219            for (unsigned i = numHeaps; i--;) {
    206220                if (!isActiveHeapKind(static_cast<HeapKind>(i)))
    207221                    continue;
     222#if BPLATFORM(MAC)
     223                PerProcess<PerHeapKind<Heap>>::get()->at(i).scavenge(lock, decommitter);
     224#else
    208225                PerProcess<PerHeapKind<Heap>>::get()->at(i).scavenge(lock, decommitter, deferredDecommits);
     226#endif
    209227            }
    210228            decommitter.processEager();
    211229
     230#if !BPLATFORM(MAC)
    212231            if (deferredDecommits)
    213232                m_state = State::RunSoon;
     233#endif
    214234        }
    215235
     
    251271    }
    252272}
     273
     274#if BPLATFORM(MAC)
     275void Scavenger::partialScavenge()
     276{
     277    std::unique_lock<Mutex> lock(m_scavengingMutex);
     278
     279    if (verbose) {
     280        fprintf(stderr, "--------------------------------\n");
     281        fprintf(stderr, "--before partial scavenging--\n");
     282        dumpStats();
     283    }
     284
     285    {
     286        BulkDecommit decommitter;
     287        {
     288            PrintTime printTime("\npartialScavenge under lock time");
     289            std::lock_guard<Mutex> lock(Heap::mutex());
     290            for (unsigned i = numHeaps; i--;) {
     291                if (!isActiveHeapKind(static_cast<HeapKind>(i)))
     292                    continue;
     293                Heap& heap = PerProcess<PerHeapKind<Heap>>::get()->at(i);
     294                size_t freeableMemory = heap.freeableMemory(lock);
     295                if (freeableMemory < 4 * MB)
     296                    continue;
     297                heap.scavengeToHighWatermark(lock, decommitter);
     298            }
     299
     300            decommitter.processEager();
     301        }
     302
     303        {
     304            PrintTime printTime("partialScavenge lazy decommit time");
     305            decommitter.processLazy();
     306        }
     307
     308        {
     309            PrintTime printTime("partialScavenge mark all as eligible time");
     310            std::lock_guard<Mutex> lock(Heap::mutex());
     311            for (unsigned i = numHeaps; i--;) {
     312                if (!isActiveHeapKind(static_cast<HeapKind>(i)))
     313                    continue;
     314                Heap& heap = PerProcess<PerHeapKind<Heap>>::get()->at(i);
     315                heap.markAllLargeAsEligibile(lock);
     316            }
     317        }
     318    }
     319
     320    {
     321        RELEASE_BASSERT(!m_deferredDecommits.size());
     322        AllIsoHeaps::get()->forEach(
     323            [&] (IsoHeapImplBase& heap) {
     324                heap.scavengeToHighWatermark(m_deferredDecommits);
     325            });
     326        IsoHeapImplBase::finishScavenging(m_deferredDecommits);
     327        m_deferredDecommits.shrink(0);
     328    }
     329
     330    if (verbose) {
     331        fprintf(stderr, "--after partial scavenging--\n");
     332        dumpStats();
     333        fprintf(stderr, "--------------------------------\n");
     334    }
     335
     336    {
     337        std::unique_lock<Mutex> lock(mutex());
     338        m_lastPartialScavengeTime = std::chrono::steady_clock::now();
     339    }
     340}
     341#endif
    253342
    254343size_t Scavenger::freeableMemory()
     
    333422        }
    334423
     424#if BPLATFORM(MAC)
     425        enum class ScavengeMode {
     426            None,
     427            Partial,
     428            Full
     429        };
     430
     431        size_t freeableMemory = this->freeableMemory();
     432
     433        ScavengeMode scavengeMode = [&] {
     434            auto timeSinceLastFullScavenge = this->timeSinceLastFullScavenge();
     435            auto timeSinceLastPartialScavenge = this->timeSinceLastPartialScavenge();
     436            auto timeSinceLastScavenge = std::min(timeSinceLastPartialScavenge, timeSinceLastFullScavenge);
     437
     438            if (isUnderMemoryPressure() && freeableMemory > 1 * MB && timeSinceLastScavenge > std::chrono::milliseconds(5))
     439                return ScavengeMode::Full;
     440
     441            if (!m_isProbablyGrowing) {
     442                if (timeSinceLastFullScavenge < std::chrono::milliseconds(1000) && !m_isInMiniMode)
     443                    return ScavengeMode::Partial;
     444                return ScavengeMode::Full;
     445            }
     446
     447            if (m_isInMiniMode) {
     448                if (timeSinceLastFullScavenge < std::chrono::milliseconds(200))
     449                    return ScavengeMode::Partial;
     450                return ScavengeMode::Full;
     451            }
     452
     453#if BCPU(X86_64)
     454            auto partialScavengeInterval = std::chrono::milliseconds(12000);
     455#else
     456            auto partialScavengeInterval = std::chrono::milliseconds(8000);
     457#endif
     458            if (timeSinceLastScavenge < partialScavengeInterval) {
     459                // Rate limit partial scavenges.
     460                return ScavengeMode::None;
     461            }
     462            if (freeableMemory < 25 * MB)
     463                return ScavengeMode::None;
     464            if (5 * freeableMemory < footprint())
     465                return ScavengeMode::None;
     466            return ScavengeMode::Partial;
     467        }();
     468
     469        m_isProbablyGrowing = false;
     470
     471        switch (scavengeMode) {
     472        case ScavengeMode::None: {
     473            runSoon();
     474            break;
     475        }
     476        case ScavengeMode::Partial: {
     477            partialScavenge();
     478            runSoon();
     479            break;
     480        }
     481        case ScavengeMode::Full: {
     482            scavenge();
     483            break;
     484        }
     485        }
     486#else
    335487        std::chrono::steady_clock::time_point start { std::chrono::steady_clock::now() };
    336488       
     
    358510        if (verbose)
    359511            fprintf(stderr, "new wait time %lldms\n", static_cast<long long int>(m_waitTime.count()));
     512#endif
    360513    }
    361514}
  • trunk/Source/bmalloc/bmalloc/Scavenger.h

    r244497 r249670  
    9090
    9191    std::chrono::milliseconds timeSinceLastFullScavenge();
     92#if BPLATFORM(MAC)
     93    std::chrono::milliseconds timeSinceLastPartialScavenge();
     94    void partialScavenge();
     95#endif
    9296
    9397    std::atomic<State> m_state { State::Sleep };
     
    102106    std::thread m_thread;
    103107    std::chrono::steady_clock::time_point m_lastFullScavengeTime { std::chrono::steady_clock::now() };
    104    
     108#if BPLATFORM(MAC)
     109    std::chrono::steady_clock::time_point m_lastPartialScavengeTime { std::chrono::steady_clock::now() };
     110#endif
     111
    105112#if BOS(DARWIN)
    106113    dispatch_source_t m_pressureHandlerDispatchSource;
  • trunk/Source/bmalloc/bmalloc/SmallPage.h

    r243144 r249670  
    5151    bool hasPhysicalPages() { return m_hasPhysicalPages; }
    5252    void setHasPhysicalPages(bool hasPhysicalPages) { m_hasPhysicalPages = hasPhysicalPages; }
    53    
     53
     54#if !BPLATFORM(MAC)
    5455    bool usedSinceLastScavenge() { return m_usedSinceLastScavenge; }
    5556    void clearUsedSinceLastScavenge() { m_usedSinceLastScavenge = false; }
    5657    void setUsedSinceLastScavenge() { m_usedSinceLastScavenge = true; }
     58#endif
    5759
    5860    SmallLine* begin();
     
    6466    unsigned char m_hasFreeLines: 1;
    6567    unsigned char m_hasPhysicalPages: 1;
     68#if !BPLATFORM(MAC)
    6669    unsigned char m_usedSinceLastScavenge: 1;
     70#endif
    6771    unsigned char m_refCount: 7;
    6872    unsigned char m_sizeClass;
Note: See TracChangeset for help on using the changeset viewer.