profile-generator.h revision 3b9bc31999c9787eb726ecdbfd5796bfdec32a18
1// Copyright 2011 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef V8_PROFILER_PROFILE_GENERATOR_H_ 6#define V8_PROFILER_PROFILE_GENERATOR_H_ 7 8#include <map> 9#include "include/v8-profiler.h" 10#include "src/allocation.h" 11#include "src/compiler.h" 12#include "src/hashmap.h" 13#include "src/profiler/strings-storage.h" 14 15namespace v8 { 16namespace internal { 17 18// Provides a mapping from the offsets within generated code to 19// the source line. 20class JITLineInfoTable : public Malloced { 21 public: 22 JITLineInfoTable(); 23 ~JITLineInfoTable(); 24 25 void SetPosition(int pc_offset, int line); 26 int GetSourceLineNumber(int pc_offset) const; 27 28 bool empty() const { return pc_offset_map_.empty(); } 29 30 private: 31 // pc_offset -> source line 32 typedef std::map<int, int> PcOffsetMap; 33 PcOffsetMap pc_offset_map_; 34 DISALLOW_COPY_AND_ASSIGN(JITLineInfoTable); 35}; 36 37 38class CodeEntry { 39 public: 40 // CodeEntry doesn't own name strings, just references them. 41 inline CodeEntry(Logger::LogEventsAndTags tag, const char* name, 42 const char* name_prefix = CodeEntry::kEmptyNamePrefix, 43 const char* resource_name = CodeEntry::kEmptyResourceName, 44 int line_number = v8::CpuProfileNode::kNoLineNumberInfo, 45 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo, 46 JITLineInfoTable* line_info = NULL, 47 Address instruction_start = NULL); 48 ~CodeEntry(); 49 50 const char* name_prefix() const { return name_prefix_; } 51 bool has_name_prefix() const { return name_prefix_[0] != '\0'; } 52 const char* name() const { return name_; } 53 const char* resource_name() const { return resource_name_; } 54 int line_number() const { return line_number_; } 55 int column_number() const { return column_number_; } 56 const JITLineInfoTable* line_info() const { return line_info_; } 57 int script_id() const { return script_id_; } 58 void set_script_id(int script_id) { script_id_ = script_id; } 59 int position() const { return position_; } 60 void set_position(int position) { position_ = position; } 61 void set_bailout_reason(const char* bailout_reason) { 62 bailout_reason_ = bailout_reason; 63 } 64 const char* bailout_reason() const { return bailout_reason_; } 65 66 void set_deopt_info(const char* deopt_reason, SourcePosition position, 67 size_t pc_offset) { 68 DCHECK(deopt_position_.IsUnknown()); 69 deopt_reason_ = deopt_reason; 70 deopt_position_ = position; 71 pc_offset_ = pc_offset; 72 } 73 CpuProfileDeoptInfo GetDeoptInfo(); 74 const char* deopt_reason() const { return deopt_reason_; } 75 SourcePosition deopt_position() const { return deopt_position_; } 76 bool has_deopt_info() const { return !deopt_position_.IsUnknown(); } 77 void clear_deopt_info() { 78 deopt_reason_ = kNoDeoptReason; 79 deopt_position_ = SourcePosition::Unknown(); 80 } 81 82 void FillFunctionInfo(SharedFunctionInfo* shared); 83 84 void set_inlined_function_infos( 85 const std::vector<InlinedFunctionInfo>& infos) { 86 inlined_function_infos_ = infos; 87 } 88 const std::vector<InlinedFunctionInfo> inlined_function_infos() { 89 return inlined_function_infos_; 90 } 91 92 void SetBuiltinId(Builtins::Name id); 93 Builtins::Name builtin_id() const { 94 return BuiltinIdField::decode(bit_field_); 95 } 96 97 uint32_t GetHash() const; 98 bool IsSameFunctionAs(CodeEntry* entry) const; 99 100 int GetSourceLine(int pc_offset) const; 101 102 void AddInlineStack(int pc_offset, std::vector<CodeEntry*>& inline_stack); 103 const std::vector<CodeEntry*>* GetInlineStack(int pc_offset) const; 104 105 Address instruction_start() const { return instruction_start_; } 106 Logger::LogEventsAndTags tag() const { return TagField::decode(bit_field_); } 107 108 static const char* const kEmptyNamePrefix; 109 static const char* const kEmptyResourceName; 110 static const char* const kEmptyBailoutReason; 111 static const char* const kNoDeoptReason; 112 113 private: 114 class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {}; 115 class BuiltinIdField : public BitField<Builtins::Name, 8, 8> {}; 116 117 uint32_t bit_field_; 118 const char* name_prefix_; 119 const char* name_; 120 const char* resource_name_; 121 int line_number_; 122 int column_number_; 123 int script_id_; 124 int position_; 125 const char* bailout_reason_; 126 const char* deopt_reason_; 127 SourcePosition deopt_position_; 128 size_t pc_offset_; 129 JITLineInfoTable* line_info_; 130 Address instruction_start_; 131 // Should be an unordered_map, but it doesn't currently work on Win & MacOS. 132 std::map<int, std::vector<CodeEntry*>> inline_locations_; 133 134 std::vector<InlinedFunctionInfo> inlined_function_infos_; 135 136 DISALLOW_COPY_AND_ASSIGN(CodeEntry); 137}; 138 139 140class ProfileTree; 141 142class ProfileNode { 143 public: 144 inline ProfileNode(ProfileTree* tree, CodeEntry* entry); 145 146 ProfileNode* FindChild(CodeEntry* entry); 147 ProfileNode* FindOrAddChild(CodeEntry* entry); 148 void IncrementSelfTicks() { ++self_ticks_; } 149 void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; } 150 void IncrementLineTicks(int src_line); 151 152 CodeEntry* entry() const { return entry_; } 153 unsigned self_ticks() const { return self_ticks_; } 154 const List<ProfileNode*>* children() const { return &children_list_; } 155 unsigned id() const { return id_; } 156 unsigned function_id() const; 157 unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); } 158 bool GetLineTicks(v8::CpuProfileNode::LineTick* entries, 159 unsigned int length) const; 160 void CollectDeoptInfo(CodeEntry* entry); 161 const std::vector<CpuProfileDeoptInfo>& deopt_infos() const { 162 return deopt_infos_; 163 } 164 Isolate* isolate() const; 165 166 void Print(int indent); 167 168 static bool CodeEntriesMatch(void* entry1, void* entry2) { 169 return reinterpret_cast<CodeEntry*>(entry1) 170 ->IsSameFunctionAs(reinterpret_cast<CodeEntry*>(entry2)); 171 } 172 173 private: 174 static uint32_t CodeEntryHash(CodeEntry* entry) { return entry->GetHash(); } 175 176 static bool LineTickMatch(void* a, void* b) { return a == b; } 177 178 ProfileTree* tree_; 179 CodeEntry* entry_; 180 unsigned self_ticks_; 181 // Mapping from CodeEntry* to ProfileNode* 182 HashMap children_; 183 List<ProfileNode*> children_list_; 184 unsigned id_; 185 HashMap line_ticks_; 186 187 std::vector<CpuProfileDeoptInfo> deopt_infos_; 188 189 DISALLOW_COPY_AND_ASSIGN(ProfileNode); 190}; 191 192 193class ProfileTree { 194 public: 195 explicit ProfileTree(Isolate* isolate); 196 ~ProfileTree(); 197 198 ProfileNode* AddPathFromEnd( 199 const std::vector<CodeEntry*>& path, 200 int src_line = v8::CpuProfileNode::kNoLineNumberInfo, 201 bool update_stats = true); 202 ProfileNode* root() const { return root_; } 203 unsigned next_node_id() { return next_node_id_++; } 204 unsigned GetFunctionId(const ProfileNode* node); 205 206 void Print() { 207 root_->Print(0); 208 } 209 210 Isolate* isolate() const { return isolate_; } 211 212 private: 213 template <typename Callback> 214 void TraverseDepthFirst(Callback* callback); 215 216 CodeEntry root_entry_; 217 unsigned next_node_id_; 218 ProfileNode* root_; 219 Isolate* isolate_; 220 221 unsigned next_function_id_; 222 HashMap function_ids_; 223 224 DISALLOW_COPY_AND_ASSIGN(ProfileTree); 225}; 226 227 228class CpuProfile { 229 public: 230 CpuProfile(Isolate* isolate, const char* title, bool record_samples); 231 232 // Add pc -> ... -> main() call path to the profile. 233 void AddPath(base::TimeTicks timestamp, const std::vector<CodeEntry*>& path, 234 int src_line, bool update_stats); 235 void CalculateTotalTicksAndSamplingRate(); 236 237 const char* title() const { return title_; } 238 const ProfileTree* top_down() const { return &top_down_; } 239 240 int samples_count() const { return samples_.length(); } 241 ProfileNode* sample(int index) const { return samples_.at(index); } 242 base::TimeTicks sample_timestamp(int index) const { 243 return timestamps_.at(index); 244 } 245 246 base::TimeTicks start_time() const { return start_time_; } 247 base::TimeTicks end_time() const { return end_time_; } 248 249 void UpdateTicksScale(); 250 251 void Print(); 252 253 private: 254 const char* title_; 255 bool record_samples_; 256 base::TimeTicks start_time_; 257 base::TimeTicks end_time_; 258 List<ProfileNode*> samples_; 259 List<base::TimeTicks> timestamps_; 260 ProfileTree top_down_; 261 262 DISALLOW_COPY_AND_ASSIGN(CpuProfile); 263}; 264 265 266class CodeMap { 267 public: 268 CodeMap() {} 269 ~CodeMap(); 270 void AddCode(Address addr, CodeEntry* entry, unsigned size); 271 void MoveCode(Address from, Address to); 272 CodeEntry* FindEntry(Address addr); 273 int GetSharedId(Address addr); 274 275 void Print(); 276 277 private: 278 struct CodeEntryInfo { 279 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) 280 : entry(an_entry), size(a_size) { } 281 CodeEntry* entry; 282 unsigned size; 283 }; 284 285 struct CodeTreeConfig { 286 typedef Address Key; 287 typedef CodeEntryInfo Value; 288 static const Key kNoKey; 289 static const Value NoValue() { return CodeEntryInfo(NULL, 0); } 290 static int Compare(const Key& a, const Key& b) { 291 return a < b ? -1 : (a > b ? 1 : 0); 292 } 293 }; 294 typedef SplayTree<CodeTreeConfig> CodeTree; 295 296 class CodeTreePrinter { 297 public: 298 void Call(const Address& key, const CodeEntryInfo& value); 299 }; 300 301 void DeleteAllCoveredCode(Address start, Address end); 302 303 CodeTree tree_; 304 305 DISALLOW_COPY_AND_ASSIGN(CodeMap); 306}; 307 308 309class CpuProfilesCollection { 310 public: 311 explicit CpuProfilesCollection(Heap* heap); 312 ~CpuProfilesCollection(); 313 314 bool StartProfiling(const char* title, bool record_samples); 315 CpuProfile* StopProfiling(const char* title); 316 List<CpuProfile*>* profiles() { return &finished_profiles_; } 317 const char* GetName(Name* name) { 318 return function_and_resource_names_.GetName(name); 319 } 320 const char* GetName(int args_count) { 321 return function_and_resource_names_.GetName(args_count); 322 } 323 const char* GetFunctionName(Name* name) { 324 return function_and_resource_names_.GetFunctionName(name); 325 } 326 const char* GetFunctionName(const char* name) { 327 return function_and_resource_names_.GetFunctionName(name); 328 } 329 bool IsLastProfile(const char* title); 330 void RemoveProfile(CpuProfile* profile); 331 332 CodeEntry* NewCodeEntry( 333 Logger::LogEventsAndTags tag, const char* name, 334 const char* name_prefix = CodeEntry::kEmptyNamePrefix, 335 const char* resource_name = CodeEntry::kEmptyResourceName, 336 int line_number = v8::CpuProfileNode::kNoLineNumberInfo, 337 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo, 338 JITLineInfoTable* line_info = NULL, Address instruction_start = NULL); 339 340 // Called from profile generator thread. 341 void AddPathToCurrentProfiles(base::TimeTicks timestamp, 342 const std::vector<CodeEntry*>& path, 343 int src_line, bool update_stats); 344 345 // Limits the number of profiles that can be simultaneously collected. 346 static const int kMaxSimultaneousProfiles = 100; 347 348 private: 349 StringsStorage function_and_resource_names_; 350 List<CodeEntry*> code_entries_; 351 List<CpuProfile*> finished_profiles_; 352 353 Isolate* isolate_; 354 355 // Accessed by VM thread and profile generator thread. 356 List<CpuProfile*> current_profiles_; 357 base::Semaphore current_profiles_semaphore_; 358 359 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); 360}; 361 362 363class ProfileGenerator { 364 public: 365 explicit ProfileGenerator(CpuProfilesCollection* profiles); 366 367 void RecordTickSample(const TickSample& sample); 368 369 CodeMap* code_map() { return &code_map_; } 370 371 static const char* const kProgramEntryName; 372 static const char* const kIdleEntryName; 373 static const char* const kGarbageCollectorEntryName; 374 // Used to represent frames for which we have no reliable way to 375 // detect function. 376 static const char* const kUnresolvedFunctionName; 377 378 private: 379 CodeEntry* EntryForVMState(StateTag tag); 380 381 CpuProfilesCollection* profiles_; 382 CodeMap code_map_; 383 CodeEntry* program_entry_; 384 CodeEntry* idle_entry_; 385 CodeEntry* gc_entry_; 386 CodeEntry* unresolved_entry_; 387 388 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); 389}; 390 391 392} // namespace internal 393} // namespace v8 394 395#endif // V8_PROFILER_PROFILE_GENERATOR_H_ 396