Ignore:
Timestamp:
Dec 4, 2012, 5:26:13 PM (12 years ago)
Author:
[email protected]
Message:

JSC should be able to report profiling data associated with the IR dumps and disassembly
https://bugs.webkit.org/show_bug.cgi?id=102999

Reviewed by Gavin Barraclough.

Source/JavaScriptCore:

Added a new profiler to JSC. It's simply called "Profiler" in anticipation of it
ultimately replacing the previous profiling infrastructure. This profiler counts the
number of times that a bytecode executes in various engines, and will record both the
counts and all disassembly and bytecode dumps, into a database that can be at any
time turned into either a JS object using any global object or global data of your
choice, or can be turned into a JSON string, or saved to a file.

Currently the only use of this is the new '-p <file>' flag to the jsc command-line.

The profiler is always compiled in and normally incurs no execution time cost, but is
only activated when you create a Profiler::Database and install it in
JSGlobalData::m_perBytecodeProfiler. From that point on, all code blocks will be
compiled along with disassembly and bytecode dumps stored into the Profiler::Database,
and all code blocks will have execution counts, which are also stored in the database.
The database will continue to keep information about code blocks alive even after they
are otherwise GC'd.

This currently still has some glitches, like the fact that it only counts executions
in the JITs. Doing execution counting in the LLInt might require a bit of a rethink
about how the counting is expressed - currently it is implicit in bytecode, so there
is no easy way to "turn it on" in the LLInt. Also, right now there is no information
recorded about OSR exits or out-of-line stubs. But, even so, it's quite cool, and
gives you a peek into what JSC is doing that would otherwise not be possible.

  • CMakeLists.txt:
  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • Target.pri:
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::~CodeBlock):

  • bytecode/CodeBlock.h:

(CodeBlock):
(JSC::CodeBlock::baselineVersion):

  • bytecode/CodeOrigin.cpp:

(JSC::InlineCallFrame::baselineCodeBlock):
(JSC):

  • bytecode/CodeOrigin.h:

(InlineCallFrame):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGDisassembler.cpp:

(JSC::DFG::Disassembler::dump):
(DFG):
(JSC::DFG::Disassembler::reportToProfiler):
(JSC::DFG::Disassembler::dumpHeader):
(JSC::DFG::Disassembler::append):
(JSC::DFG::Disassembler::createDumpList):

  • dfg/DFGDisassembler.h:

(Disassembler):
(JSC::DFG::Disassembler::DumpedOp::DumpedOp):
(DumpedOp):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::Graph):
(JSC::DFG::Graph::dumpCodeOrigin):
(JSC::DFG::Graph::dump):

  • dfg/DFGGraph.h:

(Graph):

  • dfg/DFGJITCompiler.cpp:

(JSC::DFG::JITCompiler::JITCompiler):
(JSC::DFG::JITCompiler::compile):
(JSC::DFG::JITCompiler::compileFunction):

  • dfg/DFGNode.h:

(Node):
(JSC::DFG::Node::hasExecutionCounter):
(JSC::DFG::Node::executionCounter):

  • dfg/DFGNodeType.h:

(DFG):

  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • jit/JIT.cpp:

(JSC::JIT::JIT):
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompile):

  • jit/JIT.h:

(JIT):

  • jit/JITDisassembler.cpp:

(JSC::JITDisassembler::dump):
(JSC::JITDisassembler::reportToProfiler):
(JSC):
(JSC::JITDisassembler::dumpHeader):
(JSC::JITDisassembler::firstSlowLabel):
(JSC::JITDisassembler::dumpVectorForInstructions):
(JSC::JITDisassembler::dumpForInstructions):
(JSC::JITDisassembler::reportInstructions):

  • jit/JITDisassembler.h:

(JITDisassembler):
(DumpedOp):

  • jsc.cpp:

(CommandLine::CommandLine):
(CommandLine):
(printUsageStatement):
(CommandLine::parseArguments):
(jscmain):

  • profiler/ProfilerBytecode.cpp: Added.

(Profiler):
(JSC::Profiler::Bytecode::toJS):

  • profiler/ProfilerBytecode.h: Added.

(Profiler):
(Bytecode):
(JSC::Profiler::Bytecode::Bytecode):
(JSC::Profiler::Bytecode::bytecodeIndex):
(JSC::Profiler::Bytecode::description):
(JSC::Profiler::getBytecodeIndexForBytecode):

  • profiler/ProfilerBytecodes.cpp: Added.

