Title: [199754] trunk/Source/_javascript_Core
Revision
199754
Author
sbar...@apple.com
Date
2016-04-19 19:24:53 -0700 (Tue, 19 Apr 2016)

Log Message

allow jsc shell to dump sampling profiler data
https://bugs.webkit.org/show_bug.cgi?id=156725

Reviewed by Benjamin Poulain.

This patch adds a '--reportSamplingProfilerData' option to the
JSC shell which will enable the sampling profiler and dump
its data at the end of execution. The dump will include the
40 hottest functions and the 80 hottest bytecode locations.
If you're using this option to debug, it's easy to just hack
on the code to make it dump more or less information.

* jsc.cpp:
(CommandLine::parseArguments):
(jscmain):
* runtime/Options.h:
* runtime/SamplingProfiler.cpp:
(JSC::SamplingProfiler::processUnverifiedStackTraces):
(JSC::SamplingProfiler::stackTracesAsJSON):
(JSC::SamplingProfiler::reportTopFunctions):
(JSC::SamplingProfiler::reportTopBytecodes):
* runtime/SamplingProfiler.h:
(JSC::SamplingProfiler::StackFrame::hasExpressionInfo):
(JSC::SamplingProfiler::StackFrame::hasBytecodeIndex):
(JSC::SamplingProfiler::StackFrame::hasCodeBlockHash):
(JSC::SamplingProfiler::setStopWatch):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (199753 => 199754)


--- trunk/Source/_javascript_Core/ChangeLog	2016-04-20 01:36:02 UTC (rev 199753)
+++ trunk/Source/_javascript_Core/ChangeLog	2016-04-20 02:24:53 UTC (rev 199754)
@@ -1,3 +1,32 @@
+2016-04-19  Saam barati  <sbar...@apple.com>
+
+        allow jsc shell to dump sampling profiler data
+        https://bugs.webkit.org/show_bug.cgi?id=156725
+
+        Reviewed by Benjamin Poulain.
+
+        This patch adds a '--reportSamplingProfilerData' option to the
+        JSC shell which will enable the sampling profiler and dump
+        its data at the end of execution. The dump will include the
+        40 hottest functions and the 80 hottest bytecode locations.
+        If you're using this option to debug, it's easy to just hack
+        on the code to make it dump more or less information.
+
+        * jsc.cpp:
+        (CommandLine::parseArguments):
+        (jscmain):
+        * runtime/Options.h:
+        * runtime/SamplingProfiler.cpp:
+        (JSC::SamplingProfiler::processUnverifiedStackTraces):
+        (JSC::SamplingProfiler::stackTracesAsJSON):
+        (JSC::SamplingProfiler::reportTopFunctions):
+        (JSC::SamplingProfiler::reportTopBytecodes):
+        * runtime/SamplingProfiler.h:
+        (JSC::SamplingProfiler::StackFrame::hasExpressionInfo):
+        (JSC::SamplingProfiler::StackFrame::hasBytecodeIndex):
+        (JSC::SamplingProfiler::StackFrame::hasCodeBlockHash):
+        (JSC::SamplingProfiler::setStopWatch):
+
 2016-04-19  Mark Lam  <mark....@apple.com>
 
         Re-landing: ES6: Implement RegExp.prototype[@@search].

Modified: trunk/Source/_javascript_Core/jsc.cpp (199753 => 199754)


--- trunk/Source/_javascript_Core/jsc.cpp	2016-04-20 01:36:02 UTC (rev 199753)
+++ trunk/Source/_javascript_Core/jsc.cpp	2016-04-20 02:24:53 UTC (rev 199754)
@@ -660,6 +660,7 @@
     Vector<String> m_arguments;
     bool m_profile { false };
     String m_profilerOutput;
+    bool m_dumpSamplingProfilerData { false };
 
     void parseArguments(int, char**);
 };
@@ -2166,6 +2167,12 @@
             needToDumpOptions = true;
             continue;
         }
+        if (!strcmp(arg, "--reportSamplingProfilerData")) {
+            JSC::Options::useSamplingProfiler() = true;
+            JSC::Options::collectSamplingProfilerDataForJSCShell() = true;
+            m_dumpSamplingProfilerData = true;
+            continue;
+        }
 
         // See if the -- option is a JSC VM option.
         if (strstr(arg, "--") == arg) {
@@ -2266,6 +2273,11 @@
         vm->heap.collectAllGarbage();
     }
 
