[JSC] Add --destroy-vm shell option and dumpHeapStatisticsAtVMDestruction option
authorysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Mar 2019 18:35:04 +0000 (18:35 +0000)
committerysuzuki@apple.com <ysuzuki@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 18 Mar 2019 18:35:04 +0000 (18:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195897

Reviewed by Keith Miller.

It is useful if we have an option logging the status of all the existing MarkedBlocks and their objects at VM destruction.
I used this feature to find wasting memory, and successfully removed many wasted MarkedBlocks and JS cells like r243081.
This patch adds,

1. --destroy-vm option to JSC shell to destroy main thread JSC::VM
2. dumpHeapStatisticsAtVMDestruction to dump MarkedBlocks at VM destruction

While the current option name is "dumpHeapStatisticsAtVMDestruction", we just dump the status of MarkedBlocks and cells. But eventually,
we would like to collect heap statistics and dump them to investigate Heap status more.

This patch also removes logHeapStatisticsAtExit option since it is no longer used in JSC.

* heap/Heap.cpp:
(JSC::Heap::dumpHeapStatisticsAtVMDestruction):
(JSC::Heap::lastChanceToFinalize):
* heap/Heap.h:
* jsc.cpp:
(printUsageStatement):
(CommandLine::parseArguments):
(runJSC):
* runtime/Options.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@243086 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/Heap.h
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/runtime/Options.h

index a7f6537..c059289 100644 (file)
@@ -1,5 +1,34 @@
 2019-03-18  Yusuke Suzuki  <ysuzuki@apple.com>
 
+        [JSC] Add --destroy-vm shell option and dumpHeapStatisticsAtVMDestruction option
+        https://bugs.webkit.org/show_bug.cgi?id=195897
+
+        Reviewed by Keith Miller.
+
+        It is useful if we have an option logging the status of all the existing MarkedBlocks and their objects at VM destruction.
+        I used this feature to find wasting memory, and successfully removed many wasted MarkedBlocks and JS cells like r243081.
+        This patch adds,
+
+        1. --destroy-vm option to JSC shell to destroy main thread JSC::VM
+        2. dumpHeapStatisticsAtVMDestruction to dump MarkedBlocks at VM destruction
+
+        While the current option name is "dumpHeapStatisticsAtVMDestruction", we just dump the status of MarkedBlocks and cells. But eventually,
+        we would like to collect heap statistics and dump them to investigate Heap status more.
+
+        This patch also removes logHeapStatisticsAtExit option since it is no longer used in JSC.
+
+        * heap/Heap.cpp:
+        (JSC::Heap::dumpHeapStatisticsAtVMDestruction):
+        (JSC::Heap::lastChanceToFinalize):
+        * heap/Heap.h:
+        * jsc.cpp:
+        (printUsageStatement):
+        (CommandLine::parseArguments):
+        (runJSC):
+        * runtime/Options.h:
+
+2019-03-18  Yusuke Suzuki  <ysuzuki@apple.com>
+
         [JSC] jsSubstring should resolve rope before calling JSRopeString::create
         https://bugs.webkit.org/show_bug.cgi?id=195840
 
index 230711e..1945104 100644 (file)
@@ -344,6 +344,30 @@ bool Heap::isPagedOut(MonotonicTime deadline)
     return m_objectSpace.isPagedOut(deadline);
 }
 
+void Heap::dumpHeapStatisticsAtVMDestruction()
+{
+    unsigned counter = 0;
+    m_objectSpace.forEachBlock([&] (MarkedBlock::Handle* block) {
+        unsigned live = 0;
+        block->forEachCell([&] (HeapCell* cell, HeapCell::Kind) {
+            if (cell->isLive())
+                live++;
+            return IterationStatus::Continue;
+        });
+        dataLogLn("[", counter++, "] ", block->cellSize(), ", ", live, " / ", block->cellsPerBlock(), " ", static_cast<double>(live) / block->cellsPerBlock() * 100, "% ", block->attributes(), " ", block->subspace()->name());
+        block->forEachCell([&] (HeapCell* heapCell, HeapCell::Kind kind) {
+            if (heapCell->isLive() && kind == HeapCell::Kind::JSCell) {
+                auto* cell = static_cast<JSCell*>(heapCell);
+                if (cell->isObject())
+                    dataLogLn("    ", JSValue((JSObject*)cell));
+                else
+                    dataLogLn("    ", *cell);
+            }
+            return IterationStatus::Continue;
+        });
+    });
+}
+
 // The VM is being destroyed and the collector will never run again.
 // Run all pending finalizers now because we won't get another chance.
 void Heap::lastChanceToFinalize()