(Profiler):
(JSC::Profiler::Bytecodes::Bytecodes):
(JSC::Profiler::Bytecodes::~Bytecodes):
(JSC::Profiler::Bytecodes::indexForBytecodeIndex):
(JSC::Profiler::Bytecodes::forBytecodeIndex):
(JSC::Profiler::Bytecodes::dump):
(JSC::Profiler::Bytecodes::toJS):

  • profiler/ProfilerBytecodes.h: Added.

(Profiler):
(Bytecodes):
(JSC::Profiler::Bytecodes::append):
(JSC::Profiler::Bytecodes::id):
(JSC::Profiler::Bytecodes::hash):
(JSC::Profiler::Bytecodes::size):
(JSC::Profiler::Bytecodes::at):

  • profiler/ProfilerCompilation.cpp: Added.

(Profiler):
(JSC::Profiler::Compilation::Compilation):
(JSC::Profiler::Compilation::~Compilation):
(JSC::Profiler::Compilation::addDescription):
(JSC::Profiler::Compilation::executionCounterFor):
(JSC::Profiler::Compilation::toJS):

  • profiler/ProfilerCompilation.h: Added.

(Profiler):
(Compilation):
(JSC::Profiler::Compilation::bytecodes):
(JSC::Profiler::Compilation::kind):

  • profiler/ProfilerCompilationKind.cpp: Added.

(WTF):
(WTF::printInternal):

  • profiler/ProfilerCompilationKind.h: Added.

(Profiler):
(WTF):

  • profiler/ProfilerCompiledBytecode.cpp: Added.

(Profiler):
(JSC::Profiler::CompiledBytecode::CompiledBytecode):
(JSC::Profiler::CompiledBytecode::~CompiledBytecode):
(JSC::Profiler::CompiledBytecode::toJS):

  • profiler/ProfilerCompiledBytecode.h: Added.

(Profiler):
(CompiledBytecode):
(JSC::Profiler::CompiledBytecode::originStack):
(JSC::Profiler::CompiledBytecode::description):

  • profiler/ProfilerDatabase.cpp: Added.

(Profiler):
(JSC::Profiler::Database::Database):
(JSC::Profiler::Database::~Database):
(JSC::Profiler::Database::addBytecodes):
(JSC::Profiler::Database::ensureBytecodesFor):
(JSC::Profiler::Database::notifyDestruction):
(JSC::Profiler::Database::newCompilation):
(JSC::Profiler::Database::toJS):
(JSC::Profiler::Database::toJSON):
(JSC::Profiler::Database::save):

  • profiler/ProfilerDatabase.h: Added.

(Profiler):
(Database):

  • profiler/ProfilerExecutionCounter.h: Added.

(Profiler):
(ExecutionCounter):
(JSC::Profiler::ExecutionCounter::ExecutionCounter):
(JSC::Profiler::ExecutionCounter::address):
(JSC::Profiler::ExecutionCounter::count):

  • profiler/ProfilerOrigin.cpp: Added.

(Profiler):
(JSC::Profiler::Origin::Origin):
(JSC::Profiler::Origin::dump):
(JSC::Profiler::Origin::toJS):

  • profiler/ProfilerOrigin.h: Added.

(JSC):
(Profiler):
(Origin):
(JSC::Profiler::Origin::Origin):
(JSC::Profiler::Origin::operator!):
(JSC::Profiler::Origin::bytecodes):
(JSC::Profiler::Origin::bytecodeIndex):
(JSC::Profiler::Origin::operator!=):
(JSC::Profiler::Origin::operator==):
(JSC::Profiler::Origin::hash):
(JSC::Profiler::Origin::isHashTableDeletedValue):
(JSC::Profiler::OriginHash::hash):
(JSC::Profiler::OriginHash::equal):
(OriginHash):
(WTF):

  • profiler/ProfilerOriginStack.cpp: Added.

(Profiler):
(JSC::Profiler::OriginStack::OriginStack):
(JSC::Profiler::OriginStack::~OriginStack):
(JSC::Profiler::OriginStack::append):
(JSC::Profiler::OriginStack::operator==):
(JSC::Profiler::OriginStack::hash):
(JSC::Profiler::OriginStack::dump):
(JSC::Profiler::OriginStack::toJS):

  • profiler/ProfilerOriginStack.h: Added.

(JSC):
(Profiler):
(OriginStack):
(JSC::Profiler::OriginStack::OriginStack):
(JSC::Profiler::OriginStack::operator!):
(JSC::Profiler::OriginStack::size):
(JSC::Profiler::OriginStack::fromBottom):
(JSC::Profiler::OriginStack::fromTop):
(JSC::Profiler::OriginStack::isHashTableDeletedValue):
(JSC::Profiler::OriginStackHash::hash):
(JSC::Profiler::OriginStackHash::equal):
(OriginStackHash):
(WTF):

  • runtime/CommonIdentifiers.h:
  • runtime/ExecutionHarness.h:

