Skip to content

Commit 0e9a5f8

Browse files
magomezpgorszkowski-igalia
authored andcommitted
[MemoryPressure] Add WPE_RAM_SIZE env var to define a custom RAM size
[MemoryPressure] Handle video memory usage besides normal memory Delete JIT code only on synchronous requests: Tune memory pressure settings for rapid mem usage changes When playing an asset with video, frequent seek/jump operations within a short period may cause rapid memory increases. The current pressure settings may not allow (enough) memory release in time to avoid an app running in a container to be killed due it reaching the memory limits. To allow sufficient, in time, memory release, the release needs to happen with the "synchrounous" flag set to true, allowing full garbage collection cycle when reaching critical limits. Furthermore, the critical threshold needs to be lowered as well considering that the release is not instantaneous and on embedded devices the 95% original threshold does not allow enough room for mem release on apps with lower allowed memory usage limits. [1203][MemoryPressureHandler] Increase default fraction values Do critical and synchonous memory release when limit is exceeded and print log message. Signed-off-by: Andrzej Surdej <Andrzej_Surdej@comcast.com> Improve 'MemoryPressureMonitor' to use cgroup memory measurements within container MemoryPressureMonitor: Fix cgroup memory statistics Fix "memory.memsw.usage_in_bytes" file path so it acounts for swap also
1 parent c3b13d6 commit 0e9a5f8

9 files changed

Lines changed: 257 additions & 39 deletions

Source/WTF/wtf/MemoryPressureHandler.cpp

Lines changed: 132 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@
2828

2929
#include <algorithm>
3030
#include <atomic>
31+
#include <fnmatch.h>
3132
#include <functional>
33+
#include <unistd.h>
3234
#include <wtf/Logging.h>
3335
#include <wtf/MemoryFootprint.h>
3436
#include <wtf/NeverDestroyed.h>
3537
#include <wtf/RAMSize.h>
38+
#include <wtf/text/StringToIntegerConversion.h>
3639

3740
namespace WTF {
3841

@@ -42,14 +45,64 @@ WTF_EXPORT_PRIVATE bool MemoryPressureHandler::ReliefLogger::s_loggingEnabled =
4245
static const double s_conservativeThresholdFraction = 0.5;
4346
static const double s_strictThresholdFraction = 0.65;
4447
#else
45-
static const double s_conservativeThresholdFraction = 0.33;
46-
static const double s_strictThresholdFraction = 0.5;
48+
static const double s_conservativeThresholdFraction = 0.8;
49+
static const double s_strictThresholdFraction = 0.9;
4750
#endif
4851
static const std::optional<double> s_killThresholdFraction;
4952
static const Seconds s_pollInterval = 30_s;
5053

5154
static std::atomic<bool> s_hasCreatedMemoryPressureHandler;
5255

56+
// This file contains the amount of video memory used, and will be filled by some other
57+
// platform component. It's a text file containing an unsigned integer value.
58+
static String s_GPUMemoryFile;
59+
static ssize_t s_envBaseThresholdVideo = 0;
60+
61+
static bool isWebProcess()
62+
{
63+
static bool result = false;
64+
static bool initialized = false;
65+
66+
if (!initialized) {
67+
initialized = true;
68+
69+
FILE* file = fopen("/proc/self/cmdline", "r");
70+
if (!file)
71+
return result;
72+
73+
char* buffer = nullptr;
74+
size_t size = 0;
75+
if (getline(&buffer, &size, file) != -1)
76+
result = !fnmatch("*WPEWebProcess*", buffer, 0);
77+
78+
free(buffer);
79+
fclose(file);
80+
}
81+
82+
return result;
83+
}
84+
85+
static size_t memoryFootprintVideo()
86+
{
87+
if (!isWebProcess() || s_GPUMemoryFile.isEmpty())
88+
return 0;
89+
90+
FILE* file = fopen(s_GPUMemoryFile.utf8().data(), "r");
91+
if (!file)
92+
return 0;
93+
94+
char* buffer = nullptr;
95+
size_t size = 0;
96+
size_t footprint = 0;
97+
if (getline(&buffer, &size, file) != -1)
98+
sscanf(buffer, "%lu", &footprint);
99+
100+
free(buffer);
101+
fclose(file);
102+
103+
return footprint;
104+
}
105+
53106
MemoryPressureHandler& MemoryPressureHandler::singleton()
54107
{
55108
static LazyNeverDestroyed<MemoryPressureHandler> memoryPressureHandler;
@@ -76,6 +129,27 @@ MemoryPressureHandler::MemoryPressureHandler()
76129
#if PLATFORM(COCOA)
77130
setDispatchQueue(dispatch_get_main_queue());
78131
#endif
132+
133+
// If this is the WebProcess, Check whether the env var WPE_POLL_MAX_MEMORY_GPU_FILE exists, containing the file
134+
// that we need to poll to get the video memory used, and whether WPE_POLL_MAX_MEMORY_GPU exists, overriding the
135+
// limit for video memory set by the API.
136+
if (isWebProcess()) {
137+
s_GPUMemoryFile = String::fromLatin1(getenv("WPE_POLL_MAX_MEMORY_GPU_FILE"));
138+
String s = String::fromLatin1(getenv("WPE_POLL_MAX_MEMORY_GPU"));
139+
if (!s.isEmpty()) {
140+
String value = s.convertToLowercaseWithoutLocale();
141+
size_t units = 1;
142+
if (value.endsWith('k'))
143+
units = KB;
144+
else if (value.endsWith('m'))
145+
units = MB;
146+
if (units != 1)
147+
value = value.substring(0, value.length() - 1);
148+
s_envBaseThresholdVideo = parseInteger<size_t>(value).value_or(0) * units;
149+
if (s_envBaseThresholdVideo)
150+
m_configuration.baseThresholdVideo = s_envBaseThresholdVideo;
151+
}
152+
}
79153
}
80154

81155
void MemoryPressureHandler::setMemoryFootprintPollIntervalForTesting(Seconds pollInterval)
@@ -139,10 +213,14 @@ void MemoryPressureHandler::setPageCount(unsigned pageCount)
139213
singleton().m_pageCount = pageCount;
140214
}
141215

