profile-generator.h revision 109988c7ccb6f3fd1a58574fa3dfb88beaef6632
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 Address instruction_start() const { return instruction_start_; } 103 104 static const char* const kEmptyNamePrefix; 105 static const char* const kEmptyResourceName; 106 static const char* const kEmptyBailoutReason; 107 static const char* const kNoDeoptReason; 108 109 private: 110 class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {}; 111 class BuiltinIdField : public BitField<Builtins::Name, 8, 8> {}; 112 Logger::LogEventsAndTags tag() const { return TagField::decode(bit_field_); } 113 114 uint32_t bit_field_; 115 const char* name_prefix_; 116 const char* name_; 117 const char* resource_name_; 118 int line_number_; 119 int column_number_; 120 int script_id_; 121 int position_; 122 const char* bailout_reason_; 123 const char* deopt_reason_; 124 SourcePosition deopt_position_; 125 size_t pc_offset_; 126 JITLineInfoTable* line_info_; 127 Address instruction_start_; 128 129 std::vector<InlinedFunctionInfo> inlined_function_infos_; 130 131 DISALLOW_COPY_AND_ASSIGN(CodeEntry); 132}; 133 134 135class ProfileTree; 136 137class ProfileNode { 138 public: 139 inline ProfileNode(ProfileTree* tree, CodeEntry* entry); 140 141 ProfileNode* FindChild(CodeEntry* entry); 142 ProfileNode* FindOrAddChild(CodeEntry* entry); 143 void IncrementSelfTicks() { ++self_ticks_; } 144 void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; } 145 void IncrementLineTicks(int src_line); 146 147 CodeEntry* entry() const { return entry_; } 148 unsigned self_ticks() const { return self_ticks_; } 149 const List<ProfileNode*>* children() const { return &children_list_; } 150 unsigned id() const { return id_; } 151 unsigned function_id() const; 152 unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); } 153 bool GetLineTicks(v8::CpuProfileNode::LineTick* entries, 154 unsigned int length) const; 155 void CollectDeoptInfo(CodeEntry* entry); 156 const std::vector<CpuProfileDeoptInfo>& deopt_infos() const { 157 return deopt_infos_; 158 } 159 Isolate* isolate() const; 160 161 void Print(int indent); 162 163 static bool CodeEntriesMatch(void* entry1, void* entry2) { 164 return reinterpret_cast<CodeEntry*>(entry1) 165 ->IsSameFunctionAs(reinterpret_cast<CodeEntry*>(entry2)); 166 } 167 168 private: 169 static uint32_t CodeEntryHash(CodeEntry* entry) { return entry->GetHash(); } 170 171 static bool LineTickMatch(void* a, void* b) { return a == b; } 172 173 ProfileTree* tree_; 174 CodeEntry* entry_; 175 unsigned self_ticks_; 176 // Mapping from CodeEntry* to ProfileNode* 177 HashMap children_; 178 List<ProfileNode*> children_list_; 179 unsigned id_; 180 HashMap line_ticks_; 181 182 std::vector<CpuProfileDeoptInfo> deopt_infos_; 183 184 DISALLOW_COPY_AND_ASSIGN(ProfileNode); 185}; 186 187 188class ProfileTree { 189 public: 190 explicit ProfileTree(Isolate* isolate); 191 ~ProfileTree(); 192 193 ProfileNode* AddPathFromEnd( 194 const Vector<CodeEntry*>& path, 195 int src_line = v8::CpuProfileNode::kNoLineNumberInfo, 196 bool update_stats = true); 197 ProfileNode* root() const { return root_; } 198 unsigned next_node_id() { return next_node_id_++; } 199 unsigned GetFunctionId(const ProfileNode* node); 200 201 void Print() { 202 root_->Print(0); 203 } 204 205 Isolate* isolate() const { return isolate_; } 206 207 private: 208 template <typename Callback> 209 void TraverseDepthFirst(Callback* callback); 210 211 CodeEntry root_entry_; 212 unsigned next_node_id_; 213 ProfileNode* root_; 214 Isolate* isolate_; 215 216 unsigned next_function_id_; 217 HashMap function_ids_; 218 219 DISALLOW_COPY_AND_ASSIGN(ProfileTree); 220}; 221 222 223class CpuProfile { 224 public: 225 CpuProfile(Isolate* isolate, const char* title, bool record_samples); 226 227 // Add pc -> ... -> main() call path to the profile. 228 void AddPath(base::TimeTicks timestamp, const Vector<CodeEntry*>& path, 229 int src_line, bool update_stats); 230 void CalculateTotalTicksAndSamplingRate(); 231 232 const char* title() const { return title_; } 233 const ProfileTree* top_down() const { return &top_down_; } 234 235 int samples_count() const { return samples_.length(); } 236 ProfileNode* sample(int index) const { return samples_.at(index); } 237 base::TimeTicks sample_timestamp(int index) const { 238 return timestamps_.at(index); 239 } 240 241 base::TimeTicks start_time() const { return start_time_; } 242 base::TimeTicks end_time() const { return end_time_; } 243 244 void UpdateTicksScale(); 245 246 void Print(); 247 248 private: 249 const char* title_; 250 bool record_samples_; 251 base::TimeTicks start_time_; 252 base::TimeTicks end_time_; 253 List<ProfileNode*> samples_; 254 List<base::TimeTicks> timestamps_; 255 ProfileTree top_down_; 256 257 DISALLOW_COPY_AND_ASSIGN(CpuProfile); 258}; 259 260 261class CodeMap { 262 public: 263 CodeMap() {} 264 ~CodeMap(); 265 void AddCode(Address addr, CodeEntry* entry, unsigned size); 266 void MoveCode(Address from, Address to); 267 CodeEntry* FindEntry(Address addr); 268 int GetSharedId(Address addr); 269 270 void Print(); 271 272 private: 273 struct CodeEntryInfo { 274 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) 275 : entry(an_entry), size(a_size) { } 276 CodeEntry* entry; 277 unsigned size; 278 }; 279 280 struct CodeTreeConfig { 281 typedef Address Key; 282 typedef CodeEntryInfo Value; 283 static const Key kNoKey; 284 static const Value NoValue() { return CodeEntryInfo(NULL, 0); } 285 static int Compare(const Key& a, const Key& b) { 286 return a < b ? -1 : (a > b ? 1 : 0); 287 } 288 }; 289 typedef SplayTree<CodeTreeConfig> CodeTree; 290 291 class CodeTreePrinter { 292 public: 293 void Call(const Address& key, const CodeEntryInfo& value); 294 }; 295 296 void DeleteAllCoveredCode(Address start, Address end); 297 298 CodeTree tree_; 299 300 DISALLOW_COPY_AND_ASSIGN(CodeMap); 301}; 302 303 304class CpuProfilesCollection { 305 public: 306 explicit CpuProfilesCollection(Heap* heap); 307 ~CpuProfilesCollection(); 308 309 bool StartProfiling(const char* title, bool record_samples); 310 CpuProfile* StopProfiling(const char* title); 311 List<CpuProfile*>* profiles() { return &finished_profiles_; } 312 const char* GetName(Name* name) { 313 return function_and_resource_names_.GetName(name); 314 } 315 const char* GetName(int args_count) { 316 return function_and_resource_names_.GetName(args_count); 317 } 318 const char* GetFunctionName(Name* name) { 319 return function_and_resource_names_.GetFunctionName(name); 320 } 321 const char* GetFunctionName(const char* name) { 322 return function_and_resource_names_.GetFunctionName(name); 323 } 324 bool IsLastProfile(const char* title); 325 void RemoveProfile(CpuProfile* profile); 326 327 CodeEntry* NewCodeEntry( 328 Logger::LogEventsAndTags tag, const char* name, 329 const char* name_prefix = CodeEntry::kEmptyNamePrefix, 330 const char* resource_name = CodeEntry::kEmptyResourceName, 331 int line_number = v8::CpuProfileNode::kNoLineNumberInfo, 332 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo, 333 JITLineInfoTable* line_info = NULL, Address instruction_start = NULL); 334 335 // Called from profile generator thread. 336 void AddPathToCurrentProfiles(base::TimeTicks timestamp, 337 const Vector<CodeEntry*>& path, int src_line, 338 bool update_stats); 339 340 // Limits the number of profiles that can be simultaneously collected. 341 static const int kMaxSimultaneousProfiles = 100; 342 343 private: 344 StringsStorage function_and_resource_names_; 345 List<CodeEntry*> code_entries_; 346 List<CpuProfile*> finished_profiles_; 347 348 Isolate* isolate_; 349 350 // Accessed by VM thread and profile generator thread. 351 List<CpuProfile*> current_profiles_; 352 base::Semaphore current_profiles_semaphore_; 353 354 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); 355}; 356 357 358class ProfileGenerator { 359 public: 360 explicit ProfileGenerator(CpuProfilesCollection* profiles); 361 362 void RecordTickSample(const TickSample& sample); 363 364 CodeMap* code_map() { return &code_map_; } 365 366 static const char* const kProgramEntryName; 367 static const char* const kIdleEntryName; 368 static const char* const kGarbageCollectorEntryName; 369 // Used to represent frames for which we have no reliable way to 370 // detect function. 371 static const char* const kUnresolvedFunctionName; 372 373 private: 374 CodeEntry* EntryForVMState(StateTag tag); 375 376 CpuProfilesCollection* profiles_; 377 CodeMap code_map_; 378 CodeEntry* program_entry_; 379 CodeEntry* idle_entry_; 380 CodeEntry* gc_entry_; 381 CodeEntry* unresolved_entry_; 382 383 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); 384}; 385 386 387} // namespace internal 388} // namespace v8 389 390#endif // V8_PROFILER_PROFILE_GENERATOR_H_ 391