(JSC::prepareForExecution):
(JSC::prepareFunctionForExecution):

  • runtime/JSGlobalData.cpp:

(JSC::JSGlobalData::JSGlobalData):
(JSC::JSGlobalData::~JSGlobalData):

  • runtime/JSGlobalData.h:

(JSGlobalData):

  • runtime/Options.h:

(JSC):

Source/WTF:

Made some minor changes to support the new profiler. FileOutputStream now has an
open() method, and DataLog uses it. StringPrintStream has a reset() method, which
allows you to reuse the same StringPrintStream for creating multiple strings.
SegmentedVector now has a const operator[]. And, WTFString now can do fromUTF8() on
a CString directly.

  • wtf/DataLog.cpp:

(WTF::initializeLogFileOnce):

  • wtf/FilePrintStream.cpp:

(WTF::FilePrintStream::open):
(WTF):

  • wtf/FilePrintStream.h:
  • wtf/SegmentedVector.h:

(WTF::SegmentedVector::at):
(SegmentedVector):
(WTF::SegmentedVector::operator[]):

  • wtf/StringPrintStream.cpp:

(WTF::StringPrintStream::reset):
(WTF):

  • wtf/StringPrintStream.h:

(StringPrintStream):

  • wtf/text/WTFString.cpp:

(WTF::String::fromUTF8):
(WTF):

  • wtf/text/WTFString.h:

(String):

Tools:

Added a tool that allows you to grok the output from JSC's new profiler. Currently,
this still gets confused a bit about the execution counts of a method running
standalone versus a method running inlined, but other than that, it's pretty cool.
See the attached "sampling profiling session" attached to the bug to see it in
action.

