Title: [239195] trunk/Source
Revision
239195
Author
sbar...@apple.com
Date
2018-12-13 20:05:41 -0800 (Thu, 13 Dec 2018)

Log Message

The JSC shell should listen for memory pressure events and respond to them
https://bugs.webkit.org/show_bug.cgi?id=192647

Reviewed by Keith Miller.

Source/_javascript_Core:

We want the JSC shell to behave more like the WebContent process when
it comes to running performance tests. One way to make the shell
more like this is to have it respond to memory pressure events in
a similar way as the WebContent process. This makes it easier to run
benchmarks like JetStream2 on the CLI on iOS.

* jsc.cpp:
(jscmain):
* runtime/VM.cpp:
(JSC::VM::drainMicrotasks):
* runtime/VM.h:
(JSC::VM::setOnEachMicrotaskTick):

Source/WTF:

* wtf/MemoryPressureHandler.cpp:
(WTF::MemoryPressureHandler::MemoryPressureHandler):
(WTF::MemoryPressureHandler::setDispatchQueue):
Make it so that we can customize which dispatch queue memory pressure
events get handled on.

* wtf/MemoryPressureHandler.h:
(WTF::MemoryPressureHandler::setShouldLogMemoryMemoryPressureEvents):
Make it so that we can disable logging that happens on each memory
pressure event.

* wtf/cocoa/MemoryPressureHandlerCocoa.mm:
(WTF::MemoryPressureHandler::install):
(WTF::MemoryPressureHandler::uninstall):
(WTF::MemoryPressureHandler::holdOff):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (239194 => 239195)


--- trunk/Source/_javascript_Core/ChangeLog	2018-12-14 03:48:34 UTC (rev 239194)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-12-14 04:05:41 UTC (rev 239195)
@@ -1,3 +1,23 @@
+2018-12-13  Saam Barati  <sbar...@apple.com>
+
+        The JSC shell should listen for memory pressure events and respond to them
+        https://bugs.webkit.org/show_bug.cgi?id=192647
+
+        Reviewed by Keith Miller.
+
+        We want the JSC shell to behave more like the WebContent process when
+        it comes to running performance tests. One way to make the shell
+        more like this is to have it respond to memory pressure events in
+        a similar way as the WebContent process. This makes it easier to run
+        benchmarks like JetStream2 on the CLI on iOS.
+
+        * jsc.cpp:
+        (jscmain):
+        * runtime/VM.cpp:
+        (JSC::VM::drainMicrotasks):
+        * runtime/VM.h:
+        (JSC::VM::setOnEachMicrotaskTick):
+
 2018-12-13  Mark Lam  <mark....@apple.com>
 
         Ensure that StructureFlags initialization always starts with Base::StructureFlags.

Modified: trunk/Source/_javascript_Core/jsc.cpp (239194 => 239195)


--- trunk/Source/_javascript_Core/jsc.cpp	2018-12-14 03:48:34 UTC (rev 239194)
+++ trunk/Source/_javascript_Core/jsc.cpp	2018-12-14 04:05:41 UTC (rev 239195)
@@ -80,8 +80,10 @@
 #include <sys/types.h>
 #include <thread>
 #include <type_traits>
+#include <wtf/Box.h>
 #include <wtf/CommaPrinter.h>
 #include <wtf/MainThread.h>
+#include <wtf/MemoryPressureHandler.h>
 #include <wtf/MonotonicTime.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/StringPrintStream.h>
@@ -2871,9 +2873,49 @@
 #endif
     Gigacage::disableDisablingPrimitiveGigacageIfShouldBeEnabled();
 
