PerfSpewer.h (8144B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef jit_PerfSpewer_h 8 #define jit_PerfSpewer_h 9 10 #ifdef JS_ION_PERF 11 # include <stdio.h> 12 #endif 13 #include "js/AllocPolicy.h" 14 #include "js/Vector.h" 15 16 #ifdef JS_JITSPEW 17 # include "jit/GraphSpewer.h" 18 #endif 19 20 class JSScript; 21 enum class JSOp : uint8_t; 22 23 namespace js { 24 25 namespace wasm { 26 struct OpBytes; 27 struct CodeMetadata; 28 } // namespace wasm 29 30 namespace jit { 31 32 class JitCode; 33 class BacktrackingAllocator; 34 class CompilerFrameInfo; 35 class MacroAssembler; 36 class MBasicBlock; 37 class MIRGraph; 38 class LInstruction; 39 enum class CacheOp : uint16_t; 40 41 struct AutoLockPerfSpewer { 42 AutoLockPerfSpewer(); 43 ~AutoLockPerfSpewer(); 44 }; 45 46 bool PerfEnabled(); 47 48 class PerfSpewer { 49 protected: 50 // An entry to insert into the DEBUG_INFO jitdump record. It maps from a code 51 // offset (relative to startOffset_) to a line number and column number. 52 struct DebugEntry { 53 constexpr DebugEntry() : offset(0), line(0), column(0) {} 54 constexpr DebugEntry(uint32_t offset_, uint32_t line_, uint32_t column_ = 0) 55 : offset(offset_), line(line_), column(column_) {} 56 57 uint32_t offset; 58 uint32_t line; 59 uint32_t column; 60 }; 61 62 // The debug records for this perf spewer. 63 Vector<DebugEntry, 0, SystemAllocPolicy> debugInfo_; 64 65 // The start offset that debugInfo_ is relative to. 66 uint32_t startOffset_ = 0; 67 68 // The generated IR file that we write into for IONPERF=ir. The move 69 // constructors assert that this file has been closed/finished. 70 FILE* irFile_ = nullptr; 71 uint32_t irFileLines_ = 0; 72 73 // The filename of irFile_. 74 JS::UniqueChars irFileName_; 75 76 virtual const char* CodeName(uint32_t op) = 0; 77 virtual const char* IRFileExtension() { return ".txt"; } 78 79 // Append an opcode to opcodes_ and the implicit debugInfo_ entry referencing 80 // it. 81 void recordOpcode(uint32_t offset, uint32_t opcode); 82 void recordOpcode(uint32_t offset, uint32_t opcode, JS::UniqueChars&& str); 83 void recordOpcode(uint32_t offset, JS::UniqueChars&& str); 84 85 // Save the debugInfo_ vector to the JIT dump file. 86 void saveDebugInfo(const char* filename, uintptr_t base, 87 AutoLockPerfSpewer& lock); 88 89 // Save the generated IR file, if any, and the debug info to the JIT dump 90 // file. 91 void saveJitCodeDebugInfo(JSScript* script, JitCode* code, 92 AutoLockPerfSpewer& lock); 93 94 // Save the generated IR file, if any, and the debug info to the JIT dump 95 // file. 96 void saveWasmCodeDebugInfo(uintptr_t codeBase, AutoLockPerfSpewer& lock); 97 98 void saveJSProfile(JitCode* code, JS::UniqueChars& desc, JSScript* script); 99 void saveWasmProfile(uintptr_t codeBase, size_t codeSize, 100 JS::UniqueChars& desc); 101 102 virtual void disable(AutoLockPerfSpewer& lock); 103 virtual void disable(); 104 105 public: 106 PerfSpewer() = default; 107 ~PerfSpewer(); 108 PerfSpewer(PerfSpewer&&); 109 PerfSpewer& operator=(PerfSpewer&&); 110 111 // Mark the start code offset that this perf spewer is relative to. 112 void markStartOffset(uint32_t offset) { startOffset_ = offset; } 113 114 // Start recording. This may create a temp file if we're recording IR. 115 virtual void startRecording(const wasm::CodeMetadata* wasmCodeMeta = nullptr); 116 117 // Finish recording and get ready for saving to jitdump, but do not yet 118 // write the debug info. 119 virtual void endRecording(); 120 121 void recordOffset(MacroAssembler& masm, const char*); 122 123 static void Init(); 124 125 static void CollectJitCodeInfo(JS::UniqueChars& function_name, JitCode* code, 126 AutoLockPerfSpewer& lock); 127 static void CollectJitCodeInfo(JS::UniqueChars& function_name, 128 void* code_addr, uint64_t code_size, 129 AutoLockPerfSpewer& lock); 130 }; 131 132 void CollectPerfSpewerJitCodeProfile(JitCode* code, const char* msg); 133 void CollectPerfSpewerJitCodeProfile(uintptr_t base, uint64_t size, 134 const char* msg); 135 136 void CollectPerfSpewerWasmMap(uintptr_t base, uintptr_t size, 137 JS::UniqueChars&& desc); 138 139 class IonPerfSpewer : public PerfSpewer { 140 const char* CodeName(uint32_t op) override; 141 const char* IRFileExtension() override; 142 143 void disable() override; 144 145 #ifdef JS_JITSPEW 146 Fprinter graphPrinter_; 147 UniqueGraphSpewer graphSpewer_ = nullptr; 148 #endif 149 150 public: 151 IonPerfSpewer() = default; 152 IonPerfSpewer(IonPerfSpewer&&) = default; 153 IonPerfSpewer& operator=(IonPerfSpewer&&) = default; 154 155 void startRecording( 156 const wasm::CodeMetadata* wasmCodeMeta = nullptr) override; 157 void endRecording() override; 158 159 void recordPass(const char* pass, MIRGraph* graph, 160 BacktrackingAllocator* ra = nullptr); 161 void recordInstruction(MacroAssembler& masm, LInstruction* ins); 162 163 void saveJSProfile(JSContext* cx, JSScript* script, JitCode* code); 164 void saveWasmProfile(uintptr_t codeBase, size_t codeSize, 165 JS::UniqueChars& desc); 166 }; 167 168 class WasmBaselinePerfSpewer : public PerfSpewer { 169 const char* CodeName(uint32_t op) override; 170 171 public: 172 WasmBaselinePerfSpewer() = default; 173 WasmBaselinePerfSpewer(WasmBaselinePerfSpewer&&) = default; 174 WasmBaselinePerfSpewer& operator=(WasmBaselinePerfSpewer&&) = default; 175 176 [[nodiscard]] bool needsToRecordInstruction() const; 177 void recordInstruction(MacroAssembler& masm, const wasm::OpBytes& op); 178 void saveProfile(uintptr_t codeBase, size_t codeSize, JS::UniqueChars& desc); 179 }; 180 181 class BaselineInterpreterPerfSpewer : public PerfSpewer { 182 // An opcode to insert into the generated IR source file. 183 struct Op { 184 uint32_t offset = 0; 185 uint32_t opcode = 0; 186 // This string is used to replace the opcode, to define things like 187 // Prologue/Epilogue, or to add operand info. 188 JS::UniqueChars str; 189 190 explicit Op(uint32_t offset_, uint32_t opcode_) 191 : offset(offset_), opcode(opcode_) {} 192 explicit Op(uint32_t offset_, JS::UniqueChars&& str_) 193 : offset(offset_), opcode(0), str(std::move(str_)) {} 194 195 Op(Op&& copy) { 196 offset = copy.offset; 197 opcode = copy.opcode; 198 str = std::move(copy.str); 199 } 200 201 // Do not copy the UniqueChars member. 202 Op(Op& copy) = delete; 203 }; 204 Vector<Op, 0, SystemAllocPolicy> ops_; 205 206 const char* CodeName(uint32_t op) override; 207 208 public: 209 void recordOffset(MacroAssembler& masm, const JSOp& op); 210 void recordOffset(MacroAssembler& masm, const char* name); 211 void saveProfile(JitCode* code); 212 }; 213 214 class BaselinePerfSpewer : public PerfSpewer { 215 const char* CodeName(uint32_t op) override; 216 217 public: 218 void recordInstruction(MacroAssembler& masm, jsbytecode* pc, JSScript* script, 219 CompilerFrameInfo& frame); 220 void saveProfile(JSContext* cx, JSScript* script, JitCode* code); 221 }; 222 223 class InlineCachePerfSpewer : public PerfSpewer { 224 const char* CodeName(uint32_t op) override; 225 226 public: 227 void recordInstruction(MacroAssembler& masm, const CacheOp& op); 228 }; 229 230 class BaselineICPerfSpewer : public InlineCachePerfSpewer { 231 public: 232 void saveProfile(JitCode* code, const char* stubName); 233 }; 234 235 class IonICPerfSpewer : public InlineCachePerfSpewer { 236 public: 237 explicit IonICPerfSpewer(JSScript* script, jsbytecode* pc); 238 239 void saveProfile(JSContext* cx, JSScript* script, JitCode* code, 240 const char* stubName); 241 }; 242 243 class PerfSpewerRangeRecorder { 244 using OffsetPair = std::tuple<uint32_t, JS::UniqueChars>; 245 Vector<OffsetPair, 0, js::SystemAllocPolicy> ranges; 246 247 MacroAssembler& masm; 248 249 void appendEntry(JS::UniqueChars& desc); 250 251 public: 252 explicit PerfSpewerRangeRecorder(MacroAssembler& masm_) : masm(masm_) {}; 253 254 void recordOffset(const char* name); 255 void recordOffset(const char* name, JSContext* cx, JSScript* script); 256 void recordVMWrapperOffset(const char* name); 257 void collectRangesForJitCode(JitCode* code); 258 }; 259 260 } // namespace jit 261 } // namespace js 262 263 #endif /* jit_PerfSpewer_h */