142-
std::optional<size_t> MemoryPressureHandler::thresholdForMemoryKill()
216+
std::optional<size_t> MemoryPressureHandler::thresholdForMemoryKill(MemoryType type)
143217
{
144218
if (m_configuration.killThresholdFraction)
145-
return m_configuration.baseThreshold * (*m_configuration.killThresholdFraction);
219+
return (*m_configuration.killThresholdFraction) * (type == MemoryType::Normal ? m_configuration.baseThreshold : m_configuration.baseThresholdVideo);
220+
else {
221+
// Don't kill the process if no killThreshold was set.
222+
return std::nullopt;
223+
}
146224

147225
switch (m_processState) {
148226
case WebsamProcessState::Inactive:
@@ -153,26 +231,26 @@ std::optional<size_t> MemoryPressureHandler::thresholdForMemoryKill()
153231
return std::nullopt;
154232
}
155233

156-
size_t MemoryPressureHandler::thresholdForPolicy(MemoryUsagePolicy policy)
234+
size_t MemoryPressureHandler::thresholdForPolicy(MemoryUsagePolicy policy, MemoryType type)
157235
{
158236
switch (policy) {
159237
case MemoryUsagePolicy::Unrestricted:
160238
return 0;
161239
case MemoryUsagePolicy::Conservative:
162-
return m_configuration.baseThreshold * m_configuration.conservativeThresholdFraction;
240+
return m_configuration.conservativeThresholdFraction * (type == MemoryType::Normal ? m_configuration.baseThreshold : m_configuration.baseThresholdVideo);
163241
case MemoryUsagePolicy::Strict:
164-
return m_configuration.baseThreshold * m_configuration.strictThresholdFraction;
242+
return m_configuration.strictThresholdFraction * (type == MemoryType::Normal ? m_configuration.baseThreshold : m_configuration.baseThresholdVideo);
165243
default:
166244
ASSERT_NOT_REACHED();
167245
return 0;
168246
}
169247
}
170248

171-
MemoryUsagePolicy MemoryPressureHandler::policyForFootprint(size_t footprint)
249+
MemoryUsagePolicy MemoryPressureHandler::policyForFootprints(size_t footprint, size_t footprintVideo)
172250
{
173-
if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Strict))
251+
if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Strict, MemoryType::Normal) || footprintVideo >= thresholdForPolicy(MemoryUsagePolicy::Strict, MemoryType::Video))
174252
return MemoryUsagePolicy::Strict;
175-
if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Conservative))
253+
if (footprint >= thresholdForPolicy(MemoryUsagePolicy::Conservative, MemoryType::Normal) || footprintVideo >= thresholdForPolicy(MemoryUsagePolicy::Conservative, MemoryType::Video))
176254
return MemoryUsagePolicy::Conservative;
177255
return MemoryUsagePolicy::Unrestricted;
178256
}
@@ -183,31 +261,35 @@ MemoryUsagePolicy MemoryPressureHandler::currentMemoryUsagePolicy()
183261
return MemoryUsagePolicy::Conservative;
184262
if (m_isSimulatingMemoryPressure)
185263
return MemoryUsagePolicy::Strict;
186-
return policyForFootprint(memoryFootprint());
264+
return policyForFootprints(memoryFootprint(), memoryFootprintVideo());
187265
}
188266

