2828
2929#include < algorithm>
3030#include < atomic>
31+ #include < fnmatch.h>
3132#include < functional>
3233#include < ranges>
34+ #include < unistd.h>
3335#include < wtf/Logging.h>
3436#include < wtf/MemoryFootprint.h>
3537#include < wtf/NeverDestroyed.h>
3638#include < wtf/RAMSize.h>
39+ #include < wtf/text/StringToIntegerConversion.h>
3740
3841namespace WTF {
3942
@@ -51,6 +54,56 @@ static const Seconds s_pollInterval = 30_s;
5154
5255static std::atomic<bool > s_hasCreatedMemoryPressureHandler;
5356
57+ // This file contains the amount of video memory used, and will be filled by some other
58+ // platform component. It's a text file containing an unsigned integer value.
59+ static String s_GPUMemoryFile;
60+ static ssize_t s_envBaseThresholdVideo = 0 ;
61+
62+ static bool isWebProcess ()
63+ {
64+ static bool result = false ;
65+ static bool initialized = false ;
66+
67+ if (!initialized) {
68+ initialized = true ;
69+
70+ FILE* file = fopen (" /proc/self/cmdline" , " r" );
71+ if (!file)
72+ return result;
73+
74+ char * buffer = nullptr ;
75+ size_t size = 0 ;
76+ if (getline (&buffer, &size, file) != -1 )
77+ result = !fnmatch (" *WPEWebProcess*" , buffer, 0 );
78+
79+ free (buffer);
80+ fclose (file);
81+ }
82+
83+ return result;
84+ }
85+
86+ static size_t memoryFootprintVideo ()
87+ {
88+ if (!isWebProcess () || s_GPUMemoryFile.isEmpty ())
89+ return 0 ;
90+
91+ FILE* file = fopen (s_GPUMemoryFile.utf8 ().data (), " r" );
92+ if (!file)
93+ return 0 ;
94+
95+ char * buffer = nullptr ;
96+ size_t size = 0 ;
97+ size_t footprint = 0 ;
98+ if (getline (&buffer, &size, file) != -1 )
99+ sscanf (buffer, " %u" , &footprint);
100+
101+ free (buffer);
102+ fclose (file);
103+
104+ return footprint;
105+ }
106+
54107MemoryPressureHandler& MemoryPressureHandler::singleton ()
55108{
56109 static LazyNeverDestroyed<MemoryPressureHandler> memoryPressureHandler;
@@ -77,6 +130,27 @@ MemoryPressureHandler::MemoryPressureHandler()
77130#if PLATFORM(COCOA)
78131 setDispatchQueue (dispatch_get_main_queue ());
79132#endif
133+
134+ // If this is the WebProcess, Check whether the env var WPE_POLL_MAX_MEMORY_GPU_FILE exists, containing the file
135+ // that we need to poll to get the video memory used, and whether WPE_POLL_MAX_MEMORY_GPU exists, overriding the
136+ // limit for video memory set by the API.
137+ if (isWebProcess ()) {
138+ s_GPUMemoryFile = String::fromLatin1 (getenv (" WPE_POLL_MAX_MEMORY_GPU_FILE" ));
139+ String s = String::fromLatin1 (getenv (" WPE_POLL_MAX_MEMORY_GPU" ));
140+ if (!s.isEmpty ()) {
141+ String value = s.convertToLowercaseWithoutLocale ();
142+ size_t units = 1 ;
143+ if (value.endsWith (' k' ))
144+ units = KB;
145+ else if (value.endsWith (' m' ))
146+ units = MB;
147+ if (units != 1 )
148+ value = value.substring (0 , value.length () - 1 );
149+ s_envBaseThresholdVideo = parseInteger<size_t >(value).value_or (0 ) * units;
150+ if (s_envBaseThresholdVideo)
151+ m_configuration.baseThresholdVideo = s_envBaseThresholdVideo;
152+ }
153+ }
80154}
81155
82156void MemoryPressureHandler::setMemoryFootprintPollIntervalForTesting (Seconds pollInterval)
@@ -134,10 +208,14 @@ void MemoryPressureHandler::setPageCount(unsigned pageCount)
134208 singleton ().m_pageCount = pageCount;
135209}
136210
137- std::optional<size_t > MemoryPressureHandler::thresholdForMemoryKill ()
211+ std::optional<size_t > MemoryPressureHandler::thresholdForMemoryKill (MemoryType type )
138212{
139213 if (m_configuration.killThresholdFraction )
140- return m_configuration.baseThreshold * (*m_configuration.killThresholdFraction );
214+ return (*m_configuration.killThresholdFraction ) * (type == MemoryType::Normal ? m_configuration.baseThreshold : m_configuration.baseThresholdVideo );
215+ else {
216+ // Don't kill the process if no killThreshold was set.
217+ return std::nullopt ;
218+ }
141219
142220 switch (m_processState) {
143221 case WebsamProcessState::Inactive:
@@ -148,26 +226,26 @@ std::optional<size_t> MemoryPressureHandler::thresholdForMemoryKill()
148226 return std::nullopt ;
149227}
150228
151- size_t MemoryPressureHandler::thresholdForPolicy (MemoryUsagePolicy policy)
229+ size_t MemoryPressureHandler::thresholdForPolicy (MemoryUsagePolicy policy, MemoryType type )
152230{
153231 switch (policy) {
154232 case MemoryUsagePolicy::Unrestricted:
155233 return 0 ;
156234 case MemoryUsagePolicy::Conservative:
157- return m_configuration.baseThreshold * m_configuration.conservativeThresholdFraction ;
235+ return m_configuration.conservativeThresholdFraction * (type == MemoryType::Normal ? m_configuration.baseThreshold : m_configuration. baseThresholdVideo ) ;
158236 case MemoryUsagePolicy::Strict:
159- return m_configuration.baseThreshold * m_configuration.strictThresholdFraction ;
237+ return m_configuration.strictThresholdFraction * (type == MemoryType::Normal ? m_configuration.baseThreshold : m_configuration. baseThresholdVideo ) ;
160238 default :
161239 ASSERT_NOT_REACHED ();
162240 return 0 ;
163241 }
164242}
165243
166- MemoryUsagePolicy MemoryPressureHandler::policyForFootprint (size_t footprint)
244+ MemoryUsagePolicy MemoryPressureHandler::policyForFootprints (size_t footprint, size_t footprintVideo )
167245{
168- if (footprint >= thresholdForPolicy (MemoryUsagePolicy::Strict))
246+ if (footprint >= thresholdForPolicy (MemoryUsagePolicy::Strict, MemoryType::Normal) || footprintVideo >= thresholdForPolicy (MemoryUsagePolicy::Strict, MemoryType::Video ))
169247 return MemoryUsagePolicy::Strict;
170- if (footprint >= thresholdForPolicy (MemoryUsagePolicy::Conservative))
248+ if (footprint >= thresholdForPolicy (MemoryUsagePolicy::Conservative, MemoryType::Normal) || footprintVideo >= thresholdForPolicy (MemoryUsagePolicy::Conservative, MemoryType::Video ))
171249 return MemoryUsagePolicy::Conservative;
172250 return MemoryUsagePolicy::Unrestricted;
173251}
@@ -178,31 +256,35 @@ MemoryUsagePolicy MemoryPressureHandler::currentMemoryUsagePolicy()
178256 return MemoryUsagePolicy::Conservative;
179257 if (m_isSimulatingMemoryPressure)
180258 return MemoryUsagePolicy::Strict;
181- return policyForFootprint (memoryFootprint ());
259+ return policyForFootprints (memoryFootprint (), memoryFootprintVideo ());
182260}
183261
184- void MemoryPressureHandler::shrinkOrDie (size_t killThreshold)
262+ void MemoryPressureHandler::shrinkOrDie (size_t killThreshold, size_t killThresholdVideo )
185263{
186264 RELEASE_LOG (MemoryPressure, " Process is above the memory kill threshold. Trying to shrink down." );
187265 releaseMemory (Critical::Yes, Synchronous::Yes);
188266
189267 size_t footprint = memoryFootprint ();
268+ size_t footprintVideo = memoryFootprintVideo ();
190269 RELEASE_LOG (MemoryPressure, " New memory footprint: %zu MB" , footprint / MB);
191270
192- if (footprint < killThreshold) {
271+ if (( footprint < killThreshold) && (footprintVideo < killThresholdVideo) ) {
193272 RELEASE_LOG (MemoryPressure, " Shrank below memory kill threshold. Process gets to live." );
194- setMemoryUsagePolicyBasedOnFootprint (footprint);
273+ setMemoryUsagePolicyBasedOnFootprints (footprint, footprintVideo );
195274 return ;
196275 }
197276
198- WTFLogAlways (" Unable to shrink memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n " , footprint / MB, killThreshold / MB);
277+ if (footprint >= killThreshold)
278+ WTFLogAlways (" Unable to shrink memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n " , footprint / MB, killThreshold / MB);
279+ else
280+ WTFLogAlways (" Unable to shrink video memory footprint of process (%zu MB) below the kill thresold (%zu MB). Killed\n " , footprintVideo / MB, killThresholdVideo / MB);
199281 RELEASE_ASSERT (m_memoryKillCallback);
200282 m_memoryKillCallback ();
201283}
202284
203- void MemoryPressureHandler::setMemoryUsagePolicyBasedOnFootprint (size_t footprint)
285+ void MemoryPressureHandler::setMemoryUsagePolicyBasedOnFootprints (size_t footprint, size_t footprintVideo )
204286{
205- auto newPolicy = policyForFootprint (footprint);
287+ auto newPolicy = policyForFootprints (footprint, footprintVideo );
206288 if (newPolicy == m_memoryUsagePolicy)
207289 return ;
208290
@@ -225,6 +307,7 @@ void MemoryPressureHandler::setMemoryFootprintNotificationThresholds(Vector<size
225307void MemoryPressureHandler::measurementTimerFired ()
226308{
227309 size_t footprint = memoryFootprint ();
310+ size_t footprintVideo = memoryFootprintVideo ();
228311#if PLATFORM(COCOA)
229312 RELEASE_LOG (MemoryPressure, " Current memory footprint: %zu MB" , footprint / MB);
230313#endif
@@ -234,13 +317,14 @@ void MemoryPressureHandler::measurementTimerFired()
234317 m_memoryFootprintNotificationHandler (notificationThreshold);
235318 }
236319
237- auto killThreshold = thresholdForMemoryKill ();
238- if (killThreshold && footprint >= *killThreshold) {
239- shrinkOrDie (*killThreshold);
320+ auto killThreshold = thresholdForMemoryKill (MemoryType::Normal);
321+ auto killThresholdVideo = thresholdForMemoryKill (MemoryType::Video);
322+ if ((killThreshold && footprint >= *killThreshold) || (killThresholdVideo && footprintVideo >= *killThresholdVideo)) {
323+ shrinkOrDie (*killThreshold, *killThresholdVideo);
240324 return ;
241325 }
242326
243- setMemoryUsagePolicyBasedOnFootprint (footprint);
327+ setMemoryUsagePolicyBasedOnFootprints (footprint, footprintVideo );
244328
245329 switch (m_memoryUsagePolicy) {
246330 case MemoryUsagePolicy::Unrestricted:
@@ -308,6 +392,20 @@ void MemoryPressureHandler::endSimulatedMemoryPressure()
308392 memoryPressureStatusChanged ();
309393}
310394
395+ void MemoryPressureHandler::setConfiguration (Configuration&& configuration)
396+ {
397+ m_configuration = WTFMove (configuration);
398+ if (s_envBaseThresholdVideo)
399+ m_configuration.baseThresholdVideo = s_envBaseThresholdVideo;
400+ }
401+
402+ void MemoryPressureHandler::setConfiguration (const Configuration& configuration)
403+ {
404+ m_configuration = configuration;
405+ if (s_envBaseThresholdVideo)
406+ m_configuration.baseThresholdVideo = s_envBaseThresholdVideo;
407+ }
408+
311409void MemoryPressureHandler::releaseMemory (Critical critical, Synchronous synchronous)
312410{
313411 if (!m_lowMemoryHandler)
@@ -349,14 +447,15 @@ void MemoryPressureHandler::ReliefLogger::logMemoryUsageChange()
349447
350448 auto currentMemory = platformMemoryUsage ();
351449 if (!currentMemory || !m_initialMemory) {
352- MEMORYPRESSURE_LOG (" Memory pressure relief: % " PUBLIC_LOG_STRING " : (Unable to get dirty memory information for process)" , m_logString);
450+ MEMORYPRESSURE_LOG (" Memory pressure relief: pid = %d, % " PUBLIC_LOG_STRING " : (Unable to get dirty memory information for process)" , getpid () , m_logString);
353451 return ;
354452 }
355453
356454 long residentDiff = currentMemory->resident - m_initialMemory->resident ;
357455 long physicalDiff = currentMemory->physical - m_initialMemory->physical ;
358456
359- MEMORYPRESSURE_LOG (" Memory pressure relief: %" PUBLIC_LOG_STRING " : res = %zu/%zu/%ld, res+swap = %zu/%zu/%ld" ,
457+ MEMORYPRESSURE_LOG (" Memory pressure relief: pid = %d, %" PUBLIC_LOG_STRING " : res = %zu/%zu/%ld, res+swap = %zu/%zu/%ld" ,
458+ getpid (),
360459 m_logString,
361460 m_initialMemory->resident , currentMemory->resident , residentDiff,
362461 m_initialMemory->physical , currentMemory->physical , physicalDiff);
@@ -368,15 +467,17 @@ void MemoryPressureHandler::platformInitialize() { }
368467
369468MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration ()
370469 : baseThreshold(std::min(3 * GB, ramSize()))
470+ , baseThresholdVideo(1 * GB)
371471 , conservativeThresholdFraction(s_conservativeThresholdFraction)
372472 , strictThresholdFraction(s_strictThresholdFraction)
373473 , killThresholdFraction(s_killThresholdFraction)
374474 , pollInterval(s_pollInterval)
375475{
376476}
377477
378- MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration (size_t base, double conservative, double strict, std::optional<double > kill, Seconds interval)
478+ MemoryPressureHandlerConfiguration::MemoryPressureHandlerConfiguration (size_t base, size_t baseVideo, double conservative, double strict, std::optional<double > kill, Seconds interval)
379479 : baseThreshold(base)
480+ , baseThresholdVideo(baseVideo)
380481 , conservativeThresholdFraction(conservative)
381482 , strictThresholdFraction(strict)
382483 , killThresholdFraction(kill)
0 commit comments