--- modules/javafx.web/src/main/native/Source/WTF/wtf/unix/MemoryPressureHandlerUnix.cpp.orig 2020-07-19 18:56:35 UTC +++ modules/javafx.web/src/main/native/Source/WTF/wtf/unix/MemoryPressureHandlerUnix.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2011, 2012 Apple Inc. All Rights Reserved. + * Copyright (C) 2014 Raspberry Pi Foundation. All Rights Reserved. + * Copyright (C) 2018 Igalia S.L. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include + +#include +#include +#include +#include +#include + +#if OS(LINUX) +#include +#elif OS(FREEBSD) +#include +#include +#include +#endif + +#define LOG_CHANNEL_PREFIX Log + +namespace WTF { + +// Disable memory event reception for a minimum of s_minimumHoldOffTime +// seconds after receiving an event. Don't let events fire any sooner than +// s_holdOffMultiplier times the last cleanup processing time. Effectively +// this is 1 / s_holdOffMultiplier percent of the time. +// If after releasing the memory we don't free at least s_minimumBytesFreedToUseMinimumHoldOffTime, +// we wait longer to try again (s_maximumHoldOffTime). +// These value seems reasonable and testing verifies that it throttles frequent +// low memory events, greatly reducing CPU usage. +static const Seconds s_minimumHoldOffTime { 5_s }; +static const Seconds s_maximumHoldOffTime { 30_s }; +static const size_t s_minimumBytesFreedToUseMinimumHoldOffTime = 1 * MB; +static const unsigned s_holdOffMultiplier = 20; + +void MemoryPressureHandler::triggerMemoryPressureEvent(bool isCritical) +{ + if (!m_installed) + return; + + if (ReliefLogger::loggingEnabled()) + LOG(MemoryPressure, "Got memory pressure notification (%s)", isCritical ? "critical" : "non-critical"); + + setUnderMemoryPressure(true); + + if (isMainThread()) + respondToMemoryPressure(isCritical ? Critical::Yes : Critical::No); + else + RunLoop::main().dispatch([this, isCritical] { + respondToMemoryPressure(isCritical ? Critical::Yes : Critical::No); + }); + + if (ReliefLogger::loggingEnabled() && isUnderMemoryPressure()) + LOG(MemoryPressure, "System is no longer under memory pressure."); + + setUnderMemoryPressure(false); +} + +void MemoryPressureHandler::install() +{ + if (m_installed || m_holdOffTimer.isActive()) + return; + + m_installed = true; +} + +void MemoryPressureHandler::uninstall() +{ + if (!m_installed) + return; + + m_holdOffTimer.stop(); + + m_installed = false; +} + +void MemoryPressureHandler::holdOffTimerFired() +{ + install(); +} + +void MemoryPressureHandler::holdOff(Seconds seconds) +{ + m_holdOffTimer.startOneShot(seconds); +} + +static size_t processMemoryUsage() +{ +#if OS(LINUX) + ProcessMemoryStatus memoryStatus; + currentProcessMemoryStatus(memoryStatus); + return (memoryStatus.resident - memoryStatus.shared); +#elif OS(FREEBSD) + static size_t pageSize = sysconf(_SC_PAGE_SIZE); + struct kinfo_proc info; + size_t infolen = sizeof(info); + + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + if (sysctl(mib, 4, &info, &infolen, nullptr, 0)) + return 0; + + return static_cast(info.ki_rssize - info.ki_tsize) * pageSize; +#else +#error "Missing a platform specific way of determining the memory usage" +#endif +} + +void MemoryPressureHandler::respondToMemoryPressure(Critical critical, Synchronous synchronous) +{ + uninstall(); + + MonotonicTime startTime = MonotonicTime::now(); + int64_t processMemory = processMemoryUsage(); + releaseMemory(critical, synchronous); + int64_t bytesFreed = processMemory - processMemoryUsage(); + Seconds holdOffTime = s_maximumHoldOffTime; + if (bytesFreed > 0 && static_cast(bytesFreed) >= s_minimumBytesFreedToUseMinimumHoldOffTime) + holdOffTime = (MonotonicTime::now() - startTime) * s_holdOffMultiplier; + holdOff(std::max(holdOffTime, s_minimumHoldOffTime)); +} + +void MemoryPressureHandler::platformReleaseMemory(Critical) +{ +#if HAVE(MALLOC_TRIM) + malloc_trim(0); +#endif +} + +Optional MemoryPressureHandler::ReliefLogger::platformMemoryUsage() +{ + return MemoryUsage {processMemoryUsage(), memoryFootprint()}; +} + +} // namespace WTF