189-
void MemoryPressureHandler::shrinkOrDie(size_t killThreshold)
267+
void MemoryPressureHandler::shrinkOrDie(size_t killThreshold, size_t killThresholdVideo)
190268
{
191269
RELEASE_LOG(MemoryPressure, "Process is above the memory kill threshold. Trying to shrink down.");
192270
releaseMemory(Critical::Yes, Synchronous::Yes);
193271

194272
size_t footprint = memoryFootprint();
273+
size_t footprintVideo = memoryFootprintVideo();
195274
RELEASE_LOG(MemoryPressure, "New memory footprint: %zu MB", footprint / MB);
196275

197-
if (footprint < killThreshold) {
276+
if ((footprint < killThreshold) && (footprintVideo < killThresholdVideo)) {
198277
RELEASE_LOG(MemoryPressure, "Shrank below memory kill threshold. Process gets to live.");
199-
setMemoryUsagePolicyBasedOnFootprint(footprint);
278+
setMemoryUsagePolicyBasedOnFootprints(footprint, footprintVideo);
200279
return;
201280
}
202281

203-
WTFLogAlways("Unable to shrink memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n", footprint / MB, killThreshold / MB);
282+
if (footprint >= killThreshold)
283+
WTFLogAlways("Unable to shrink memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n", footprint / MB, killThreshold / MB);
284+
else
285+
WTFLogAlways("Unable to shrink video memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n", footprintVideo / MB, killThresholdVideo / MB);
204286
RELEASE_ASSERT(m_memoryKillCallback);
205287
m_memoryKillCallback();
206288
}
207289

208-
void MemoryPressureHandler::setMemoryUsagePolicyBasedOnFootprint(size_t footprint)
290+
void MemoryPressureHandler::setMemoryUsagePolicyBasedOnFootprints(size_t footprint, size_t footprintVideo)
209291
{
210-
auto newPolicy = policyForFootprint(footprint);
292+
auto newPolicy = policyForFootprints(footprint, footprintVideo);
211293
if (newPolicy == m_memoryUsagePolicy)
212294
return;
213295

@@ -230,6 +312,7 @@ void MemoryPressureHandler::setMemoryFootprintNotificationThresholds(Vector<size
230312
void MemoryPressureHandler::measurementTimerFired()
231313
{
232314
size_t footprint = memoryFootprint();
315+
size_t footprintVideo = memoryFootprintVideo();
233316
#if PLATFORM(COCOA)
234317
RELEASE_LOG(MemoryPressure, "Current memory footprint: %zu MB", footprint / MB);
235318
#endif
@@ -239,13 +322,14 @@ void MemoryPressureHandler::measurementTimerFired()
239322
m_memoryFootprintNotificationHandler(notificationThreshold);
240323
}
241324

242-
auto killThreshold = thresholdForMemoryKill();
243-
if (killThreshold && footprint >= *killThreshold) {
244-
shrinkOrDie(*killThreshold);
325+
auto killThreshold = thresholdForMemoryKill(MemoryType::Normal);
326+
auto killThresholdVideo = thresholdForMemoryKill(MemoryType::Video);
327+
if ((killThreshold && footprint >= *killThreshold) || (killThresholdVideo && footprintVideo >= *killThresholdVideo)) {
328+
shrinkOrDie(*killThreshold, *killThresholdVideo);
245329
return;
246330
}
247331

248-
setMemoryUsagePolicyBasedOnFootprint(footprint);
332+
setMemoryUsagePolicyBasedOnFootprints(footprint, footprintVideo);
249333

250334
switch (m_memoryUsagePolicy) {
251335
case MemoryUsagePolicy::Unrestricted:
@@ -254,6 +338,13 @@ void MemoryPressureHandler::measurementTimerFired()
254338
releaseMemory(Critical::No, Synchronous::No);
255339
break;
256340
case MemoryUsagePolicy::Strict:
341+
if (footprint > m_configuration.baseThreshold || footprintVideo > m_configuration.baseThresholdVideo) {
342+
WTFLogAlways("MemoryPressure: Critical memory usage (PID=%d) [MB]: %zu (of %zu), video: %zu (of %zu)\n",
343+
getpid(), footprint / MB, m_configuration.baseThreshold / MB,
344+
footprintVideo / MB, m_configuration.baseThresholdVideo / MB);
345+
releaseMemory(Critical::Yes, Synchronous::Yes);
346+
break;
347+
}
257348
releaseMemory(Critical::Yes, Synchronous::No);
258349
break;
259350
}
@@ -313,6 +404,20 @@ void MemoryPressureHandler::endSimulatedMemoryPressure()
313404
memoryPressureStatusChanged();
314405
}
315406

407+
void MemoryPressureHandler::setConfiguration(Configuration&& configuration)
408+
{
409+
m_configuration = WTFMove(configuration);
410+
if (s_envBaseThresholdVideo)
411+
m_configuration.baseThresholdVideo = s_envBaseThresholdVideo;
412+
}
413+
414+
void MemoryPressureHandler::setConfiguration(const Configuration& configuration)
415+
{
416+
m_configuration = configuration;
417+
if (s_envBaseThresholdVideo)
418+
m_configuration.baseThresholdVideo = s_envBaseThresholdVideo;
419+
}
420+
316421
void MemoryPressureHandler::releaseMemory(Critical critical, Synchronous synchronous)
317422
{
318423
if (!m_lowMemoryHandler)
@@ -354,14 +459,15 @@ void MemoryPressureHandler::ReliefLogger::logMemoryUsageChange()
354459

355460
auto currentMemory = platformMemoryUsage();
356461
if (!currentMemory || !m_initialMemory) {
357-
MEMORYPRESSURE_LOG("Memory pressure relief: %" PUBLIC_LOG_STRING ": (Unable to get dirty memory information for process)", m_logString);
462+
MEMORYPRESSURE_LOG("Memory pressure relief: pid = %d, %" PUBLIC_LOG_STRING ": (Unable to get dirty memory information for process)", getpid(), m_logString);
358463
return;
359464
}
360465

361466
long residentDiff = currentMemory->resident - m_initialMemory->resident;
362467
long physicalDiff = currentMemory->physical - m_initialMemory->physical;
363468

364-
MEMORYPRESSURE_LOG("Memory pressure relief: %" PUBLIC_LOG_STRING ": res = %zu/%zu/%ld, res+swap = %zu/%zu/%ld",
469+
MEMORYPRESSURE_LOG("Memory pressure relief: pid = %d, %" PUBLIC_LOG_STRING ": res = %zu/%zu/%ld, res+swap = %zu/%zu/%ld",
470+
getpid(),
365471
m_logString,
366472
m_initialMemory->resident, currentMemory->resident, residentDiff,
367473
m_initialMemory->physical, currentMemory->physical, physicalDiff);
@@ -373,15 +479,17 @@ void MemoryPressureHandler::platformInitialize() { }
373479

374480
MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration()
375481
: baseThreshold(std::min(3 * GB, ramSize()))
482+
, baseThresholdVideo(1 * GB)
376483
, conservativeThresholdFraction(s_conservativeThresholdFraction)
377484
, strictThresholdFraction(s_strictThresholdFraction)
378485
, killThresholdFraction(s_killThresholdFraction)
379486
, pollInterval(s_pollInterval)
380487
{
381488
}
382489

383-
MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration(size_t base, double conservative, double strict, std::optional<double> kill, Seconds interval)
490+
MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration(size_t base, size_t baseVideo, double conservative, double strict, std::optional<double> kill, Seconds interval)
384491
: baseThreshold(base)
492+
, baseThresholdVideo(baseVideo)
385493
, conservativeThresholdFraction(conservative)
386494
, strictThresholdFraction(strict)
387495
, killThresholdFraction(kill)

Source/WTF/wtf/MemoryPressureHandler.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ enum class MemoryUsagePolicy : uint8_t {
6060
Strict, // Time to start pinching pennies for real
6161
};
6262

63+
enum class MemoryType : uint8_t {
64+
Normal,
65+
Video
66+
};
67+
6368
enum class WebsamProcessState : uint8_t {
6469
Active,
6570
Inactive,
@@ -73,9 +78,10 @@ typedef WTF::Function<void(Critical, Synchronous)> LowMemoryHandler;
7378
struct MemoryPressureHandlerConfiguration {
7479
WTF_MAKE_STRUCT_FAST_ALLOCATED;
7580
WTF_EXPORT_PRIVATE MemoryPressureHandlerConfiguration();
76-
WTF_EXPORT_PRIVATE MemoryPressureHandlerConfiguration(size_t, double, double, std::optional<double>, Seconds);
81+
WTF_EXPORT_PRIVATE MemoryPressureHandlerConfiguration(size_t, size_t, double, double, std::optional<double>, Seconds);
7782

7883
size_t baseThreshold;
84+
size_t baseThresholdVideo;
7985
double conservativeThresholdFraction;
8086
double strictThresholdFraction;
8187
std::optional<double> killThresholdFraction;
@@ -187,9 +193,8 @@ class MemoryPressureHandler {
187193
};
188194

189195
using Configuration = MemoryPressureHandlerConfiguration;
190-
191-
void setConfiguration(Configuration&& configuration) { m_configuration = WTFMove(configuration); }
192-
void setConfiguration(const Configuration& configuration) { m_configuration = configuration; }
196+
void setConfiguration(Configuration&&);
197+
void setConfiguration(const Configuration&);
193198

194199
WTF_EXPORT_PRIVATE void releaseMemory(Critical, Synchronous = Synchronous::No);
195200

@@ -212,9 +217,9 @@ class MemoryPressureHandler {
212217
WTF_EXPORT_PRIVATE void setMemoryFootprintNotificationThresholds(Vector<size_t>&& thresholds, WTF::Function<void(size_t)>&&);
213218

214219
private:
215-
std::optional<size_t> thresholdForMemoryKill();
216-
size_t thresholdForPolicy(MemoryUsagePolicy);
217-
MemoryUsagePolicy policyForFootprint(size_t);
220+
std::optional<size_t> thresholdForMemoryKill(MemoryType);
221+
size_t thresholdForPolicy(MemoryUsagePolicy, MemoryType);
222+
MemoryUsagePolicy policyForFootprints(size_t, size_t);
218223

219224
void memoryPressureStatusChanged();
220225

@@ -231,8 +236,8 @@ class MemoryPressureHandler {
231236
void platformInitialize();
232237

233238
void measurementTimerFired();
234-
void shrinkOrDie(size_t killThreshold);
235-
void setMemoryUsagePolicyBasedOnFootprint(size_t);
239+
void shrinkOrDie(size_t killThreshold, size_t killThresholdVideo);
240+
void setMemoryUsagePolicyBasedOnFootprints(size_t, size_t);
236241

237242
unsigned m_pageCount { 0 };
238243

0 commit comments

Comments
 (0)