Skip to content

Commit fa5a363

Browse files
committed
MemoryPressureMonitor: allow selecting the source of the memory measurements
1 parent 2419a7e commit fa5a363

7 files changed

Lines changed: 125 additions & 24 deletions

File tree

Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Ref<ProcessPoolConfiguration> ProcessPoolConfiguration::copy()
8080
#if PLATFORM(GTK) || PLATFORM(WPE)
8181
copy->m_memoryPressureHandlerConfiguration = this->m_memoryPressureHandlerConfiguration;
8282
copy->m_serviceWorkerMemoryPressureHandlerConfiguration = this->m_serviceWorkerMemoryPressureHandlerConfiguration;
83+
copy->m_memoryPressureMonitorMode = this->m_memoryPressureMonitorMode;
8384
#endif
8485
#if HAVE(AUDIT_TOKEN)
8586
copy->m_presentingApplicationProcessToken = this->m_presentingApplicationProcessToken;

Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
#include "APIObject.h"
2929
#include "CacheModel.h"
30+
#include "MemoryPressureMonitor.h"
3031
#include "WebsiteDataStore.h"
3132
#include <wtf/MemoryPressureHandler.h>
3233
#include <wtf/ProcessID.h>
@@ -162,6 +163,9 @@ class ProcessPoolConfiguration final : public ObjectImpl<Object::Type::ProcessPo
162163

163164
void setServiceWorkerMemoryPressureHandlerConfiguration(const MemoryPressureHandler::Configuration& configuration) { m_serviceWorkerMemoryPressureHandlerConfiguration = configuration; }
164165
const std::optional<MemoryPressureHandler::Configuration>& serviceWorkerMemoryPressureHandlerConfiguration() const { return m_serviceWorkerMemoryPressureHandlerConfiguration; }
166+
167+
void setMemoryPressureMonitorMode(WebKit::MemoryPressureMonitor::Mode mode) { m_memoryPressureMonitorMode = mode; }
168+
WebKit::MemoryPressureMonitor::Mode memoryPressureMonitorMode() { return m_memoryPressureMonitorMode; }
165169
#endif
166170

167171
void setTimeZoneOverride(const WTF::String& timeZoneOverride) { m_timeZoneOverride = timeZoneOverride; }
@@ -205,6 +209,7 @@ class ProcessPoolConfiguration final : public ObjectImpl<Object::Type::ProcessPo
205209
#if PLATFORM(GTK) || PLATFORM(WPE)
206210
std::optional<MemoryPressureHandler::Configuration> m_memoryPressureHandlerConfiguration;
207211
std::optional<MemoryPressureHandler::Configuration> m_serviceWorkerMemoryPressureHandlerConfiguration;
212+
WebKit::MemoryPressureMonitor::Mode m_memoryPressureMonitorMode { WebKit::MemoryPressureMonitor::Mode::Higher };
208213
#endif
209214
#if HAVE(AUDIT_TOKEN)
210215
std::optional<audit_token_t> m_presentingApplicationProcessToken;

Source/WebKit/UIProcess/API/glib/WebKitWebContext.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "APIProcessPoolConfiguration.h"
2828
#include "APIString.h"
2929
#include "LegacyGlobalSettings.h"
30+
#include "MemoryPressureMonitor.h"
3031
#include "NetworkProcessMessages.h"
3132
#include "TextChecker.h"
3233
#include "TextCheckerState.h"
@@ -35,6 +36,7 @@
3536
#include "WebKitAutomationSessionPrivate.h"
3637
#include "WebKitDownloadClient.h"
3738
#include "WebKitDownloadPrivate.h"
39+
#include "WebKitEnumTypes.h"
3840
#include "WebKitFaviconDatabasePrivate.h"
3941
#include "WebKitGeolocationManagerPrivate.h"
4042
#include "WebKitInitialize.h"
@@ -131,6 +133,7 @@ enum {
131133
PROP_MEMORY_PRESSURE_SETTINGS,
132134
PROP_TIME_ZONE_OVERRIDE,
133135
PROP_SERVICE_WORKER_MEMORY_PRESSURE_SETTINGS,
136+
PROP_MEMORY_PRESSURE_MONITOR_MODE,
134137
N_PROPERTIES,
135138
};
136139

