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