@@ -423,6 +447,9 @@ void Heap::lastChanceToFinalize()
     
     if (Options::logGC())
         dataLog("5 ");
+
+    if (UNLIKELY(Options::dumpHeapStatisticsAtVMDestruction()))
+        dumpHeapStatisticsAtVMDestruction();
     
     m_arrayBuffers.lastChanceToFinalize();
     m_objectSpace.stopAllocatingForGood();
index 5912f99..86ade6e 100644 (file)
@@ -573,6 +573,8 @@ private:
 
     void setBonusVisitorTask(RefPtr<SharedTask<void(SlotVisitor&)>>);
 
+    void dumpHeapStatisticsAtVMDestruction();
+
     static bool useGenerationalGC();
     static bool shouldSweepSynchronously();
     
index 7ef1ae1..d0399dd 100644 (file)
@@ -413,15 +413,16 @@ public:
         parseArguments(argc, argv);
     }
 
+    Vector<Script> m_scripts;
+    Vector<String> m_arguments;
+    String m_profilerOutput;
+    String m_uncaughtExceptionName;
     bool m_interactive { false };
     bool m_dump { false };
     bool m_module { false };
     bool m_exitCode { false };
-    Vector<Script> m_scripts;
-    Vector<String> m_arguments;
+    bool m_destroyVM { false };
     bool m_profile { false };
-    String m_profilerOutput;
-    String m_uncaughtExceptionName;
     bool m_treatWatchdogExceptionAsSuccess { false };
     bool m_alwaysDumpUncaughtException { false };
     bool m_dumpMemoryFootprint { false };
@@ -2692,6 +2693,7 @@ static NO_RETURN void printUsageStatement(bool help = false)
     fprintf(stderr, "  --options                  Dumps all JSC VM options and exits\n");
     fprintf(stderr, "  --dumpOptions              Dumps all non-default JSC VM options before continuing\n");
     fprintf(stderr, "  --<jsc VM option>=<value>  Sets the specified JSC VM option\n");
+    fprintf(stderr, "  --destroy-vm               Destroy VM before exiting\n");
     fprintf(stderr, "\n");
     fprintf(stderr, "Files with a .mjs extension will always be evaluated as modules.\n");
     fprintf(stderr, "\n");
@@ -2800,6 +2802,10 @@ void CommandLine::parseArguments(int argc, char** argv)
             m_dumpSamplingProfilerData = true;
             continue;
         }
+        if (!strcmp(arg, "--destroy-vm")) {
+            m_destroyVM = true;
+            continue;
+        }
 
         static const char* timeoutMultiplierOptStr = "--timeoutMultiplier=";
         static const unsigned timeoutMultiplierOptStrLength = strlen(timeoutMultiplierOptStr);
@@ -2973,7 +2979,7 @@ int runJSC(const CommandLine& options, bool isWorker, const Func& func)
 
     vm.codeCache()->write(vm);
 
-    if (isWorker) {
+    if (options.m_destroyVM || isWorker) {
         JSLockHolder locker(vm);
         // This is needed because we don't want the worker's main
         // thread to die before its compilation threads finish.
index 9216aaa..3c173a3 100644 (file)
@@ -394,7 +394,7 @@ constexpr bool enableWebAssemblyStreamingApi = false;
     v(unsigned, gcMaxHeapSize, 0, Normal, nullptr) \
     v(unsigned, forceRAMSize, 0, Normal, nullptr) \
     v(bool, recordGCPauseTimes, false, Normal, nullptr) \
-    v(bool, logHeapStatisticsAtExit, false, Normal, nullptr) \
+    v(bool, dumpHeapStatisticsAtVMDestruction, false, Normal, nullptr) \
     v(bool, forceCodeBlockToJettisonDueToOldAge, false, Normal, "If true, this means that anytime we can jettison a CodeBlock due to old age, we do.") \
     v(bool, useEagerCodeBlockJettisonTiming, false, Normal, "If true, the time slices for jettisoning a CodeBlock due to old age are shrunk significantly.") \
     \