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 "include/v8-profiler.h" 9 #include "src/allocation.h" 10 #include "src/hashmap.h" 11 12 namespace v8 { 13 namespace internal { 14 15 struct OffsetRange; 16 17 // Provides a storage of strings allocated in C++ heap, to hold them 18 // forever, even if they disappear from JS heap or external storage. 19 class StringsStorage { 20 public: 21 explicit StringsStorage(Heap* heap); 22 ~StringsStorage(); 23 24 const char* GetCopy(const char* src); 25 const char* GetFormatted(const char* format, ...); 26 const char* GetVFormatted(const char* format, va_list args); 27 const char* GetName(Name* name); 28 const char* GetName(int index); 29 const char* GetFunctionName(Name* name); 30 const char* GetFunctionName(const char* name); 31 size_t GetUsedMemorySize() const; 32 33 private: 34 static const int kMaxNameSize = 1024; 35 36 static bool StringsMatch(void* key1, void* key2); 37 const char* AddOrDisposeString(char* str, int len); 38 HashMap::Entry* GetEntry(const char* str, int len); 39 40 uint32_t hash_seed_; 41 HashMap names_; 42 43 DISALLOW_COPY_AND_ASSIGN(StringsStorage); 44 }; 45 46 47 class CodeEntry { 48 public: 49 // CodeEntry doesn't own name strings, just references them. 50 inline CodeEntry(Logger::LogEventsAndTags tag, 51 const char* name, 52 const char* name_prefix = CodeEntry::kEmptyNamePrefix, 53 const char* resource_name = CodeEntry::kEmptyResourceName, 54 int line_number = v8::CpuProfileNode::kNoLineNumberInfo, 55 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo); 56 ~CodeEntry(); 57 is_js_function()58 bool is_js_function() const { return is_js_function_tag(tag_); } name_prefix()59 const char* name_prefix() const { return name_prefix_; } has_name_prefix()60 bool has_name_prefix() const { return name_prefix_[0] != '\0'; } name()61 const char* name() const { return name_; } resource_name()62 const char* resource_name() const { return resource_name_; } line_number()63 int line_number() const { return line_number_; } column_number()64 int column_number() const { return column_number_; } set_shared_id(int shared_id)65 void set_shared_id(int shared_id) { shared_id_ = shared_id; } script_id()66 int script_id() const { return script_id_; } set_script_id(int script_id)67 void set_script_id(int script_id) { script_id_ = script_id; } set_bailout_reason(const char * bailout_reason)68 void set_bailout_reason(const char* bailout_reason) { 69 bailout_reason_ = bailout_reason; 70 } bailout_reason()71 const char* bailout_reason() const { return bailout_reason_; } 72 73 static inline bool is_js_function_tag(Logger::LogEventsAndTags tag); 74 no_frame_ranges()75 List<OffsetRange>* no_frame_ranges() const { return no_frame_ranges_; } set_no_frame_ranges(List<OffsetRange> * ranges)76 void set_no_frame_ranges(List<OffsetRange>* ranges) { 77 no_frame_ranges_ = ranges; 78 } 79 80 void SetBuiltinId(Builtins::Name id); builtin_id()81 Builtins::Name builtin_id() const { return builtin_id_; } 82 83 uint32_t GetCallUid() const; 84 bool IsSameAs(CodeEntry* entry) const; 85 86 static const char* const kEmptyNamePrefix; 87 static const char* const kEmptyResourceName; 88 static const char* const kEmptyBailoutReason; 89 90 private: 91 Logger::LogEventsAndTags tag_ : 8; 92 Builtins::Name builtin_id_ : 8; 93 const char* name_prefix_; 94 const char* name_; 95 const char* resource_name_; 96 int line_number_; 97 int column_number_; 98 int shared_id_; 99 int script_id_; 100 List<OffsetRange>* no_frame_ranges_; 101 const char* bailout_reason_; 102 103 DISALLOW_COPY_AND_ASSIGN(CodeEntry); 104 }; 105 106 107 class ProfileTree; 108 109 class ProfileNode { 110 public: 111 inline ProfileNode(ProfileTree* tree, CodeEntry* entry); 112 113 ProfileNode* FindChild(CodeEntry* entry); 114 ProfileNode* FindOrAddChild(CodeEntry* entry); IncrementSelfTicks()115 void IncrementSelfTicks() { ++self_ticks_; } IncreaseSelfTicks(unsigned amount)116 void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; } 117 entry()118 CodeEntry* entry() const { return entry_; } self_ticks()119 unsigned self_ticks() const { return self_ticks_; } children()120 const List<ProfileNode*>* children() const { return &children_list_; } id()121 unsigned id() const { return id_; } 122 123 void Print(int indent); 124 125 private: CodeEntriesMatch(void * entry1,void * entry2)126 static bool CodeEntriesMatch(void* entry1, void* entry2) { 127 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs( 128 reinterpret_cast<CodeEntry*>(entry2)); 129 } 130 CodeEntryHash(CodeEntry * entry)131 static uint32_t CodeEntryHash(CodeEntry* entry) { 132 return entry->GetCallUid(); 133 } 134 135 ProfileTree* tree_; 136 CodeEntry* entry_; 137 unsigned self_ticks_; 138 // Mapping from CodeEntry* to ProfileNode* 139 HashMap children_; 140 List<ProfileNode*> children_list_; 141 unsigned id_; 142 143 DISALLOW_COPY_AND_ASSIGN(ProfileNode); 144 }; 145 146 147 class ProfileTree { 148 public: 149 ProfileTree(); 150 ~ProfileTree(); 151 152 ProfileNode* AddPathFromEnd(const Vector<CodeEntry*>& path); 153 void AddPathFromStart(const Vector<CodeEntry*>& path); root()154 ProfileNode* root() const { return root_; } next_node_id()155 unsigned next_node_id() { return next_node_id_++; } 156 Print()157 void Print() { 158 root_->Print(0); 159 } 160 161 private: 162 template <typename Callback> 163 void TraverseDepthFirst(Callback* callback); 164 165 CodeEntry root_entry_; 166 unsigned next_node_id_; 167 ProfileNode* root_; 168 169 DISALLOW_COPY_AND_ASSIGN(ProfileTree); 170 }; 171 172 173 class CpuProfile { 174 public: 175 CpuProfile(const char* title, bool record_samples); 176 177 // Add pc -> ... -> main() call path to the profile. 178 void AddPath(base::TimeTicks timestamp, const Vector<CodeEntry*>& path); 179 void CalculateTotalTicksAndSamplingRate(); 180 title()181 const char* title() const { return title_; } top_down()182 const ProfileTree* top_down() const { return &top_down_; } 183 samples_count()184 int samples_count() const { return samples_.length(); } sample(int index)185 ProfileNode* sample(int index) const { return samples_.at(index); } sample_timestamp(int index)186 base::TimeTicks sample_timestamp(int index) const { 187 return timestamps_.at(index); 188 } 189 start_time()190 base::TimeTicks start_time() const { return start_time_; } end_time()191 base::TimeTicks end_time() const { return end_time_; } 192 193 void UpdateTicksScale(); 194 195 void Print(); 196 197 private: 198 const char* title_; 199 bool record_samples_; 200 base::TimeTicks start_time_; 201 base::TimeTicks end_time_; 202 List<ProfileNode*> samples_; 203 List<base::TimeTicks> timestamps_; 204 ProfileTree top_down_; 205 206 DISALLOW_COPY_AND_ASSIGN(CpuProfile); 207 }; 208 209 210 class CodeMap { 211 public: CodeMap()212 CodeMap() : next_shared_id_(1) { } 213 void AddCode(Address addr, CodeEntry* entry, unsigned size); 214 void MoveCode(Address from, Address to); 215 CodeEntry* FindEntry(Address addr, Address* start = NULL); 216 int GetSharedId(Address addr); 217 218 void Print(); 219 220 private: 221 struct CodeEntryInfo { CodeEntryInfoCodeEntryInfo222 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) 223 : entry(an_entry), size(a_size) { } 224 CodeEntry* entry; 225 unsigned size; 226 }; 227 228 struct CodeTreeConfig { 229 typedef Address Key; 230 typedef CodeEntryInfo Value; 231 static const Key kNoKey; NoValueCodeTreeConfig232 static const Value NoValue() { return CodeEntryInfo(NULL, 0); } CompareCodeTreeConfig233 static int Compare(const Key& a, const Key& b) { 234 return a < b ? -1 : (a > b ? 1 : 0); 235 } 236 }; 237 typedef SplayTree<CodeTreeConfig> CodeTree; 238 239 class CodeTreePrinter { 240 public: 241 void Call(const Address& key, const CodeEntryInfo& value); 242 }; 243 244 void DeleteAllCoveredCode(Address start, Address end); 245 246 // Fake CodeEntry pointer to distinguish shared function entries. 247 static CodeEntry* const kSharedFunctionCodeEntry; 248 249 CodeTree tree_; 250 int next_shared_id_; 251 252 DISALLOW_COPY_AND_ASSIGN(CodeMap); 253 }; 254 255 256 class CpuProfilesCollection { 257 public: 258 explicit CpuProfilesCollection(Heap* heap); 259 ~CpuProfilesCollection(); 260 261 bool StartProfiling(const char* title, bool record_samples); 262 CpuProfile* StopProfiling(const char* title); profiles()263 List<CpuProfile*>* profiles() { return &finished_profiles_; } GetName(Name * name)264 const char* GetName(Name* name) { 265 return function_and_resource_names_.GetName(name); 266 } GetName(int args_count)267 const char* GetName(int args_count) { 268 return function_and_resource_names_.GetName(args_count); 269 } GetFunctionName(Name * name)270 const char* GetFunctionName(Name* name) { 271 return function_and_resource_names_.GetFunctionName(name); 272 } GetFunctionName(const char * name)273 const char* GetFunctionName(const char* name) { 274 return function_and_resource_names_.GetFunctionName(name); 275 } 276 bool IsLastProfile(const char* title); 277 void RemoveProfile(CpuProfile* profile); 278 279 CodeEntry* NewCodeEntry( 280 Logger::LogEventsAndTags tag, 281 const char* name, 282 const char* name_prefix = CodeEntry::kEmptyNamePrefix, 283 const char* resource_name = CodeEntry::kEmptyResourceName, 284 int line_number = v8::CpuProfileNode::kNoLineNumberInfo, 285 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo); 286 287 // Called from profile generator thread. 288 void AddPathToCurrentProfiles( 289 base::TimeTicks timestamp, const Vector<CodeEntry*>& path); 290 291 // Limits the number of profiles that can be simultaneously collected. 292 static const int kMaxSimultaneousProfiles = 100; 293 294 private: 295 StringsStorage function_and_resource_names_; 296 List<CodeEntry*> code_entries_; 297 List<CpuProfile*> finished_profiles_; 298 299 // Accessed by VM thread and profile generator thread. 300 List<CpuProfile*> current_profiles_; 301 base::Semaphore current_profiles_semaphore_; 302 303 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); 304 }; 305 306 307 class ProfileGenerator { 308 public: 309 explicit ProfileGenerator(CpuProfilesCollection* profiles); 310 311 void RecordTickSample(const TickSample& sample); 312 code_map()313 CodeMap* code_map() { return &code_map_; } 314 315 static const char* const kProgramEntryName; 316 static const char* const kIdleEntryName; 317 static const char* const kGarbageCollectorEntryName; 318 // Used to represent frames for which we have no reliable way to 319 // detect function. 320 static const char* const kUnresolvedFunctionName; 321 322 private: 323 CodeEntry* EntryForVMState(StateTag tag); 324 325 CpuProfilesCollection* profiles_; 326 CodeMap code_map_; 327 CodeEntry* program_entry_; 328 CodeEntry* idle_entry_; 329 CodeEntry* gc_entry_; 330 CodeEntry* unresolved_entry_; 331 332 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); 333 }; 334 335 336 } } // namespace v8::internal 337 338 #endif // V8_PROFILE_GENERATOR_H_ 339