+#if PLATFORM(COCOA)
+    auto& memoryPressureHandler = MemoryPressureHandler::singleton();
+    {
+        dispatch_queue_t queue = dispatch_queue_create("jsc shell memory pressure handler", DISPATCH_QUEUE_SERIAL);
+        memoryPressureHandler.setDispatchQueue(queue);
+        dispatch_release(queue);
+    }
+    Box<Critical> memoryPressureCriticalState = Box<Critical>::create(Critical::No);
+    Box<Synchronous> memoryPressureSynchronousState = Box<Synchronous>::create(Synchronous::No);
+    memoryPressureHandler.setLowMemoryHandler([=] (Critical critical, Synchronous synchronous) {
+        // We set these racily with respect to reading them from the JS execution thread.
+        *memoryPressureCriticalState = critical;
+        *memoryPressureSynchronousState = synchronous;
+    });
+    memoryPressureHandler.setShouldLogMemoryMemoryPressureEvents(false);
+    memoryPressureHandler.install();
+
+    auto _onEachMicrotaskTick_ = [&] (VM& vm) {
+        if (*memoryPressureCriticalState == Critical::No)
+            return;
+
+        *memoryPressureCriticalState = Critical::No;
+        bool isSynchronous = *memoryPressureSynchronousState == Synchronous::Yes;
+
+        WTF::releaseFastMallocFreeMemory();
+        vm.deleteAllCode(DeleteAllCodeIfNotCollecting);
+
+        if (!vm.heap.isCurrentThreadBusy()) {
+            if (isSynchronous) {
+                vm.heap.collectNow(Sync, CollectionScope::Full);
+                WTF::releaseFastMallocFreeMemory();
+            } else
+                vm.heap.collectNowFullIfNotDoneRecently(Async);
+        }
+    };
+#endif
+
     int result = runJSC(
         options, false,
-        [&] (VM&, GlobalObject* globalObject, bool& success) {
+        [&] (VM& vm, GlobalObject* globalObject, bool& success) {
+#if PLATFORM(COCOA)
+            vm.setOnEachMicrotaskTick(WTFMove(onEachMicrotaskTick));
+#endif
             runWithOptions(globalObject, options, success);
         });
 

Modified: trunk/Source/_javascript_Core/runtime/VM.cpp (239194 => 239195)


--- trunk/Source/_javascript_Core/runtime/VM.cpp	2018-12-14 03:48:34 UTC (rev 239194)
+++ trunk/Source/_javascript_Core/runtime/VM.cpp	2018-12-14 04:05:41 UTC (rev 239195)
@@ -1128,8 +1128,11 @@
 
 void VM::drainMicrotasks()
 {
-    while (!m_microtaskQueue.isEmpty())
+    while (!m_microtaskQueue.isEmpty()) {
         m_microtaskQueue.takeFirst()->run();
+        if (m_onEachMicrotaskTick)
+            m_onEachMicrotaskTick(*this);
+    }
 }
 
 void QueuedTask::run()

Modified: trunk/Source/_javascript_Core/runtime/VM.h (239194 => 239195)


--- trunk/Source/_javascript_Core/runtime/VM.h	2018-12-14 03:48:34 UTC (rev 239194)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2018-12-14 04:05:41 UTC (rev 239195)
@@ -857,6 +857,7 @@
 
     void queueMicrotask(JSGlobalObject&, Ref<Microtask>&&);
     JS_EXPORT_PRIVATE void drainMicrotasks();
+    ALWAYS_INLINE void setOnEachMicrotaskTick(WTF::Function<void(VM&)>&& func) { m_onEachMicrotaskTick = WTFMove(func); }
     void setGlobalConstRedeclarationShouldThrow(bool globalConstRedeclarationThrow) { m_globalConstRedeclarationShouldThrow = globalConstRedeclarationThrow; }
     ALWAYS_INLINE bool globalConstRedeclarationShouldThrow() const { return m_globalConstRedeclarationShouldThrow; }
 
@@ -1016,6 +1017,8 @@
     std::unique_ptr<ShadowChicken> m_shadowChicken;
     std::unique_ptr<BytecodeIntrinsicRegistry> m_bytecodeIntrinsicRegistry;
 
+    WTF::Function<void(VM&)> m_onEachMicrotaskTick;
+
 #if ENABLE(JIT)
 #if !ASSERT_DISABLED
     JS_EXPORT_PRIVATE static bool s_canUseJITIsSet;

Modified: trunk/Source/WTF/ChangeLog (239194 => 239195)


--- trunk/Source/WTF/ChangeLog	2018-12-14 03:48:34 UTC (rev 239194)
+++ trunk/Source/WTF/ChangeLog	2018-12-14 04:05:41 UTC (rev 239195)
@@ -1,3 +1,26 @@
+2018-12-13  Saam Barati  <sbar...@apple.com>
+
+        The JSC shell should listen for memory pressure events and respond to them
+        https://bugs.webkit.org/show_bug.cgi?id=192647
+
+        Reviewed by Keith Miller.
+
+        * wtf/MemoryPressureHandler.cpp:
+        (WTF::MemoryPressureHandler::MemoryPressureHandler):
+        (WTF::MemoryPressureHandler::setDispatchQueue):
+        Make it so that we can customize which dispatch queue memory pressure
+        events get handled on.
+
+        * wtf/MemoryPressureHandler.h:
+        (WTF::MemoryPressureHandler::setShouldLogMemoryMemoryPressureEvents):
+        Make it so that we can disable logging that happens on each memory
+        pressure event.
+
+        * wtf/cocoa/MemoryPressureHandlerCocoa.mm:
+        (WTF::MemoryPressureHandler::install):
+        (WTF::MemoryPressureHandler::uninstall):
+        (WTF::MemoryPressureHandler::holdOff):
+
 2018-12-13  David Kilzer  <ddkil...@apple.com>
 
         clang-tidy: Fix unnecessary parameter copies in ParallelHelperPool.cpp

Modified: trunk/Source/WTF/wtf/MemoryPressureHandler.cpp (239194 => 239195)


--- trunk/Source/WTF/wtf/MemoryPressureHandler.cpp	2018-12-14 03:48:34 UTC (rev 239194)
+++ trunk/Source/WTF/wtf/MemoryPressureHandler.cpp	2018-12-14 04:05:41 UTC (rev 239195)
@@ -55,6 +55,9 @@
     : m_windowsMeasurementTimer(RunLoop::main(), this, &MemoryPressureHandler::windowsMeasurementTimerFired)
 #endif
 {
+#if PLATFORM(COCOA)
+    setDispatchQueue(dispatch_get_main_queue());
+#endif
 }
 
 void MemoryPressureHandler::setShouldUsePeriodicMemoryMonitor(bool use)
@@ -298,4 +301,15 @@
 void MemoryPressureHandler::platformInitialize() { }
 #endif
 
+#if PLATFORM(COCOA)
+void MemoryPressureHandler::setDispatchQueue(dispatch_queue_t queue)
+{
+    RELEASE_ASSERT(!m_installed);
+    dispatch_retain(queue);
+    if (m_dispatchQueue)
+        dispatch_release(m_dispatchQueue);
+    m_dispatchQueue = queue;
+}
+#endif
+
 } // namespace WebCore