+    if (options.m_dumpSamplingProfilerData) {
+        vm->samplingProfiler()->reportTopFunctions();
+        vm->samplingProfiler()->reportTopBytecodes();
+    }
+
     printSuperSamplerState();
 
     return result;

Modified: trunk/Source/_javascript_Core/runtime/Options.h (199753 => 199754)


--- trunk/Source/_javascript_Core/runtime/Options.h	2016-04-20 01:36:02 UTC (rev 199753)
+++ trunk/Source/_javascript_Core/runtime/Options.h	2016-04-20 02:24:53 UTC (rev 199754)
@@ -318,6 +318,7 @@
     v(bool, useTypeProfiler, false, nullptr) \
     v(bool, useControlFlowProfiler, false, nullptr) \
     v(bool, useSamplingProfiler, false, nullptr) \
+    v(bool, collectSamplingProfilerDataForJSCShell, false, "This corresponds to the JSC shell's --reportSamplingProfilerData option.") \
     v(bool, alwaysGeneratePCToCodeOriginMap, false, "This will make sure we always generate a PCToCodeOriginMap for JITed code.") \
     \
     v(bool, verifyHeap, false, nullptr) \

Modified: trunk/Source/_javascript_Core/runtime/SamplingProfiler.cpp (199753 => 199754)


--- trunk/Source/_javascript_Core/runtime/SamplingProfiler.cpp	2016-04-20 01:36:02 UTC (rev 199753)
+++ trunk/Source/_javascript_Core/runtime/SamplingProfiler.cpp	2016-04-20 02:24:53 UTC (rev 199754)
@@ -366,7 +366,10 @@
                 int endOffset;
                 codeBlock->expressionRangeForBytecodeOffset(bytecodeIndex, divot, startOffset, endOffset,
                     stackTrace.frames.last().lineNumber, stackTrace.frames.last().columnNumber);
+                stackTrace.frames.last().bytecodeIndex = bytecodeIndex;
             }
+            if (Options::collectSamplingProfilerDataForJSCShell())
+                stackTrace.frames.last().codeBlockHash = codeBlock->hash();
         };
 
         auto appendEmptyFrame = [&] {
@@ -755,6 +758,109 @@
     return json.toString();
 }
 