@@ -250,6 +253,7 @@ struct _WebKitWebContextPrivate {
250253

251254
WebKitMemoryPressureSettings* memoryPressureSettings;
252255
WebKitMemoryPressureSettings* serviceWorkerMemoryPressureSettings;
256+
WebKitMemoryPressureMonitorMode memoryPressureMonitorMode;
253257

254258
CString timeZoneOverride;
255259
};
@@ -406,6 +410,9 @@ static void webkitWebContextSetProperty(GObject* object, guint propID, const GVa
406410
context->priv->timeZoneOverride = timeZone;
407411
break;
408412
}
413+
case PROP_MEMORY_PRESSURE_MONITOR_MODE:
414+
context->priv->memoryPressureMonitorMode = static_cast<WebKitMemoryPressureMonitorMode>(g_value_get_enum(value));
415+
break;
409416
default:
410417
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
411418
}
@@ -442,6 +449,21 @@ static void webkitWebContextConstructed(GObject* object)
442449
// Once the settings have been passed to the ProcessPoolConfiguration, we don't need them anymore so we can free them.
443450
g_clear_pointer(&priv->serviceWorkerMemoryPressureSettings, webkit_memory_pressure_settings_free);
444451
}
452+
453+
switch(priv->memoryPressureMonitorMode) {
454+
case WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_SYSTEM:
455+
configuration.setMemoryPressureMonitorMode(MemoryPressureMonitor::Mode::System);
456+
break;
457+
case WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_CONTAINER:
458+
configuration.setMemoryPressureMonitorMode(MemoryPressureMonitor::Mode::Container);
459+
break;
460+
case WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_HIGHER:
461+
configuration.setMemoryPressureMonitorMode(MemoryPressureMonitor::Mode::Higher);
462+
break;
463+
default:
464+
g_assert_not_reached();
465+
}
466+
445467
configuration.setTimeZoneOverride(String::fromUTF8(priv->timeZoneOverride.data(), priv->timeZoneOverride.length()));
446468

447469
if (!priv->websiteDataManager)
@@ -620,6 +642,22 @@ static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass
620642
WEBKIT_TYPE_MEMORY_PRESSURE_SETTINGS,
621643
static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
622644