Modified: trunk/Source/WTF/wtf/MemoryPressureHandler.h (239194 => 239195)


--- trunk/Source/WTF/wtf/MemoryPressureHandler.h	2018-12-14 03:48:34 UTC (rev 239194)
+++ trunk/Source/WTF/wtf/MemoryPressureHandler.h	2018-12-14 04:05:41 UTC (rev 239195)
@@ -94,6 +94,10 @@
 
     WTF_EXPORT_PRIVATE static MemoryUsagePolicy currentMemoryUsagePolicy();
 
+#if PLATFORM(COCOA)
+    WTF_EXPORT_PRIVATE void setDispatchQueue(dispatch_queue_t);
+#endif
+
     class ReliefLogger {
     public:
         explicit ReliefLogger(const char *log)
@@ -150,6 +154,8 @@
 
     WTF_EXPORT_PRIVATE static void setPageCount(unsigned);
 
+    void setShouldLogMemoryMemoryPressureEvents(bool shouldLog) { m_shouldLogMemoryMemoryPressureEvents = shouldLog; }
+
 private:
     size_t thresholdForMemoryKill();
     void memoryPressureStatusChanged();
@@ -180,6 +186,7 @@
 
     std::atomic<bool> m_underMemoryPressure;
     bool m_isSimulatingMemoryPressure { false };
+    bool m_shouldLogMemoryMemoryPressureEvents { true };
 
     std::unique_ptr<RunLoop::Timer<MemoryPressureHandler>> m_measurementTimer;
     MemoryUsagePolicy m_memoryUsagePolicy { MemoryUsagePolicy::Unrestricted };
@@ -198,6 +205,10 @@
     RunLoop::Timer<MemoryPressureHandler> m_holdOffTimer;
     void holdOffTimerFired();
 #endif
+
+#if PLATFORM(COCOA)
+    dispatch_queue_t m_dispatchQueue { nullptr };
+#endif
 };
 
 extern WTFLogChannel LogMemoryPressure;

Modified: trunk/Source/WTF/wtf/cocoa/MemoryPressureHandlerCocoa.mm (239194 => 239195)


