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