Also had to feed EFL's build system.

  • DumpRenderTree/efl/CMakeLists.txt:
  • Scripts/display-profiler-output: Added.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/jit/JITDisassembler.cpp

    r136318 r136601  
    3232#include "CodeBlockWithJITType.h"
    3333#include "JIT.h"
     34#include <wtf/StringPrintStream.h>
    3435
    3536namespace JSC {
     
    4849void JITDisassembler::dump(PrintStream& out, LinkBuffer& linkBuffer)
    4950{
    50     out.print("Generated Baseline JIT code for ", CodeBlockWithJITType(m_codeBlock, JITCode::BaselineJIT), ", instruction count = ", m_codeBlock->instructionCount(), "\n");
    51     out.print("   Code at [", RawPointer(linkBuffer.debugAddress()), ", ", RawPointer(static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()), "):\n");
     51    dumpHeader(out, linkBuffer);
    5252    dumpDisassembly(out, linkBuffer, m_startOfCode, m_labelForBytecodeIndexInMainPath[0]);
    5353   
    54     MacroAssembler::Label firstSlowLabel;
    55     for (unsigned i = 0; i < m_labelForBytecodeIndexInSlowPath.size(); ++i) {
    56         if (m_labelForBytecodeIndexInSlowPath[i].isSet()) {
    57             firstSlowLabel = m_labelForBytecodeIndexInSlowPath[i];
    58             break;
    59         }
    60     }
    61     dumpForInstructions(out, linkBuffer, "    ", m_labelForBytecodeIndexInMainPath, firstSlowLabel.isSet() ? firstSlowLabel : m_endOfSlowPath);
     54    dumpForInstructions(out, linkBuffer, "    ", m_labelForBytecodeIndexInMainPath, firstSlowLabel());
    6255    out.print("    (End Of Main Path)\n");
    6356    dumpForInstructions(out, linkBuffer, "    (S) ", m_labelForBytecodeIndexInSlowPath, m_endOfSlowPath);
     
    7265}
    7366
    74 void JITDisassembler::dumpForInstructions(PrintStream& out, LinkBuffer& linkBuffer, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel)
     67void JITDisassembler::reportToProfiler(Profiler::Compilation* compilation, LinkBuffer& linkBuffer)
    7568{
    76     for (unsigned i = 0 ; i < labels.size();) {
     69    StringPrintStream out;
     70   
     71    dumpHeader(out, linkBuffer);
     72    compilation->addDescription(Profiler::CompiledBytecode(Profiler::OriginStack(), out.toCString()));
     73    out.reset();
     74    dumpDisassembly(out, linkBuffer, m_startOfCode, m_labelForBytecodeIndexInMainPath[0]);
     75    compilation->addDescription(Profiler::CompiledBytecode(Profiler::OriginStack(), out.toCString()));
     76   
     77    reportInstructions(compilation, linkBuffer, "    ", m_labelForBytecodeIndexInMainPath, firstSlowLabel());
     78    compilation->addDescription(Profiler::CompiledBytecode(Profiler::OriginStack(), "    (End Of Main Path)\n"));
     79    reportInstructions(compilation, linkBuffer, "    (S) ", m_labelForBytecodeIndexInSlowPath, m_endOfSlowPath);
     80    compilation->addDescription(Profiler::CompiledBytecode(Profiler::OriginStack(), "    (End Of Slow Path)\n"));
     81    out.reset();
     82    dumpDisassembly(out, linkBuffer, m_endOfSlowPath, m_endOfCode);
     83    compilation->addDescription(Profiler::CompiledBytecode(Profiler::OriginStack(), out.toCString()));
     84}
     85
     86void JITDisassembler::dumpHeader(PrintStream& out, LinkBuffer& linkBuffer)
     87{
     88    out.print("Generated Baseline JIT code for ", CodeBlockWithJITType(m_codeBlock, JITCode::BaselineJIT), ", instruction count = ", m_codeBlock->instructionCount(), "\n");
     89    out.print("   Code at [", RawPointer(linkBuffer.debugAddress()), ", ", RawPointer(static_cast<char*>(linkBuffer.debugAddress()) + linkBuffer.debugSize()), "):\n");
     90}
     91
     92MacroAssembler::Label JITDisassembler::firstSlowLabel()
     93{
     94    MacroAssembler::Label firstSlowLabel;
     95    for (unsigned i = 0; i < m_labelForBytecodeIndexInSlowPath.size(); ++i) {
     96        if (m_labelForBytecodeIndexInSlowPath[i].isSet()) {
     97            firstSlowLabel = m_labelForBytecodeIndexInSlowPath[i];
     98            break;
     99        }
     100    }
     101    return firstSlowLabel.isSet() ? firstSlowLabel : m_endOfSlowPath;
     102}
     103
     104Vector<JITDisassembler::DumpedOp> JITDisassembler::dumpVectorForInstructions(LinkBuffer& linkBuffer, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel)
     105{
     106    StringPrintStream out;
     107    Vector<DumpedOp> result;
     108   
     109    for (unsigned i = 0; i < labels.size();) {
    77110        if (!labels[i].isSet()) {
    78111            i++;
    79112            continue;
    80113        }
     114        out.reset();
     115        result.append(DumpedOp());
     116        result.last().index = i;
    81117        out.print(prefix);
    82118        m_codeBlock->dumpBytecode(out, i);
     
    84120            if (nextIndex >= labels.size()) {
    85121                dumpDisassembly(out, linkBuffer, labels[i], endLabel);
    86                 return;
     122                result.last().disassembly = out.toCString();
     123                return result;
    87124            }
    88125            if (labels[nextIndex].isSet()) {
    89126                dumpDisassembly(out, linkBuffer, labels[i], labels[nextIndex]);
     127                result.last().disassembly = out.toCString();
    90128                i = nextIndex;
    91129                break;
    92130            }
    93131        }
     132    }
     133   
     134    return result;
     135}
     136
     137void JITDisassembler::dumpForInstructions(PrintStream& out, LinkBuffer& linkBuffer, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel)
     138{
     139    Vector<DumpedOp> dumpedOps = dumpVectorForInstructions(linkBuffer, prefix, labels, endLabel);
     140   
     141    for (unsigned i = 0; i < dumpedOps.size(); ++i)
     142        out.print(dumpedOps[i].disassembly);
     143}
     144
     145void JITDisassembler::reportInstructions(Profiler::Compilation* compilation, LinkBuffer& linkBuffer, const char* prefix, Vector<MacroAssembler::Label>& labels, MacroAssembler::Label endLabel)
     146{
     147    Vector<DumpedOp> dumpedOps = dumpVectorForInstructions(linkBuffer, prefix, labels, endLabel);
     148   
     149    for (unsigned i = 0; i < dumpedOps.size(); ++i) {
     150        compilation->addDescription(
     151            Profiler::CompiledBytecode(
     152                Profiler::OriginStack(Profiler::Origin(compilation->bytecodes(), dumpedOps[i].index)),
     153                dumpedOps[i].disassembly));
    94154    }
    95155}
Note: See TracChangeset for help on using the changeset viewer.