--- trunk/Source/WTF/wtf/cocoa/MemoryPressureHandlerCocoa.mm	2018-12-14 03:48:34 UTC (rev 239194)
+++ trunk/Source/WTF/wtf/cocoa/MemoryPressureHandlerCocoa.mm	2018-12-14 04:05:41 UTC (rev 239195)
@@ -67,13 +67,13 @@
     if (m_installed || timerEventSource)
         return;
 
-    dispatch_async(dispatch_get_main_queue(), ^{
+    dispatch_async(m_dispatchQueue, ^{
 #if PLATFORM(IOS_FAMILY)
         auto memoryStatusFlags = DISPATCH_MEMORYPRESSURE_NORMAL | DISPATCH_MEMORYPRESSURE_WARN | DISPATCH_MEMORYPRESSURE_CRITICAL | DISPATCH_MEMORYPRESSURE_PROC_LIMIT_WARN | DISPATCH_MEMORYPRESSURE_PROC_LIMIT_CRITICAL;
 #else // PLATFORM(MAC)
         auto memoryStatusFlags = DISPATCH_MEMORYPRESSURE_CRITICAL;
 #endif
-        memoryPressureEventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0, memoryStatusFlags, dispatch_get_main_queue());
+        memoryPressureEventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MEMORYPRESSURE, 0, memoryStatusFlags, m_dispatchQueue);
 
         dispatch_source_set_event_handler(memoryPressureEventSource, ^{
             auto status = dispatch_source_get_data(memoryPressureEventSource);
@@ -102,13 +102,14 @@
 #else // PLATFORM(MAC)
             respondToMemoryPressure(Critical::Yes);
 #endif
-            WTFLogAlways("Received memory pressure event %lu vm pressure %d", status, isUnderMemoryPressure());
+            if (m_shouldLogMemoryMemoryPressureEvents)
+                WTFLogAlways("Received memory pressure event %lu vm pressure %d", status, isUnderMemoryPressure());
         });
         dispatch_resume(memoryPressureEventSource);
     });
 
     // Allow simulation of memory pressure with "notifyutil -p org.WebKit.lowMemory"
-    notify_register_dispatch("org.WebKit.lowMemory", &notifyTokens[0], dispatch_get_main_queue(), ^(int) {
+    notify_register_dispatch("org.WebKit.lowMemory", &notifyTokens[0], m_dispatchQueue, ^(int) {
 #if ENABLE(FMW_FOOTPRINT_COMPARISON)
         auto footprintBefore = pagesPerVMTag();
 #endif
@@ -122,15 +123,15 @@
         logFootprintComparison(footprintBefore, footprintAfter);
 #endif
 
-        dispatch_async(dispatch_get_main_queue(), ^{
+        dispatch_async(m_dispatchQueue, ^{
             endSimulatedMemoryPressure();
         });
     });
 
-    notify_register_dispatch("org.WebKit.lowMemory.begin", &notifyTokens[1], dispatch_get_main_queue(), ^(int) {
+    notify_register_dispatch("org.WebKit.lowMemory.begin", &notifyTokens[1], m_dispatchQueue, ^(int) {
         beginSimulatedMemoryPressure();
     });
-    notify_register_dispatch("org.WebKit.lowMemory.end", &notifyTokens[2], dispatch_get_main_queue(), ^(int) {
+    notify_register_dispatch("org.WebKit.lowMemory.end", &notifyTokens[2], m_dispatchQueue, ^(int) {
         endSimulatedMemoryPressure();
     });
 
@@ -142,7 +143,7 @@
     if (!m_installed)
         return;
 
-    dispatch_async(dispatch_get_main_queue(), ^{
+    dispatch_async(m_dispatchQueue, ^{
         if (memoryPressureEventSource) {
             dispatch_source_cancel(memoryPressureEventSource);
             memoryPressureEventSource = nullptr;
@@ -162,8 +163,8 @@
 
 void MemoryPressureHandler::holdOff(Seconds seconds)
 {
-    dispatch_async(dispatch_get_main_queue(), ^{
-        timerEventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
+    dispatch_async(m_dispatchQueue, ^{
+        timerEventSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, m_dispatchQueue);
         if (timerEventSource) {
             dispatch_set_context(timerEventSource, this);
             // FIXME: The final argument `s_minimumHoldOffTime.seconds()` seems wrong.
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to