Skip to content

Commit 9dc80fd

Browse files
committed
MemoryPressureMonitor: allow selecting the source of the memory measurements
1 parent 8c54004 commit 9dc80fd

7 files changed

Lines changed: 126 additions & 25 deletions

File tree

Source/WebKit/UIProcess/API/APIProcessPoolConfiguration.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ Ref<ProcessPoolConfiguration> ProcessPoolConfiguration::copy()
7878
copy->m_memoryPressureHandlerConfiguration = this->m_memoryPressureHandlerConfiguration;
7979
copy->m_disableFontHintingForTesting = this->m_disableFontHintingForTesting;
8080
copy->m_serviceWorkerMemoryPressureHandlerConfiguration = this->m_serviceWorkerMemoryPressureHandlerConfiguration;
81+
copy->m_memoryPressureMonitorMode = this->m_memoryPressureMonitorMode;
8182
#endif
8283
#if HAVE(AUDIT_TOKEN)
8384
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>
@@ -156,6 +157,9 @@ class ProcessPoolConfiguration final : public ObjectImpl<Object::Type::ProcessPo
156157

157158
void setServiceWorkerMemoryPressureHandlerConfiguration(const MemoryPressureHandler::Configuration& configuration) { m_serviceWorkerMemoryPressureHandlerConfiguration = configuration; }
158159
const std::optional<MemoryPressureHandler::Configuration>& serviceWorkerMemoryPressureHandlerConfiguration() const { return m_serviceWorkerMemoryPressureHandlerConfiguration; }
160+
161+
void setMemoryPressureMonitorMode(WebKit::MemoryPressureMonitor::Mode mode) { m_memoryPressureMonitorMode = mode; }
162+
WebKit::MemoryPressureMonitor::Mode memoryPressureMonitorMode() { return m_memoryPressureMonitorMode; }
159163
#endif
160164

161165
void setTimeZoneOverride(const WTF::String& timeZoneOverride) { m_timeZoneOverride = timeZoneOverride; }
@@ -203,6 +207,7 @@ class ProcessPoolConfiguration final : public ObjectImpl<Object::Type::ProcessPo
203207
std::optional<MemoryPressureHandler::Configuration> m_memoryPressureHandlerConfiguration;
204208
bool m_disableFontHintingForTesting { false };
205209
std::optional<MemoryPressureHandler::Configuration> m_serviceWorkerMemoryPressureHandlerConfiguration;
210+
WebKit::MemoryPressureMonitor::Mode m_memoryPressureMonitorMode { WebKit::MemoryPressureMonitor::Mode::Higher };
206211
#endif
207212
#if HAVE(AUDIT_TOKEN)
208213
std::optional<audit_token_t> m_presentingApplicationProcessToken;

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@
2525
#include "APIProcessPoolConfiguration.h"
2626
#include "APIString.h"
2727
#include "LegacyGlobalSettings.h"
28+
#include "MemoryPressureMonitor.h"
2829
#include "NetworkProcessMessages.h"
2930
#include "TextChecker.h"
3031
#include "TextCheckerState.h"
3132
#include "WebAutomationSession.h"
3233
#include "WebKitAutomationSessionPrivate.h"
3334
#include "WebKitDownloadPrivate.h"
35+
#include "WebKitEnumTypes.h"
3436
#include "WebKitGeolocationManagerPrivate.h"
3537
#include "WebKitInitialize.h"
3638
#include "WebKitInjectedBundleClient.h"
@@ -134,6 +136,7 @@ enum {
134136
PROP_MEMORY_PRESSURE_SETTINGS,
135137
PROP_TIME_ZONE_OVERRIDE,
136138
PROP_SERVICE_WORKER_MEMORY_PRESSURE_SETTINGS,
139+
PROP_MEMORY_PRESSURE_MONITOR_MODE,
137140
N_PROPERTIES,
138141
};
139142

@@ -288,6 +291,7 @@ struct _WebKitWebContextPrivate {
288291

289292
WebKitMemoryPressureSettings* memoryPressureSettings;
290293
WebKitMemoryPressureSettings* serviceWorkerMemoryPressureSettings;
294+
WebKitMemoryPressureMonitorMode memoryPressureMonitorMode;
291295

292296
CString timeZoneOverride;
293297
};
@@ -423,6 +427,9 @@ static void webkitWebContextSetProperty(GObject* object, guint propID, const GVa
423427
context->priv->timeZoneOverride = timeZone;
424428
break;
425429
}
430+
case PROP_MEMORY_PRESSURE_MONITOR_MODE:
431+
context->priv->memoryPressureMonitorMode = static_cast<WebKitMemoryPressureMonitorMode>(g_value_get_enum(value));
432+
break;
426433
default:
427434
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
428435
}
@@ -464,6 +471,20 @@ static void webkitWebContextConstructed(GObject* object)
464471
g_clear_pointer(&priv->serviceWorkerMemoryPressureSettings, webkit_memory_pressure_settings_free);
465472
}
466473

