Unreviewed, rolling out r234489.
[WebKit-https.git] / Source / WTF / wtf / MemoryPressureHandler.cpp
index 7fb88f4..0f4fd09 100644 (file)
 #include "MemoryPressureHandler.h"
 
 #include <wtf/MemoryFootprint.h>
+#include <wtf/NeverDestroyed.h>
+#include <wtf/RAMSize.h>
 
 #define LOG_CHANNEL_PREFIX Log
 
 namespace WTF {
 
 #if RELEASE_LOG_DISABLED
-WTFLogChannel LogMemoryPressure = { WTFLogChannelOn, "MemoryPressure" };
+WTFLogChannel LogMemoryPressure = { WTFLogChannelOn, "MemoryPressure", WTFLogLevelError };
 #else
-WTFLogChannel LogMemoryPressure = { WTFLogChannelOn, "MemoryPressure", LOG_CHANNEL_WEBKIT_SUBSYSTEM, OS_LOG_DEFAULT };
+WTFLogChannel LogMemoryPressure = { WTFLogChannelOn, "MemoryPressure", WTFLogLevelError, LOG_CHANNEL_WEBKIT_SUBSYSTEM, OS_LOG_DEFAULT };
 #endif
 
 WTF_EXPORT_PRIVATE bool MemoryPressureHandler::ReliefLogger::s_loggingEnabled = false;
@@ -57,9 +59,15 @@ MemoryPressureHandler::MemoryPressureHandler()
 
 void MemoryPressureHandler::setShouldUsePeriodicMemoryMonitor(bool use)
 {
+    if (!isFastMallocEnabled()) {
+        // If we're running with FastMalloc disabled, some kind of testing or debugging is probably happening.
+        // Let's be nice and not enable the memory kill mechanism.
+        return;
+    }
+
     if (use) {
         m_measurementTimer = std::make_unique<RunLoop::Timer<MemoryPressureHandler>>(RunLoop::main(), this, &MemoryPressureHandler::measurementTimerFired);
-        m_measurementTimer->startRepeating(30);
+        m_measurementTimer->startRepeating(30_s);
     } else
         m_measurementTimer = nullptr;
 }
@@ -75,25 +83,52 @@ static const char* toString(MemoryUsagePolicy policy)
 }
 #endif
 
-size_t MemoryPressureHandler::thresholdForMemoryKill()
+static size_t thresholdForMemoryKillWithProcessState(WebsamProcessState processState, unsigned tabCount)
 {
+    size_t baseThreshold = 2 * GB;
 #if CPU(X86_64) || CPU(ARM64)
-    if (m_processState == WebsamProcessState::Active)
-        return 4 * GB;
-    return 2 * GB;
+    if (processState == WebsamProcessState::Active)
+        baseThreshold = 4 * GB;
+    if (tabCount > 1)
+        baseThreshold += std::min(tabCount - 1, 4u) * 1 * GB;
 #else
-    return 3 * GB;
+    if ((tabCount > 1) || (processState == WebsamProcessState::Active))
+        baseThreshold = 3 * GB;
 #endif
+    return std::min(baseThreshold, static_cast<size_t>(ramSize() * 0.9));
+}
+
+void MemoryPressureHandler::setPageCount(unsigned pageCount)
+{
+    if (singleton().m_pageCount == pageCount)
+        return;
+    singleton().m_pageCount = pageCount;
+}
+
+size_t MemoryPressureHandler::thresholdForMemoryKill()
+{
+    return thresholdForMemoryKillWithProcessState(m_processState, m_pageCount);
 }
 
 static size_t thresholdForPolicy(MemoryUsagePolicy policy)
 {
+    const size_t baseThresholdForPolicy = std::min(3 * GB, ramSize());
+
+#if PLATFORM(IOS)
+    const double conservativeThresholdFraction = 0.5;
+    const double strictThresholdFraction = 0.65;
+#else
+    const double conservativeThresholdFraction = 0.33;
+    const double strictThresholdFraction = 0.5;
+#endif
+
     switch (policy) {
+    case MemoryUsagePolicy::Unrestricted:
+        return 0;
     case MemoryUsagePolicy::Conservative:
-        return 1 * GB;
+        return baseThresholdForPolicy * conservativeThresholdFraction;
     case MemoryUsagePolicy::Strict:
-        return 1.5 * GB;
-    case MemoryUsagePolicy::Unrestricted:
+        return baseThresholdForPolicy * strictThresholdFraction;
     default:
         ASSERT_NOT_REACHED();
         return 0;
@@ -109,6 +144,11 @@ static MemoryUsagePolicy policyForFootprint(size_t footprint)
     return MemoryUsagePolicy::Unrestricted;
 }
 
+MemoryUsagePolicy MemoryPressureHandler::currentMemoryUsagePolicy()
+{
+    return policyForFootprint(memoryFootprint().value_or(0));
+}
+
 void MemoryPressureHandler::shrinkOrDie()
 {
     RELEASE_LOG(MemoryPressure, "Process is above the memory kill threshold. Trying to shrink down.");
@@ -116,7 +156,7 @@ void MemoryPressureHandler::shrinkOrDie()
 
     auto footprint = memoryFootprint();
     RELEASE_ASSERT(footprint);
-    RELEASE_LOG(MemoryPressure, "New memory footprint: %lu MB", footprint.value() / MB);
+    RELEASE_LOG(MemoryPressure, "New memory footprint: %zu MB", footprint.value() / MB);
 
     if (footprint.value() < thresholdForMemoryKill()) {
         RELEASE_LOG(MemoryPressure, "Shrank below memory kill threshold. Process gets to live.");
@@ -124,6 +164,7 @@ void MemoryPressureHandler::shrinkOrDie()
         return;
     }
 
+    WTFLogAlways("Unable to shrink memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n", footprint.value() / MB, thresholdForMemoryKill() / MB);
     RELEASE_ASSERT(m_memoryKillCallback);
     m_memoryKillCallback();
 }
@@ -145,7 +186,7 @@ void MemoryPressureHandler::measurementTimerFired()
     if (!footprint)
         return;
 
-    RELEASE_LOG(MemoryPressure, "Current memory footprint: %lu MB", footprint.value() / MB);
+    RELEASE_LOG(MemoryPressure, "Current memory footprint: %zu MB", footprint.value() / MB);
     if (footprint.value() >= thresholdForMemoryKill()) {
         shrinkOrDie();
         return;
@@ -163,6 +204,25 @@ void MemoryPressureHandler::measurementTimerFired()
         releaseMemory(Critical::Yes, Synchronous::No);
         break;
     }
+
+    if (processState() == WebsamProcessState::Active && footprint.value() > thresholdForMemoryKillWithProcessState(WebsamProcessState::Inactive, m_pageCount))
+        doesExceedInactiveLimitWhileActive();
+    else
+        doesNotExceedInactiveLimitWhileActive();
+}
+
+void MemoryPressureHandler::doesExceedInactiveLimitWhileActive()
+{
+    if (m_hasInvokedDidExceedInactiveLimitWhileActiveCallback)
+        return;
+    if (m_didExceedInactiveLimitWhileActiveCallback)
+        m_didExceedInactiveLimitWhileActiveCallback();
+    m_hasInvokedDidExceedInactiveLimitWhileActiveCallback = true;
+}
+
+void MemoryPressureHandler::doesNotExceedInactiveLimitWhileActive()
+{
+    m_hasInvokedDidExceedInactiveLimitWhileActiveCallback = false;
 }
 
 void MemoryPressureHandler::setProcessState(WebsamProcessState state)
