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 15 namespace v8 { 16 namespace internal { 17 18 // Provides a mapping from the offsets within generated code to 19 // the source line. 20 class 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 38 class 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 135 class ProfileTree; 136 137 class 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 188 class 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 ProfileNode* root() const { return root_; } 197 unsigned next_node_id() { return next_node_id_++; } 198 unsigned GetFunctionId(const ProfileNode* node); 199 200 void Print() { 201 root_->Print(0); 202 } 203 204 Isolate* isolate() const { return isolate_; } 205 206 private: 207 template <typename Callback> 208 void TraverseDepthFirst(Callback* callback); 209 210 CodeEntry root_entry_; 211 unsigned next_node_id_; 212 ProfileNode* root_; 213 Isolate* isolate_; 214 215 unsigned next_function_id_; 216 HashMap function_ids_; 217 218 DISALLOW_COPY_AND_ASSIGN(ProfileTree); 219 }; 220 221 222 class CpuProfile { 223 public: 224 CpuProfile(Isolate* isolate, const char* title, bool record_samples); 225 226 // Add pc -> ... -> main() call path to the profile. 227 void AddPath(base::TimeTicks timestamp, const Vector<CodeEntry*>& path, 228 int src_line); 229 void CalculateTotalTicksAndSamplingRate(); 230 231 const char* title() const { return title_; } 232 const ProfileTree* top_down() const { return &top_down_; } 233 234 int samples_count() const { return samples_.length(); } 235 ProfileNode* sample(int index) const { return samples_.at(index); } 236 base::TimeTicks sample_timestamp(int index) const { 237 return timestamps_.at(index); 238 } 239 240 base::TimeTicks start_time() const { return start_time_; } 241 base::TimeTicks end_time() const { return end_time_; } 242 243 void UpdateTicksScale(); 244 245 void Print(); 246 247 private: 248 const char* title_; 249 bool record_samples_; 250 base::TimeTicks start_time_; 251 base::TimeTicks end_time_; 252 List<ProfileNode*> samples_; 253 List<base::TimeTicks> timestamps_; 254 ProfileTree top_down_; 255 256 DISALLOW_COPY_AND_ASSIGN(CpuProfile); 257 }; 258 259 260 class CodeMap { 261 public: 262 CodeMap() {} 263 ~CodeMap(); 264 void AddCode(Address addr, CodeEntry* entry, unsigned size); 265 void MoveCode(Address from, Address to); 266 CodeEntry* FindEntry(Address addr); 267 int GetSharedId(Address addr); 268 269 void Print(); 270 271 private: 272 struct CodeEntryInfo { 273 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) 274 : entry(an_entry), size(a_size) { } 275 CodeEntry* entry; 276 unsigned size; 277 }; 278 279 struct CodeTreeConfig { 280 typedef Address Key; 281 typedef CodeEntryInfo Value; 282 static const Key kNoKey; 283 static const Value NoValue() { return CodeEntryInfo(NULL, 0); } 284 static int Compare(const Key& a, const Key& b) { 285 return a < b ? -1 : (a > b ? 1 : 0); 286 } 287 }; 288 typedef SplayTree<CodeTreeConfig> CodeTree; 289 290 class CodeTreePrinter { 291 public: 292 void Call(const Address& key, const CodeEntryInfo& value); 293 }; 294 295 void DeleteAllCoveredCode(Address start, Address end); 296 297 CodeTree tree_; 298 299 DISALLOW_COPY_AND_ASSIGN(CodeMap); 300 }; 301 302 303 class CpuProfilesCollection { 304 public: 305 explicit CpuProfilesCollection(Heap* heap); 306 ~CpuProfilesCollection(); 307 308 bool StartProfiling(const char* title, bool record_samples); 309 CpuProfile* StopProfiling(const char* title); 310 List<CpuProfile*>* profiles() { return &finished_profiles_; } 311 const char* GetName(Name* name) { 312 return function_and_resource_names_.GetName(name); 313 } 314 const char* GetName(int args_count) { 315 return function_and_resource_names_.GetName(args_count); 316 } 317 const char* GetFunctionName(Name* name) { 318 return function_and_resource_names_.GetFunctionName(name); 319 } 320 const char* GetFunctionName(const char* name) { 321 return function_and_resource_names_.GetFunctionName(name); 322 } 323 bool IsLastProfile(const char* title); 324 void RemoveProfile(CpuProfile* profile); 325 326 CodeEntry* NewCodeEntry( 327 Logger::LogEventsAndTags tag, const char* name, 328 const char* name_prefix = CodeEntry::kEmptyNamePrefix, 329 const char* resource_name = CodeEntry::kEmptyResourceName, 330 int line_number = v8::CpuProfileNode::kNoLineNumberInfo, 331 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo, 332 JITLineInfoTable* line_info = NULL, Address instruction_start = NULL); 333 334 // Called from profile generator thread. 335 void AddPathToCurrentProfiles(base::TimeTicks timestamp, 336 const Vector<CodeEntry*>& path, int src_line); 337 338 // Limits the number of profiles that can be simultaneously collected. 339 static const int kMaxSimultaneousProfiles = 100; 340 341 private: 342 StringsStorage function_and_resource_names_; 343 List<CodeEntry*> code_entries_; 344 List<CpuProfile*> finished_profiles_; 345 346 Isolate* isolate_; 347 348 // Accessed by VM thread and profile generator thread. 349 List<CpuProfile*> current_profiles_; 350 base::Semaphore current_profiles_semaphore_; 351 352 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); 353 }; 354 355 356 class ProfileGenerator { 357 public: 358 explicit ProfileGenerator(CpuProfilesCollection* profiles); 359 360 void RecordTickSample(const TickSample& sample); 361 362 CodeMap* code_map() { return &code_map_; } 363 364 static const char* const kProgramEntryName; 365 static const char* const kIdleEntryName; 366 static const char* const kGarbageCollectorEntryName; 367 // Used to represent frames for which we have no reliable way to 368 // detect function. 369 static const char* const kUnresolvedFunctionName; 370 371 private: 372 CodeEntry* EntryForVMState(StateTag tag); 373 374 CpuProfilesCollection* profiles_; 375 CodeMap code_map_; 376 CodeEntry* program_entry_; 377 CodeEntry* idle_entry_; 378 CodeEntry* gc_entry_; 379 CodeEntry* unresolved_entry_; 380 381 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); 382 }; 383 384 385 } // namespace internal 386 } // namespace v8 387 388 #endif // V8_PROFILER_PROFILE_GENERATOR_H_ 389