474+
switch(priv->memoryPressureMonitorMode) {
475+
case WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_SYSTEM:
476+
configuration.setMemoryPressureMonitorMode(MemoryPressureMonitor::Mode::System);
477+
break;
478+
case WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_CONTAINER:
479+
configuration.setMemoryPressureMonitorMode(MemoryPressureMonitor::Mode::Container);
480+
break;
481+
case WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_HIGHER:
482+
configuration.setMemoryPressureMonitorMode(MemoryPressureMonitor::Mode::Higher);
483+
break;
484+
default:
485+
g_assert_not_reached();
486+
}
487+
467488
#if !ENABLE(2022_GLIB_API)
468489
if (!priv->websiteDataManager)
469490
priv->websiteDataManager = adoptGRef(webkit_website_data_manager_new("local-storage-directory", priv->localStorageDirectory.data(), nullptr));
@@ -641,6 +662,22 @@ static void webkit_web_context_class_init(WebKitWebContextClass* webContextClass
641662
WEBKIT_TYPE_MEMORY_PRESSURE_SETTINGS,
642663
static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
643664

665+
/**
666+
* WebKitWebContext:memory-pressure-mode:
667+
*
668+
* Which source of measurements will the MemoryPressureMonitor use to calculate the used memory.
669+
*
670+
* Since: 2.38
671+
*/
672+
sObjProperties[PROP_MEMORY_PRESSURE_MONITOR_MODE] =
673+
g_param_spec_enum(
674+
"memory-pressure-monitor-mode",
675+
_("MemoryPressureMonitor mode"),
676+
_("Whether the MemoryPressureMonitor will take measures from the system memory, the container or both"),
677+
WEBKIT_TYPE_MEMORY_PRESSURE_MONITOR_MODE,
678+
WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_HIGHER,
679+
static_cast<GParamFlags>(WEBKIT_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
680+
644681
/**
645682
* WebKitWebContext:time-zone-override:
646683
*

Source/WebKit/UIProcess/API/glib/WebKitWebContext.h.in

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,26 @@ typedef enum {
120120
} WebKitProcessModel;
121121
#endif
122122

123+
/**
124+
* WebKitMemoryPressureMonitorMode:
125+
* @WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_SYSTEM: calculate
126+
* the percentage of used memory based only on system memory polling.
127+
* @WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_CONTAINER: calculate
128+
* the percentage of used memory based on the usage reported by the container.
129+
* @WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_HIGHER: calculate
130+
* the percentage of used memory as the higher of the values reported by the
131+
* the system memory and the container.
132+
*
133+
* Enum values used for determining the MemoryPressureMonitor source of data.
134+
*
135+
* Since: 2.38
136+
*/
137+
typedef enum {
138+
WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_SYSTEM,
139+
WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_CONTAINER,
140+
WEBKIT_MEMORY_PRESSURE_MONITOR_MODE_HIGHER,
141+
} WebKitMemoryPressureMonitorMode;
142+
123143
/**
124144
* WebKitURISchemeRequestCallback:
125145
* @request: the #WebKitURISchemeRequest

Source/WebKit/UIProcess/WebProcessPool.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,10 @@ WebProcessPool::WebProcessPool(API::ProcessPoolConfiguration& configuration)
277277
platformInitialize(needsGlobalStaticInitialization);
278278

279279
#if OS(LINUX)
280-
if (!MemoryPressureMonitor::disabled())
280+
if (!MemoryPressureMonitor::disabled()) {
281+
MemoryPressureMonitor::singleton().setMode(m_configuration->memoryPressureMonitorMode());
281282
MemoryPressureMonitor::singleton().start();
283+
}
282284
#endif
283285

284286
addMessageReceiver(Messages::WebProcessPool::messageReceiverName(), *this);

Source/WebKit/UIProcess/linux/MemoryPressureMonitor.cpp

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

247247

248-
static int systemMemoryUsedAsPercentage(FILE* memInfoFile, FILE* zoneInfoFile, CGroupMemoryController* memoryController)
248+
static int systemMemoryUsedAsPercentage(FILE* memInfoFile, FILE* zoneInfoFile)
249249
{
250250
if (!memInfoFile || fseek(memInfoFile, 0, SEEK_SET))
251251
return -1;
@@ -288,21 +288,29 @@ static int systemMemoryUsedAsPercentage(FILE* memInfoFile, FILE* zoneInfoFile, C
288288
return -1;
289289

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

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

354362
m_started = true;
355363

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

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

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

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

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

Source/WebKit/UIProcess/linux/MemoryPressureMonitor.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,24 @@ class MemoryPressureMonitor {
3737
WTF_MAKE_NONCOPYABLE(MemoryPressureMonitor);
3838
friend NeverDestroyed<MemoryPressureMonitor>;
3939
public:
40+
enum class Mode : uint8_t {
41+
System,
42+
Container,
43+
Higher
44+
};
45+
4046
static MemoryPressureMonitor& singleton();
4147
void start();
4248
static bool disabled();
49+
void setMode(Mode mode) { m_mode = mode; }
4350

4451
~MemoryPressureMonitor();
4552

4653
private:
4754
MemoryPressureMonitor() = default;
4855
bool m_started { false };
4956
static bool s_disabled;
57+
Mode m_mode { Mode::Higher };
5058
};
5159

5260
class CGroupMemoryController {

0 commit comments

Comments
 (0)