Changeset 234646 in webkit


Ignore:
Timestamp:
Aug 7, 2018 3:01:18 AM (6 years ago)
Author:
Antti Koivisto
Message:

Web process never leaves memory pressured state if caused by process size limit
https://bugs.webkit.org/show_bug.cgi?id=188299
<rdar://problem/42157442>

Reviewed by Darin Adler.

For vm memory pressure warnings we get notified when exiting the state and we can clear
the isUnderMemoryPressure bit. However as a compatibility behavior we were also notified using
the same event when approaching the process size limit. In this case there is no "all clear"
event so we'd stay in pressured state forever, leading to unnecessarily degraded user experience.

  • WTF.xcodeproj/project.pbxproj:
  • wtf/cocoa/MemoryPressureHandlerCocoa.mm:

(WTF::MemoryPressureHandler::install):

Install a handler for process size limit events. This disables the compatibility behavior,
vm pressure events will be received for vm pressure only.

Process size limit events are treated as one-shot. We do cleanups based on criticality but
don't enter the pressured state.

(WTF::MemoryPressureHandler::uninstall):
(WTF::MemoryPressureHandler::holdOff):

  • wtf/spi/darwin/DispatchSPI.h: Added.
Location:
trunk/Source/WTF
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r234619 r234646  
     12018-08-07  Antti Koivisto  <antti@apple.com>
     2
     3        Web process never leaves memory pressured state if caused by process size limit
     4        https://bugs.webkit.org/show_bug.cgi?id=188299
     5        <rdar://problem/42157442>
     6
     7        Reviewed by Darin Adler.
     8
     9        For vm memory pressure warnings we get notified when exiting the state and we can clear
     10        the isUnderMemoryPressure bit. However as a compatibility behavior we were also notified using
     11        the same event when approaching the process size limit. In this case there is no "all clear"
     12        event so we'd stay in pressured state forever, leading to unnecessarily degraded user experience.
     13
     14        * WTF.xcodeproj/project.pbxproj:
     15        * wtf/cocoa/MemoryPressureHandlerCocoa.mm:
     16        (WTF::MemoryPressureHandler::install):
     17
     18        Install a handler for process size limit events. This disables the compatibility behavior,
     19        vm pressure events will be received for vm pressure only.
     20
     21        Process size limit events are treated as one-shot. We do cleanups based on criticality but
     22        don't enter the pressured state.
     23
     24        (WTF::MemoryPressureHandler::uninstall):
     25        (WTF::MemoryPressureHandler::holdOff):
     26        * wtf/spi/darwin/DispatchSPI.h: Added.
     27
    1282018-08-06  Alex Christensen  <achristensen@webkit.org>
    229
  • trunk/Source/WTF/WTF.xcodeproj/project.pbxproj

    r233409 r234646  
    633633                E3A32BC31FC830E2007D7E76 /* JSValueMalloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSValueMalloc.h; sourceTree = "<group>"; };
    634634                E3E158251EADA53C004A079D /* SystemFree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemFree.h; sourceTree = "<group>"; };
     635                E431CC4A21187ADB000C8A07 /* DispatchSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DispatchSPI.h; sourceTree = "<group>"; };
    635636                E4A0AD371A96245500536DF6 /* WorkQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WorkQueue.cpp; sourceTree = "<group>"; };
    636637                E4A0AD381A96245500536DF6 /* WorkQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WorkQueue.h; sourceTree = "<group>"; };
     
    12881289                        children = (
    12891290                                DE5A09FB1BA36992003D4424 /* CommonCryptoSPI.h */,
     1291                                E431CC4A21187ADB000C8A07 /* DispatchSPI.h */,
    12901292                                93DDE9311CDC052D00FD3491 /* dyldSPI.h */,
    12911293                                A5098AFF1C169E0700087797 /* SandboxSPI.h */,
  • trunk/Source/WTF/wtf/cocoa/MemoryPressureHandlerCocoa.mm

    r233128 r234646  
    3131#import <malloc/malloc.h>
    3232#import <notify.h>
     33#import <wtf/spi/darwin/DispatchSPI.h>
    3334
    3435#define ENABLE_FMW_FOOTPRINT_COMPARISON 0
     
    4748}
    4849
    49 static dispatch_source_t _cache_event_source = 0;
    50 static dispatch_source_t _timer_event_source = 0;
    51 static int _notifyTokens[3];
     50static dispatch_source_t memoryPressureEventSource = nullptr;
     51static dispatch_source_t timerEventSource = nullptr;
     52static int notifyTokens[3];
    5253
    5354// Disable memory event reception for a minimum of s_minimumHoldOffTime
     
    6465void MemoryPressureHandler::install()
    6566{
    66     if (m_installed || _timer_event_source)
     67    if (m_installed || timerEventSource)
    6768        return;
    6869
    6970    dispatch_async(dispatch_get_main_queue(), ^{
    7071#if PLATFORM(IOS)
    71         _cache_event_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0, DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL, dispatch_get_main_queue());
    72 #elif PLATFORM(MAC)
    73         _cache_event_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0, DISPATCH_MEMORYPRESSURE_CRITICAL, dispatch_get_main_queue());
    74 #endif
    75 
    76         dispatch_set_context(_cache_event_source, this);
    77         dispatch_source_set_event_handler(_cache_event_source, ^{
    78             bool critical = true;
     72        auto memoryStatusFlags = DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL | DISPATCH_MEMORYPRESSURE_PROC_LIMIT_WARN | DISPATCH_MEMORYPRESSURE_PROC_LIMIT_CRITICAL;
     73#else // PLATFORM(MAC)
     74        auto memoryStatusFlags = DISPATCH_MEMORYPRESSURE_CRITICAL;
     75#endif
     76        memoryPressureEventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0, memoryStatusFlags, dispatch_get_main_queue());
     77
     78        dispatch_source_set_event_handler(memoryPressureEventSource, ^{
     79            auto status = dispatch_source_get_data(memoryPressureEventSource);
    7980#if PLATFORM(IOS)
    80             unsigned long status = dispatch_source_get_data(_cache_event_source);
    81             critical = status == DISPATCH_MEMORYPRESSURE_CRITICAL;
    82             auto& memoryPressureHandler = MemoryPressureHandler::singleton();
    83             bool wasCritical = memoryPressureHandler.isUnderMemoryPressure();
    84             memoryPressureHandler.setUnderMemoryPressure(critical);
    85             if (status == DISPATCH_MEMORYPRESSURE_NORMAL) {
    86                 if (ReliefLogger::loggingEnabled())
    87                     NSLog(@"System is no longer under (%s) memory pressure.", wasCritical ? "critical" : "non-critical");
    88                 return;
     81            switch (status) {
     82            // VM pressure events.
     83            case DISPATCH_MEMORYPRESSURE_NORMAL:
     84                setUnderMemoryPressure(false);
     85                break;
     86            case DISPATCH_MEMORYPRESSURE_WARN:
     87                setUnderMemoryPressure(false);
     88                respondToMemoryPressure(Critical::No);
     89                break;
     90            case DISPATCH_MEMORYPRESSURE_CRITICAL:
     91                setUnderMemoryPressure(true);
     92                respondToMemoryPressure(Critical::Yes);
     93                break;
     94            // Process memory limit events.
     95            case DISPATCH_MEMORYPRESSURE_PROC_LIMIT_WARN:
     96                respondToMemoryPressure(Critical::No);
     97                break;
     98            case DISPATCH_MEMORYPRESSURE_PROC_LIMIT_CRITICAL:
     99                respondToMemoryPressure(Critical::Yes);
     100                break;
    89101            }
    90 
    91             if (ReliefLogger::loggingEnabled())
    92                 NSLog(@"Got memory pressure notification (%s)", critical ? "critical" : "non-critical");
    93 #endif
    94             MemoryPressureHandler::singleton().respondToMemoryPressure(critical ? Critical::Yes : Critical::No);
     102#else // PLATFORM(MAC)
     103            respondToMemoryPressure(Critical::Yes);
     104#endif
     105            WTFLogAlways("Received memory pressure event %lu vm pressure %d", status, isUnderMemoryPressure());
    95106        });
    96         dispatch_resume(_cache_event_source);
     107        dispatch_resume(memoryPressureEventSource);
    97108    });
    98109
    99110    // Allow simulation of memory pressure with "notifyutil -p org.WebKit.lowMemory"
    100     notify_register_dispatch("org.WebKit.lowMemory", &_notifyTokens[0], dispatch_get_main_queue(), ^(int) {
     111    notify_register_dispatch("org.WebKit.lowMemory", &notifyTokens[0], dispatch_get_main_queue(), ^(int) {
    101112#if ENABLE(FMW_FOOTPRINT_COMPARISON)
    102113        auto footprintBefore = pagesPerVMTag();
     
    117128    });
    118129
    119     notify_register_dispatch("org.WebKit.lowMemory.begin", &_notifyTokens[1], dispatch_get_main_queue(), ^(int) {
     130    notify_register_dispatch("org.WebKit.lowMemory.begin", &notifyTokens[1], dispatch_get_main_queue(), ^(int) {
    120131        beginSimulatedMemoryPressure();
    121132    });
    122     notify_register_dispatch("org.WebKit.lowMemory.end", &_notifyTokens[2], dispatch_get_main_queue(), ^(int) {
     133    notify_register_dispatch("org.WebKit.lowMemory.end", &notifyTokens[2], dispatch_get_main_queue(), ^(int) {
    123134        endSimulatedMemoryPressure();
    124135    });
     
    133144
    134145    dispatch_async(dispatch_get_main_queue(), ^{
    135         if (_cache_event_source) {
    136             dispatch_source_cancel(_cache_event_source);
    137             _cache_event_source = 0;
     146        if (memoryPressureEventSource) {
     147            dispatch_source_cancel(memoryPressureEventSource);
     148            memoryPressureEventSource = nullptr;
    138149        }
    139150
    140         if (_timer_event_source) {
    141             dispatch_source_cancel(_timer_event_source);
    142             _timer_event_source = 0;
     151        if (timerEventSource) {
     152            dispatch_source_cancel(timerEventSource);
     153            timerEventSource = nullptr;
    143154        }
    144155    });
     
    146157    m_installed = false;
    147158
    148     for (auto& token : _notifyTokens)
     159    for (auto& token : notifyTokens)
    149160        notify_cancel(token);
    150161}
     
    153164{
    154165    dispatch_async(dispatch_get_main_queue(), ^{
    155         _timer_event_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    156         if (_timer_event_source) {
    157             dispatch_set_context(_timer_event_source, this);
     166        timerEventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
     167        if (timerEventSource) {
     168            dispatch_set_context(timerEventSource, this);
    158169            // FIXME: The final argument `s_minimumHoldOffTime.seconds()` seems wrong.
    159170            // https://bugs.webkit.org/show_bug.cgi?id=183277
    160             dispatch_source_set_timer(_timer_event_source, dispatch_time(DISPATCH_TIME_NOW, seconds.seconds() * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, s_minimumHoldOffTime.seconds());
    161             dispatch_source_set_event_handler(_timer_event_source, ^{
    162                 if (_timer_event_source) {
    163                     dispatch_source_cancel(_timer_event_source);
    164                     _timer_event_source = 0;
     171            dispatch_source_set_timer(timerEventSource, dispatch_time(DISPATCH_TIME_NOW, seconds.seconds() * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, s_minimumHoldOffTime.seconds());
     172            dispatch_source_set_event_handler(timerEventSource, ^{
     173                if (timerEventSource) {
     174                    dispatch_source_cancel(timerEventSource);
     175                    timerEventSource = nullptr;
    165176                }
    166177                MemoryPressureHandler::singleton().install();
    167178            });
    168             dispatch_resume(_timer_event_source);
     179            dispatch_resume(timerEventSource);
    169180        }
    170181    });
Note: See TracChangeset for help on using the changeset viewer.