+void SamplingProfiler::reportTopFunctions()
+{
+    LockHolder locker(m_lock);
+
+    {
+        HeapIterationScope heapIterationScope(m_vm.heap);
+        processUnverifiedStackTraces();
+    }
+
+
+    HashMap<String, size_t> functionCounts;
+    for (StackTrace& stackTrace : m_stackTraces) {
+        if (!stackTrace.frames.size())
+            continue;
+
+        StackFrame& frame = stackTrace.frames.first();
+        String frameDescription = makeString(frame.displayName(m_vm), ":", String::number(frame.sourceID()));
+        functionCounts.add(frameDescription, 0).iterator->value++;
+    }
+
+    auto takeMax = [&] () -> std::pair<String, size_t> {
+        String maxFrameDescription;
+        size_t maxFrameCount = 0;
+        for (auto entry : functionCounts) {
+            if (entry.value > maxFrameCount) {
+                maxFrameCount = entry.value;
+                maxFrameDescription = entry.key;
+            }
+        }
+        if (!maxFrameDescription.isEmpty())
+            functionCounts.remove(maxFrameDescription);
+        return std::make_pair(maxFrameDescription, maxFrameCount);
+    };
+
+    dataLog("\n\nSampling rate: ", m_timingInterval.count(), " microseconds\n");
+    dataLog("Hottest functions as <numSamples  'functionName:sourceID'>\n");
+    for (size_t i = 0; i < 40; i++) {
+        auto pair = takeMax();
+        if (pair.first.isEmpty())
+            break;
+        dataLogF("%6zu ", pair.second);
+        dataLog("   '", pair.first, "'\n");
+    }
+}
+
+void SamplingProfiler::reportTopBytecodes()
+{
+    LockHolder locker(m_lock);
+
+    {
+        HeapIterationScope heapIterationScope(m_vm.heap);
+        processUnverifiedStackTraces();
+    }
+
+    HashMap<String, size_t> bytecodeCounts;
+    for (StackTrace& stackTrace : m_stackTraces) {
+        if (!stackTrace.frames.size())
+            continue;
+
+        StackFrame& frame = stackTrace.frames.first();
+        String bytecodeIndex;
+        String codeBlockHash;
+        if (frame.hasBytecodeIndex())
+            bytecodeIndex = String::number(frame.bytecodeIndex);
+        else
+            bytecodeIndex = "<nil>";
+
+        if (frame.hasCodeBlockHash()) {
+            StringPrintStream stream;
+            frame.codeBlockHash.dump(stream);
+            codeBlockHash = stream.toString();
+        } else
+            codeBlockHash = "<nil>";
+
+        String frameDescription = makeString(frame.displayName(m_vm), "#", codeBlockHash, ":", bytecodeIndex);
+        bytecodeCounts.add(frameDescription, 0).iterator->value++;
+    }
+
+    auto takeMax = [&] () -> std::pair<String, size_t> {
+        String maxFrameDescription;
+        size_t maxFrameCount = 0;
+        for (auto entry : bytecodeCounts) {
+            if (entry.value > maxFrameCount) {
+                maxFrameCount = entry.value;
+                maxFrameDescription = entry.key;
+            }
+        }
+        if (!maxFrameDescription.isEmpty())
+            bytecodeCounts.remove(maxFrameDescription);
+        return std::make_pair(maxFrameDescription, maxFrameCount);
+    };
+
+    dataLog("\n\nSampling rate: ", m_timingInterval.count(), " microseconds\n");
+    dataLog("Hottest bytecodes as <numSamples   'functionName#hash:bytecodeIndex'>\n");
+    for (size_t i = 0; i < 80; i++) {
+        auto pair = takeMax();
+        if (pair.first.isEmpty())
+            break;
+        dataLogF("%6zu ", pair.second);
+        dataLog("   '", pair.first, "'\n");
+    }
+}
+
 } // namespace JSC
 
 namespace WTF {

Modified: trunk/Source/_javascript_Core/runtime/SamplingProfiler.h (199753 => 199754)


--- trunk/Source/_javascript_Core/runtime/SamplingProfiler.h	2016-04-20 01:36:02 UTC (rev 199753)
+++ trunk/Source/_javascript_Core/runtime/SamplingProfiler.h	2016-04-20 02:24:53 UTC (rev 199754)
@@ -29,6 +29,7 @@
 #if ENABLE(SAMPLING_PROFILER)
 
 #include "CallFrame.h"
+#include "CodeBlockHash.h"
 #include "MachineStackMarker.h"
 #include <wtf/HashSet.h>
 #include <wtf/Lock.h>
@@ -83,6 +84,8 @@
         // These attempt to be _expression_-level line and column number.
         unsigned lineNumber { std::numeric_limits<unsigned>::max() };
         unsigned columnNumber { std::numeric_limits<unsigned>::max() };
+        unsigned bytecodeIndex { std::numeric_limits<unsigned>::max() };
+        CodeBlockHash codeBlockHash;
 
         bool hasExpressionInfo() const
         {
@@ -90,6 +93,16 @@
                 && columnNumber != std::numeric_limits<unsigned>::max();
         }
 
+        bool hasBytecodeIndex() const
+        {
+            return bytecodeIndex != std::numeric_limits<unsigned>::max();
+        }
+
+        bool hasCodeBlockHash() const
+        {
+            return codeBlockHash.isSet();
+        }
+
         // These are function-level data.
         String nameFromCallee(VM&);
         String displayName(VM&);
@@ -137,6 +150,10 @@
     void setStopWatch(const LockHolder&, Ref<Stopwatch>&& stopwatch) { m_stopwatch = WTFMove(stopwatch); }
     void pause(const LockHolder&);
 
+    // Used for debugging in the JSC shell.
+    JS_EXPORT_PRIVATE void reportTopFunctions();
+    JS_EXPORT_PRIVATE void reportTopBytecodes();
+
 private:
     void clearData(const LockHolder&);
     void createThreadIfNecessary(const LockHolder&);
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to