⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 211316 in webkit


Ignore:
Timestamp:
Jan 27, 2017, 5:04:06 PM (10 years ago)
Author:
sbarati@apple.com
Message:

Make the CLI for the sampling profiler better for inlined call site indices
​https://bugs.webkit.org/show_bug.cgi?id=167482

Reviewed by Mark Lam.

This patches changes the command line interface for the sampling
profiler to also dump the machine frame that the semantic code
origin is in if the semantic code origin is inlined. This helps
when doing performance work because it's helpful to know the
context that an inlined frame is in. Before, we used to just
say it was in the baseline JIT if it didn't have its own optimized
compile. Now, we can tell that its inlined into a DFG or FTL frame.

  • inspector/agents/InspectorScriptProfilerAgent.cpp:

(Inspector::buildSamples):

  • runtime/Options.h:
  • runtime/SamplingProfiler.cpp:

(JSC::SamplingProfiler::processUnverifiedStackTraces):
(JSC::SamplingProfiler::reportTopFunctions):
(JSC::SamplingProfiler::reportTopBytecodes):

  • runtime/SamplingProfiler.h:

(JSC::SamplingProfiler::StackFrame::CodeLocation::hasCodeBlockHash):
(JSC::SamplingProfiler::StackFrame::CodeLocation::hasBytecodeIndex):
(JSC::SamplingProfiler::StackFrame::CodeLocation::hasExpressionInfo):
(JSC::SamplingProfiler::StackFrame::hasExpressionInfo):
(JSC::SamplingProfiler::StackFrame::lineNumber):
(JSC::SamplingProfiler::StackFrame::columnNumber):
(JSC::SamplingProfiler::StackFrame::hasBytecodeIndex): Deleted.
(JSC::SamplingProfiler::StackFrame::hasCodeBlockHash): Deleted.

