Changeset 211316 in webkit
- Timestamp:
- Jan 27, 2017, 5:04:06 PM (10 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 5 edited
-
ChangeLog (modified) (1 diff)
-
inspector/agents/InspectorScriptProfilerAgent.cpp (modified) (1 diff)
-
runtime/Options.h (modified) (1 diff)
-
runtime/SamplingProfiler.cpp (modified) (11 diffs)
-
runtime/SamplingProfiler.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r211306 r211316 1 2017-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 1 33 2017-01-27 Yusuke Suzuki <utatane.tea@gmail.com> 2 34 -
trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp
r210042 r211316 181 181 if (stackFrame.hasExpressionInfo()) { 182 182 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()) 185 185 .release(); 186 186 frame->setExpressionLocation(WTFMove(expressionLocation)); -
trunk/Source/JavaScriptCore/runtime/Options.h
r211069 r211316 362 362 v(unsigned, sampleInterval, 1000, Normal, "Time between stack traces in microseconds.") \ 363 363 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.") \ 364 366 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.") \ 365 367 \ -
trunk/Source/JavaScriptCore/runtime/SamplingProfiler.cpp
r211247 r211316 45 45 #include "PCToCodeOriginMap.h" 46 46 #include "SlotVisitor.h" 47 #include "StrongInlines.h" 47 48 #include "VM.h" 48 49 #include <wtf/HashSet.h> … … 364 365 stackTrace.timestamp = unprocessedStackTrace.timestamp; 365 366 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) { 370 368 if (bytecodeIndex < codeBlock->instructionCount()) { 371 369 int divot; … … 373 371 int endOffset; 374 372 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; 377 375 } 378 376 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); 382 386 }; 383 387 … … 386 390 }; 387 391 388 auto storeCalleeInto TopFrame = [&] (EncodedJSValue encodedCallee) {392 auto storeCalleeIntoLastFrame = [&] (EncodedJSValue encodedCallee) { 389 393 // Set the callee if it's a valid GC object. 390 394 JSValue callee = JSValue::decode(encodedCallee); … … 442 446 }; 443 447 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 }; 444 472 445 473 // Prepend the top-most inlined frame if needed and gather … … 469 497 470 498 appendCodeBlock(topCodeBlock, bytecodeIndex); 471 storeCalleeInto TopFrame(unprocessedStackTrace.frames[0].unverifiedCallee);499 storeCalleeIntoLastFrame(unprocessedStackTrace.frames[0].unverifiedCallee); 472 500 startIndex = 1; 473 501 } 474 502 } 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); 479 505 startIndex = 1; 480 506 } … … 493 519 #if ENABLE(DFG_JIT) 494 520 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 500 524 appendCodeBlock(codeBlock, std::numeric_limits<unsigned>::max()); 501 525 } else … … 509 533 // Note that this is okay to do if we walked the inline stack because 510 534 // the machine frame will be at the top of the processed stack trace. 511 storeCalleeInto TopFrame(unprocessedStackFrame.unverifiedCallee);535 storeCalleeIntoLastFrame(unprocessedStackFrame.unverifiedCallee); 512 536 } 513 537 } … … 844 868 }; 845 869 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 } 854 880 } 855 881 } … … 874 900 continue; 875 901 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 876 920 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 } 892 926 bytecodeCounts.add(frameDescription, 0).iterator->value++; 893 927 } … … 907 941 }; 908 942 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 } 917 953 } 918 954 } -
trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h
r206525 r211316 81 81 ExecutableBase* executable { nullptr }; 82 82 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 91 114 { 92 return lineNumber != std::numeric_limits<unsigned>::max()93 && columnNumber != std::numeric_limits<unsigned>::max();115 ASSERT(hasExpressionInfo()); 116 return semanticLocation.lineNumber; 94 117 } 95 96 bool hasBytecodeIndex() const 118 unsigned columnNumber() const 97 119 { 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; 104 122 } 105 123
Note:
See TracChangeset
for help on using the changeset viewer.