645+
/**
646+
* WebKitWebContext:memory-pressure-mode:
647+
*
648+
* Which source of measurements will the MemoryPressureMonitor use to calculate the used memory.
649+
*
650+
* Since: 2.38
651+
*/
652+
sObjProperties[PROP_MEMORY_PRESSURE_MONITOR_MODE] =
653+
g_param_spec_enum(
654+
"memory-pressure-monitor-mode",
655+
_("MemoryPressureMonitor mode"),
656+
_("Whether the MemoryPressureMonitor will take measures from the system memory, the container or both"),
657+
WEBKIT_TYPE_MEMORY_PRESSURE_MONITOR_MODE,
658+
WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_HIGHER,
659+
static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
660+
623661
/**
624662
* WebKitWebContext:time-zone-override:
625663
*

Source/WebKit/UIProcess/API/wpe/WebKitWebContext.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,26 @@ typedef enum {
8888
WEBKIT_PROCESS_MODEL_MULTIPLE_SECONDARY_PROCESSES,
8989
} WebKitProcessModel;
9090

91+
/**
92+
* WebKitMemoryPressureMonitorMode:
93+
* @WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_SYSTEM: calculate
94+
* the percentage of used memory based only on system memory polling.
95+
* @WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_CONTAINER: calculate
96+
* the percentage of used memory based on the usage reported by the container.
97+
* @WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_HIGHER: calculate
98+
* the percentage of used memory as the higher of the values reported by the
99+
* the system memory and the container.
100+
*
101+
* Enum values used for determining the MemoryPressureMonitor source of data.
102+
*
103+
* Since: 2.38
104+
*/
105+
typedef enum {
106+
WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_SYSTEM,
107+
WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_CONTAINER,
108+
WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_HIGHER,
109+
} WebKitMemoryPressureMonitorMode;
110+
91111
/**
92112
* WebKitURISchemeRequestCallback:
93113
* @request: the #WebKitURISchemeRequest

Source/WebKit/UIProcess/WebProcessPool.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ WebProcessPool::WebProcessPool(API::ProcessPoolConfiguration& configuration)
240240
platformInitialize();
241241

242242
#if OS(LINUX)
243+
MemoryPressureMonitor::singleton().setMode(m_configuration->memoryPressureMonitorMode());
243244
MemoryPressureMonitor::singleton().start();
244245
#endif
245246

Source/WebKit/UIProcess/linux/MemoryPressureMonitor.cpp

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ static CString getCgroupControllerPath(FILE* cgroupControllerFile, const char* c
244244
}
245245

246246

247-
static int systemMemoryUsedAsPercentage(FILE* memInfoFile, FILE* zoneInfoFile, CGroupMemoryController* memoryController)
247+
static int systemMemoryUsedAsPercentage(FILE* memInfoFile, FILE* zoneInfoFile)
248248
{
249249
if (!memInfoFile || fseek(memInfoFile, 0, SEEK_SET))
250250
return -1;
@@ -287,21 +287,29 @@ static int systemMemoryUsedAsPercentage(FILE* memInfoFile, FILE* zoneInfoFile, C
287287
return -1;
288288

289289
int memoryUsagePercentage = ((memoryTotal - memoryAvailable) * 100) / memoryTotal;
290-
LOG_VERBOSE(MemoryPressure, "MemoryPressureMonitor::memory: real (memory total=%zu MB) (memory available=%zu MB) (memory usage percentage=%d MB)", memoryTotal, memoryAvailable, memoryUsagePercentage);
291-
if (memoryController->isActive()) {
292-
memoryTotal = memoryController->getMemoryTotalWithCgroup();
293-
size_t memoryUsage = memoryController->getMemoryUsageWithCgroup();
294-
if (memoryTotal != notSet && memoryUsage != notSet) {
295-
int memoryUsagePercentageWithCgroup = 100 * ((float) memoryUsage / (float) memoryTotal);
296-
LOG_VERBOSE(MemoryPressure, "MemoryPressureMonitor::memory: cgroup (memory total=%zu bytes) (memory usage=%zu bytes) (memory usage percentage=%d bytes)", memoryTotal, memoryUsage, memoryUsagePercentageWithCgroup);
297-
if (memoryUsagePercentageWithCgroup > memoryUsagePercentage)
298-
memoryUsagePercentage = memoryUsagePercentageWithCgroup;
299-
}
300-
}
301-
LOG_VERBOSE(MemoryPressure, "MemoryPressureMonitor::memory: memoryUsagePercentage (%d)", memoryUsagePercentage);
290+
LOG_VERBOSE(MemoryPressure, "MemoryPressureMonitor: memory real (memory total=%zu MB) (memory available=%zu MB) (memory usage percentage=%d MB)", memoryTotal, memoryAvailable, memoryUsagePercentage);
291+
302292
return memoryUsagePercentage;
303293
}
304294

295+
static int containerMemoryUsedAsPercentage(CGroupMemoryController* memoryController)
296+
{
297+
if (!memoryController->isActive())
298+
return -1;
299+
300+
size_t memoryTotal = memoryController->getMemoryTotalWithCgroup();
301+
size_t memoryUsage = memoryController->getMemoryUsageWithCgroup();
302+
303+
if (memoryTotal == notSet || memoryUsage == notSet)
304+
return -1;
305+
306+
int memoryUsagePercentageWithCgroup = 100 * ((float) memoryUsage / (float) memoryTotal);
307+
LOG_VERBOSE(MemoryPressure, "MemoryPressureMonitor: memory cgroup (memory total=%zu bytes) (memory usage=%zu bytes) (memory usage percentage=%d bytes)", memoryTotal, memoryUsage, memoryUsagePercentageWithCgroup);
308+
309+
return memoryUsagePercentageWithCgroup;
310+
}
311+
312+
305313
static inline Seconds pollIntervalForUsedMemoryPercentage(int usedPercentage)
306314
{
307315
// Use a different poll interval depending on the currently memory used,
@@ -352,30 +360,50 @@ void MemoryPressureMonitor::start()
352360

353361
m_started = true;
354362

355-
Thread::create("MemoryPressureMonitor", [] {
363+
Thread::create("MemoryPressureMonitor", [mode = m_mode] {
356364
FileHandle memInfoFile, zoneInfoFile, cgroupControllerFile;
357365
CGroupMemoryController memoryController = CGroupMemoryController();
358366
Seconds pollInterval = s_maxPollingInterval;
359367
while (true) {
360368
sleep(pollInterval);
361369

362-
// Cannot operate without this one, retry opening on the next iteration after sleeping.
363-
if (!tryOpeningForUnbufferedReading(memInfoFile, s_procMeminfo))
364-
continue;
370+
int usedPercentage = -1;
371+
if (mode == Mode::Container || mode == Mode::Higher) {
372+
tryOpeningForUnbufferedReading(cgroupControllerFile, s_procSelfCgroup);
373+
374+
CString cgroupMemoryControllerPath = getCgroupControllerPath(cgroupControllerFile.get(), "memory");
375+
memoryController.setMemoryControllerPath(cgroupMemoryControllerPath);
376+
377+
usedPercentage = containerMemoryUsedAsPercentage(&memoryController);
378+
379+
// Warn only if we weren't able to get the data and we're in container mode, where it's
380+
// expected to work.
381+
if (usedPercentage == -1 && mode == Mode::Container)
382+
WTFLogAlways("MemoryPressureMonitor: failed to get the memory usage using cgroup");
383+
}
365384

366-
// The monitor can work without these two, but it will be more precise if thy are eventually opened: keep trying.
367-
tryOpeningForUnbufferedReading(zoneInfoFile, s_procZoneinfo);
368-
tryOpeningForUnbufferedReading(cgroupControllerFile, s_procSelfCgroup);
385+
if (mode == Mode::System || mode == Mode::Higher) {
386+
// Cannot operate without this one, retry opening on the next iteration after sleeping.
387+
if (!tryOpeningForUnbufferedReading(memInfoFile, s_procMeminfo))
388+
continue;
389+
390+
tryOpeningForUnbufferedReading(zoneInfoFile, s_procZoneinfo);
391+
392+
int systemUsedPercentage = systemMemoryUsedAsPercentage(memInfoFile.get(), zoneInfoFile.get());
393+
394+
if (systemUsedPercentage == -1)
395+
WTFLogAlways("MemoryPressureMonitor: failed to get the memory usage using real memory");
396+
397+
usedPercentage = std::max(usedPercentage, systemUsedPercentage);
398+
}
369399

370-
CString cgroupMemoryControllerPath = getCgroupControllerPath(cgroupControllerFile.get(), "memory");
371-
memoryController.setMemoryControllerPath(cgroupMemoryControllerPath);
372-
int usedPercentage = systemMemoryUsedAsPercentage(memInfoFile.get(), zoneInfoFile.get(), &memoryController);
373400
if (usedPercentage == -1) {
374-
WTFLogAlways("Failed to get the memory usage");
401+
WTFLogAlways("MemoryPressureMonitor: failed to get the memory usage using any method");
375402
pollInterval = s_maxPollingInterval;
376403
continue;
377404
}
378405

406+
LOG_VERBOSE(MemoryPressure, "MemoryPressureMonitor: memoryUsagePercentage (%d)", usedPercentage);
379407
if (usedPercentage >= s_memoryPresurePercentageThreshold) {
380408
bool isCritical = (usedPercentage >= s_memoryPresurePercentageThresholdCritical);
381409
RunLoop::main().dispatch([isCritical] {

Source/WebKit/UIProcess/linux/MemoryPressureMonitor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,24 @@ class MemoryPressureMonitor {
4141
WTF_MAKE_NONCOPYABLE(MemoryPressureMonitor);
4242
friend NeverDestroyed<MemoryPressureMonitor>;
4343
public:
44+
enum class Mode : uint8_t {
45+
System,
46+
Container,
47+
Higher
48+
};
49+
4450
static MemoryPressureMonitor& singleton();
4551
void start();
4652
static bool disabled();
53+
void setMode(Mode mode) { m_mode = mode; }
4754

4855
~MemoryPressureMonitor();
4956

5057
private:
5158
MemoryPressureMonitor() = default;
5259
bool m_started { false };
5360
static bool s_disabled;
61+
Mode m_mode { Mode::Higher };
5462
};
5563

5664
class CGroupMemoryController {

0 commit comments

Comments
 (0)