Location:
trunk/Source/JavaScriptCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r211306 r211316  
     12017-01-27  Saam Barati  <sbarati@apple.com>
     2
     3        Make the CLI for the sampling profiler better for inlined call site indices
     4        https://bugs.webkit.org/show_bug.cgi?id=167482
     5
     6        Reviewed by Mark Lam.
     7
     8        This patches changes the command line interface for the sampling
     9        profiler to also dump the machine frame that the semantic code
     10        origin is in if the semantic code origin is inlined. This helps
     11        when doing performance work because it's helpful to know the
     12        context that an inlined frame is in. Before, we used to just
     13        say it was in the baseline JIT if it didn't have its own optimized
     14        compile. Now, we can tell that its inlined into a DFG or FTL frame.
     15
     16        * inspector/agents/InspectorScriptProfilerAgent.cpp:
     17        (Inspector::buildSamples):
     18        * runtime/Options.h:
     19        * runtime/SamplingProfiler.cpp:
     20        (JSC::SamplingProfiler::processUnverifiedStackTraces):
     21        (JSC::SamplingProfiler::reportTopFunctions):
     22        (JSC::SamplingProfiler::reportTopBytecodes):
     23        * runtime/SamplingProfiler.h:
     24        (JSC::SamplingProfiler::StackFrame::CodeLocation::hasCodeBlockHash):
     25        (JSC::SamplingProfiler::StackFrame::CodeLocation::hasBytecodeIndex):
     26        (JSC::SamplingProfiler::StackFrame::CodeLocation::hasExpressionInfo):
     27        (JSC::SamplingProfiler::StackFrame::hasExpressionInfo):
     28        (JSC::SamplingProfiler::StackFrame::lineNumber):
     29        (JSC::SamplingProfiler::StackFrame::columnNumber):
     30        (JSC::SamplingProfiler::StackFrame::hasBytecodeIndex): Deleted.
     31        (JSC::SamplingProfiler::StackFrame::hasCodeBlockHash): Deleted.
     32
    1332017-01-27  Yusuke Suzuki  <utatane.tea@gmail.com>
    234
  • trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp

    r210042 r211316  
    181181            if (stackFrame.hasExpressionInfo()) {
    182182                Ref<Protocol::ScriptProfiler::ExpressionLocation> expressionLocation = Protocol::ScriptProfiler::ExpressionLocation::create()
    183                     .setLine(stackFrame.lineNumber)
    184                     .setColumn(stackFrame.columnNumber)
     183                    .setLine(stackFrame.lineNumber())
     184                    .setColumn(stackFrame.columnNumber())
    185185                    .release();
    186186                frame->setExpressionLocation(WTFMove(expressionLocation));
  • trunk/Source/JavaScriptCore/runtime/Options.h

    r211069 r211316  
    362362    v(unsigned, sampleInterval, 1000, Normal, "Time between stack traces in microseconds.") \
    363363    v(bool, collectSamplingProfilerDataForJSCShell, false, Normal, "This corresponds to the JSC shell's --sample option.") \
     364    v(unsigned, samplingProfilerTopFunctionsCount, 12, Normal, "Number of top functions to report when using the command line interface.") \
     365    v(unsigned, samplingProfilerTopBytecodesCount, 40, Normal, "Number of top bytecodes to report when using the command line interface.") \
    364366    v(optionString, samplingProfilerPath, nullptr, Normal, "The path to the directory to write sampiling profiler output to. This probably will not work with WK2 unless the path is in the whitelist.") \
    365367    \
  • trunk/Source/JavaScriptCore/runtime/SamplingProfiler.cpp

    r211247 r211316  
    4545#include "PCToCodeOriginMap.h"
    4646#include "SlotVisitor.h"
     47#include "StrongInlines.h"
    4748#include "VM.h"
    4849#include <wtf/HashSet.h>
    … …  
    364365        stackTrace.timestamp = unprocessedStackTrace.timestamp;
    365366
    366         auto appendCodeBlock = [&] (CodeBlock* codeBlock, unsigned bytecodeIndex) {
    367             stackTrace.frames.append(StackFrame(codeBlock->ownerExecutable()));
    368             m_liveCellPointers.add(codeBlock->ownerExecutable());
    369 
     367        auto populateCodeLocation = [] (CodeBlock* codeBlock, unsigned bytecodeIndex, StackFrame::CodeLocation& location) {
    370368            if (bytecodeIndex < codeBlock->instructionCount()) {
    371369                int divot;
    … …  
    373371                int endOffset;
    374372                codeBlock->expressionRangeForBytecodeOffset(bytecodeIndex, divot, startOffset, endOffset,
    375                     stackTrace.frames.last().lineNumber, stackTrace.frames.last().columnNumber);
    376                 stackTrace.frames.last().bytecodeIndex = bytecodeIndex;
     373                    location.lineNumber, location.columnNumber);
     374                location.bytecodeIndex = bytecodeIndex;
    377375            }
    378376            if (Options::collectSamplingProfilerDataForJSCShell()) {
    379                 stackTrace.frames.last().codeBlockHash = codeBlock->hash();
    380                 stackTrace.frames.last().jitType = codeBlock->jitType();
    381             }
     377                location.codeBlockHash = codeBlock->hash();
     378                location.jitType = codeBlock->jitType();
     379            }
     380        };
     381
     382        auto appendCodeBlock = [&] (CodeBlock* codeBlock, unsigned bytecodeIndex) {
     383            stackTrace.frames.append(StackFrame(codeBlock->ownerExecutable()));
     384            m_liveCellPointers.add(codeBlock->ownerExecutable());
     385            populateCodeLocation(codeBlock, bytecodeIndex, stackTrace.frames.last().semanticLocation);
    382386        };
    383387
    … …  
    386390        };
    387391
    388         auto storeCalleeIntoTopFrame = [&] (EncodedJSValue encodedCallee) {
     392        auto storeCalleeIntoLastFrame = [&] (EncodedJSValue encodedCallee) {
    389393            // Set the callee if it's a valid GC object.
    390394            JSValue callee = JSValue::decode(encodedCallee);
    … …  
    442446        };
    443447
     448        auto appendCodeOrigin = [&] (CodeBlock* machineCodeBlock, CodeOrigin origin) {
     449            size_t startIndex = stackTrace.frames.size(); // We want to change stack traces that we're about to append.
     450
     451            CodeOrigin machineOrigin;
     452            origin.walkUpInlineStack([&] (const CodeOrigin& codeOrigin) {
     453                machineOrigin = codeOrigin;
     454                appendCodeBlock(codeOrigin.inlineCallFrame ? codeOrigin.inlineCallFrame->baselineCodeBlock.get() : machineCodeBlock, codeOrigin.bytecodeIndex);
     455            });
     456
     457            if (Options::collectSamplingProfilerDataForJSCShell()) {
     458                RELEASE_ASSERT(machineOrigin.isSet());
     459                RELEASE_ASSERT(!machineOrigin.inlineCallFrame);
     460
     461                StackFrame::CodeLocation machineLocation = stackTrace.frames.last().semanticLocation;
     462
     463                // We want to tell each inlined frame about the machine frame
     464                // they were inlined into. Currently, we only use this for dumping
     465                // output on the command line, but we could extend it to the web
     466                // inspector in the future if we find a need for it there.
     467                RELEASE_ASSERT(stackTrace.frames.size());
     468                for (size_t i = startIndex; i < stackTrace.frames.size() - 1; i++)
     469                    stackTrace.frames[i].machineLocation = std::make_pair(machineLocation, Strong<CodeBlock>(m_vm, machineCodeBlock));
     470            }
     471        };
    444472
    445473        // Prepend the top-most inlined frame if needed and gather
    … …  
    469497
    470498                    appendCodeBlock(topCodeBlock, bytecodeIndex);
    471                     storeCalleeIntoTopFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
     499                    storeCalleeIntoLastFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
    472500                    startIndex = 1;
    473501                }
    474502            } else if (std::optional<CodeOrigin> codeOrigin = topCodeBlock->findPC(unprocessedStackTrace.topPC)) {
    475                 codeOrigin->walkUpInlineStack([&] (const CodeOrigin& codeOrigin) {
    476                     appendCodeBlock(codeOrigin.inlineCallFrame ? codeOrigin.inlineCallFrame->baselineCodeBlock.get() : topCodeBlock, codeOrigin.bytecodeIndex);
    477                 });
    478                 storeCalleeIntoTopFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
     503                appendCodeOrigin(topCodeBlock, *codeOrigin);
     504                storeCalleeIntoLastFrame(unprocessedStackTrace.frames[0].unverifiedCallee);
    479505                startIndex = 1;
    480506            }
    … …  
    493519#if ENABLE(DFG_JIT)
    494520                if (codeBlock->hasCodeOrigins()) {
    495                     if (codeBlock->canGetCodeOrigin(callSiteIndex)) {
    496                         codeBlock->codeOrigin(callSiteIndex).walkUpInlineStack([&] (const CodeOrigin& codeOrigin) {
    497                             appendCodeBlock(codeOrigin.inlineCallFrame ? codeOrigin.inlineCallFrame->baselineCodeBlock.get() : codeBlock, codeOrigin.bytecodeIndex);
    498                         });
    499                     } else
     521                    if (codeBlock->canGetCodeOrigin(callSiteIndex))
     522                        appendCodeOrigin(codeBlock, codeBlock->codeOrigin(callSiteIndex));
     523                    else
    500524                        appendCodeBlock(codeBlock, std::numeric_limits<unsigned>::max());
    501525                } else
    … …  
    509533            // Note that this is okay to do if we walked the inline stack because
    510534            // the machine frame will be at the top of the processed stack trace.
    511             storeCalleeIntoTopFrame(unprocessedStackFrame.unverifiedCallee);
     535            storeCalleeIntoLastFrame(unprocessedStackFrame.unverifiedCallee);
    512536        }
    513537    }
    … …  
    844868    };
    845869
    846     out.print("\n\nSampling rate: ", m_timingInterval.count(), " microseconds\n");
    847     out.print("Hottest functions as <numSamples  'functionName:sourceID'>\n");
    848     for (size_t i = 0; i < 40; i++) {
    849         auto pair = takeMax();
    850         if (pair.first.isEmpty())
    851             break;
    852         out.printf("%6zu ", pair.second);
    853         out.print("   '", pair.first, "'\n");
     870    if (Options::samplingProfilerTopFunctionsCount()) {
     871        out.print("\n\nSampling rate: ", m_timingInterval.count(), " microseconds\n");
     872        out.print("Top functions as <numSamples  'functionName:sourceID'>\n");
     873        for (size_t i = 0; i < Options::samplingProfilerTopFunctionsCount(); i++) {
     874            auto pair = takeMax();
     875            if (pair.first.isEmpty())
     876                break;
     877            out.printf("%6zu ", pair.second);
     878            out.print("   '", pair.first, "'\n");
     879        }
    854880    }
    855881}
    … …  
    874900            continue;
    875901
     902        auto descriptionForLocation = [&] (StackFrame::CodeLocation location) -> String {
     903            String bytecodeIndex;
     904            String codeBlockHash;
     905            if (location.hasBytecodeIndex())
     906                bytecodeIndex = String::number(location.bytecodeIndex);
     907            else
     908                bytecodeIndex = "<nil>";
     909
     910            if (location.hasCodeBlockHash()) {
     911                StringPrintStream stream;
     912                location.codeBlockHash.dump(stream);
     913                codeBlockHash = stream.toString();
     914            } else
     915                codeBlockHash = "<nil>";
     916
     917            return makeString("#", codeBlockHash, ":", JITCode::typeName(location.jitType), ":", bytecodeIndex);
     918        };
     919
    876920        StackFrame& frame = stackTrace.frames.first();
    877         String bytecodeIndex;
    878         String codeBlockHash;
    879         if (frame.hasBytecodeIndex())
    880             bytecodeIndex = String::number(frame.bytecodeIndex);
    881         else
    882             bytecodeIndex = "<nil>";
    883 
    884         if (frame.hasCodeBlockHash()) {
    885             StringPrintStream stream;
    886             frame.codeBlockHash.dump(stream);
    887             codeBlockHash = stream.toString();
    888         } else
    889             codeBlockHash = "<nil>";
    890 
    891         String frameDescription = makeString(frame.displayName(m_vm), "#", codeBlockHash, ":", JITCode::typeName(frame.jitType), ":", bytecodeIndex);
     921        String frameDescription = makeString(frame.displayName(m_vm), descriptionForLocation(frame.semanticLocation));
     922        if (std::optional<std::pair<StackFrame::CodeLocation, Strong<CodeBlock>>> machineLocation = frame.machineLocation) {
     923            frameDescription = makeString(frameDescription, " <-- ",
     924                machineLocation->second->inferredName().data(), descriptionForLocation(machineLocation->first));
     925        }
    892926        bytecodeCounts.add(frameDescription, 0).iterator->value++;
    893927    }
    … …  
    907941    };
    908942
    909     out.print("\n\nSampling rate: ", m_timingInterval.count(), " microseconds\n");
    910     out.print("Hottest bytecodes as <numSamples   'functionName#hash:JITType:bytecodeIndex'>\n");
    911     for (size_t i = 0; i < 80; i++) {
    912         auto pair = takeMax();
    913         if (pair.first.isEmpty())
    914             break;
    915         out.printf("%6zu ", pair.second);
    916         out.print("   '", pair.first, "'\n");
     943    if (Options::samplingProfilerTopBytecodesCount()) {
     944        out.print("\n\nSampling rate: ", m_timingInterval.count(), " microseconds\n");
     945        out.print("Hottest bytecodes as <numSamples   'functionName#hash:JITType:bytecodeIndex'>\n");
     946        for (size_t i = 0; i < Options::samplingProfilerTopBytecodesCount(); i++) {
     947            auto pair = takeMax();
     948            if (pair.first.isEmpty())
     949                break;
     950            out.printf("%6zu ", pair.second);
     951            out.print("   '", pair.first, "'\n");
     952        }
    917953    }
    918954}
  • trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h

    r206525 r211316  
    8181        ExecutableBase* executable { nullptr };
    8282        JSObject* callee { nullptr };
    83         // These attempt to be expression-level line and column number.
    84         unsigned lineNumber { std::numeric_limits<unsigned>::max() };
    85         unsigned columnNumber { std::numeric_limits<unsigned>::max() };
    86         unsigned bytecodeIndex { std::numeric_limits<unsigned>::max() };
    87         CodeBlockHash codeBlockHash;
    88         JITCode::JITType jitType { JITCode::None };
    89 
    90         bool hasExpressionInfo() const
     83
     84        struct CodeLocation {
     85            bool hasCodeBlockHash() const
     86            {
     87                return codeBlockHash.isSet();
     88            }
     89
     90            bool hasBytecodeIndex() const
     91            {
     92                return bytecodeIndex != std::numeric_limits<unsigned>::max();
     93            }
     94
     95            bool hasExpressionInfo() const
     96            {
     97                return lineNumber != std::numeric_limits<unsigned>::max()
     98                    && columnNumber != std::numeric_limits<unsigned>::max();
     99            }
     100
     101            // These attempt to be expression-level line and column number.
     102            unsigned lineNumber { std::numeric_limits<unsigned>::max() };
     103            unsigned columnNumber { std::numeric_limits<unsigned>::max() };
     104            unsigned bytecodeIndex { std::numeric_limits<unsigned>::max() };
     105            CodeBlockHash codeBlockHash;
     106            JITCode::JITType jitType { JITCode::None };
     107        };
     108
     109        CodeLocation semanticLocation;
     110        std::optional<std::pair<CodeLocation, Strong<CodeBlock>>> machineLocation; // This is non-null if we were inlined. It represents the machine frame we were inlined into.
     111
     112        bool hasExpressionInfo() const { return semanticLocation.hasExpressionInfo(); }
     113        unsigned lineNumber() const
    91114        {
    92             return lineNumber != std::numeric_limits<unsigned>::max()
    93                 && columnNumber != std::numeric_limits<unsigned>::max();
     115            ASSERT(hasExpressionInfo());
     116            return semanticLocation.lineNumber;
    94117        }
    95 
    96         bool hasBytecodeIndex() const
     118        unsigned columnNumber() const
    97119        {
    98             return bytecodeIndex != std::numeric_limits<unsigned>::max();
    99         }
    100 
    101         bool hasCodeBlockHash() const
    102         {
    103             return codeBlockHash.isSet();
     120            ASSERT(hasExpressionInfo());
     121            return semanticLocation.columnNumber;
    104122        }
    105123
Note: See TracChangeset for help on using the changeset viewer.