@@ -170,9 +230,6 @@ void MemoryPressureHandler::setProcessState(WebsamProcessState state)
     if (m_processState == state)
         return;
     m_processState = state;
-    memoryPressureStatusChanged();
-    if (m_processState == WebsamProcessState::Inactive)
-        respondToMemoryPressure(Critical::Yes, Synchronous::No);
 }
 
 void MemoryPressureHandler::beginSimulatedMemoryPressure()
@@ -192,17 +249,6 @@ void MemoryPressureHandler::endSimulatedMemoryPressure()
     memoryPressureStatusChanged();
 }
 
-bool MemoryPressureHandler::isUnderMemoryPressure()
-{
-    auto& memoryPressureHandler = singleton();
-    return memoryPressureHandler.m_underMemoryPressure
-#if PLATFORM(MAC)
-        || memoryPressureHandler.m_memoryUsagePolicy >= MemoryUsagePolicy::Strict
-        || memoryPressureHandler.m_processState == WebsamProcessState::Inactive
-#endif
-        || memoryPressureHandler.m_isSimulatingMemoryPressure;
-}
-
 void MemoryPressureHandler::releaseMemory(Critical critical, Synchronous synchronous)
 {
     if (!m_lowMemoryHandler)
@@ -252,16 +298,15 @@ void MemoryPressureHandler::ReliefLogger::logMemoryUsageChange()
         m_initialMemory->physical, currentMemory->physical, physicalDiff);
 }
 
-#if !PLATFORM(COCOA) && !OS(LINUX) && !PLATFORM(WIN)
+#if !PLATFORM(COCOA) && !OS(LINUX) && !OS(WINDOWS)
 void MemoryPressureHandler::install() { }
 void MemoryPressureHandler::uninstall() { }
-void MemoryPressureHandler::holdOff(unsigned) { }
 void MemoryPressureHandler::respondToMemoryPressure(Critical, Synchronous) { }
 void MemoryPressureHandler::platformReleaseMemory(Critical) { }
 std::optional<MemoryPressureHandler::ReliefLogger::MemoryUsage> MemoryPressureHandler::ReliefLogger::platformMemoryUsage() { return std::nullopt; }
 #endif
 
-#if !PLATFORM(WIN)
+#if !OS(WINDOWS)
 void MemoryPressureHandler::platformInitialize() { }
 #endif