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.
5 #ifndef V8_PROFILE_GENERATOR_H_
6 #define V8_PROFILE_GENERATOR_H_
8 #include "allocation.h"
10 #include "../include/v8-profiler.h"
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 {
21 explicit StringsStorage(Heap* heap);
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;
34 static const int kMaxNameSize = 1024;
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);
44 DISALLOW_COPY_AND_ASSIGN(StringsStorage);
50 // CodeEntry doesn't own name strings, just references them.
51 inline CodeEntry(Logger::LogEventsAndTags tag,
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 JITLineInfoTable* line_info = NULL);
60 bool is_js_function() const { return is_js_function_tag(tag_); }
61 const char* name_prefix() const { return name_prefix_; }
62 bool has_name_prefix() const { return name_prefix_[0] != '\0'; }
63 const char* name() const { return name_; }
64 const char* resource_name() const { return resource_name_; }
65 int line_number() const { return line_number_; }
66 int column_number() const { return column_number_; }
67 const JITLineInfoTable& line_info() const { return line_info_; }
68 void set_shared_id(int shared_id) { shared_id_ = shared_id; }
69 int script_id() const { return script_id_; }
70 void set_script_id(int script_id) { script_id_ = script_id; }
71 void set_bailout_reason(const char* bailout_reason) {
72 bailout_reason_ = bailout_reason;
74 const char* bailout_reason() const { return bailout_reason_; }
76 static inline bool is_js_function_tag(Logger::LogEventsAndTags tag);
78 List<OffsetRange>* no_frame_ranges() const { return no_frame_ranges_; }
79 void set_no_frame_ranges(List<OffsetRange>* ranges) {
80 no_frame_ranges_ = ranges;
83 void SetBuiltinId(Builtins::Name id);
84 Builtins::Name builtin_id() const { return builtin_id_; }
86 uint32_t GetCallUid() const;
87 bool IsSameAs(CodeEntry* entry) const;
89 static const char* const kEmptyNamePrefix;
90 static const char* const kEmptyResourceName;
91 static const char* const kEmptyBailoutReason;
94 Logger::LogEventsAndTags tag_ : 8;
95 Builtins::Name builtin_id_ : 8;
96 const char* name_prefix_;
98 const char* resource_name_;
101 JITLineInfoTable line_info_;
104 List<OffsetRange>* no_frame_ranges_;
105 const char* bailout_reason_;
107 DISALLOW_COPY_AND_ASSIGN(CodeEntry);
115 inline ProfileNode(ProfileTree* tree, CodeEntry* entry);
117 ProfileNode* FindChild(CodeEntry* entry);
118 ProfileNode* FindOrAddChild(CodeEntry* entry);
119 void IncrementSelfTicks() { ++self_ticks_; }
120 void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; }
121 void IncrementLineTicks(int src_line);
123 CodeEntry* entry() const { return entry_; }
124 unsigned self_ticks() const { return self_ticks_; }
125 const List<ProfileNode*>* children() const { return &children_list_; }
126 unsigned id() const { return id_; }
127 unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); }
128 bool GetLineTicks(LineTick* entries, unsigned int number) const;
130 void Print(int indent);
133 static bool CodeEntriesMatch(void* entry1, void* entry2) {
134 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs(
135 reinterpret_cast<CodeEntry*>(entry2));
138 static uint32_t CodeEntryHash(CodeEntry* entry) {
139 return entry->GetCallUid();
144 unsigned self_ticks_;
145 // Mapping from CodeEntry* to ProfileNode*
147 List<ProfileNode*> children_list_;
151 DISALLOW_COPY_AND_ASSIGN(ProfileNode);
160 ProfileNode* AddPathFromEnd(const Vector<CodeEntry*>& path,
161 int src_line = v8::CpuProfileNode::kNoLineNumberInfo);
162 void AddPathFromStart(const Vector<CodeEntry*>& path,
163 int src_line = v8::CpuProfileNode::kNoLineNumberInfo);
164 ProfileNode* root() const { return root_; }
165 unsigned next_node_id() { return next_node_id_++; }
172 template <typename Callback>
173 void TraverseDepthFirst(Callback* callback);
175 CodeEntry root_entry_;
176 unsigned next_node_id_;
179 DISALLOW_COPY_AND_ASSIGN(ProfileTree);
185 CpuProfile(const char* title, bool record_samples);
187 // Add pc -> ... -> main() call path to the profile.
188 void AddPath(TimeTicks timestamp, const Vector<CodeEntry*>& path,
190 void CalculateTotalTicksAndSamplingRate();
192 const char* title() const { return title_; }
193 const ProfileTree* top_down() const { return &top_down_; }
195 int samples_count() const { return samples_.length(); }
196 ProfileNode* sample(int index) const { return samples_.at(index); }
197 TimeTicks sample_timestamp(int index) const { return timestamps_.at(index); }
199 TimeTicks start_time() const { return start_time_; }
200 TimeTicks end_time() const { return end_time_; }
202 void UpdateTicksScale();
208 bool record_samples_;
209 TimeTicks start_time_;
211 List<ProfileNode*> samples_;
212 List<TimeTicks> timestamps_;
213 ProfileTree top_down_;
215 DISALLOW_COPY_AND_ASSIGN(CpuProfile);
221 CodeMap() : next_shared_id_(1) { }
222 void AddCode(Address addr, CodeEntry* entry, unsigned size);
223 void MoveCode(Address from, Address to);
224 CodeEntry* FindEntry(Address addr, Address* start = NULL);
225 int GetSharedId(Address addr);
230 struct CodeEntryInfo {
231 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
232 : entry(an_entry), size(a_size) { }
237 struct CodeTreeConfig {
239 typedef CodeEntryInfo Value;
240 static const Key kNoKey;
241 static const Value NoValue() { return CodeEntryInfo(NULL, 0); }
242 static int Compare(const Key& a, const Key& b) {
243 return a < b ? -1 : (a > b ? 1 : 0);
246 typedef SplayTree<CodeTreeConfig> CodeTree;
248 class CodeTreePrinter {
250 void Call(const Address& key, const CodeEntryInfo& value);
253 void DeleteAllCoveredCode(Address start, Address end);
255 // Fake CodeEntry pointer to distinguish shared function entries.
256 static CodeEntry* const kSharedFunctionCodeEntry;
261 DISALLOW_COPY_AND_ASSIGN(CodeMap);
265 class CpuProfilesCollection {
267 explicit CpuProfilesCollection(Heap* heap);
268 ~CpuProfilesCollection();
270 bool StartProfiling(const char* title, bool record_samples);
271 CpuProfile* StopProfiling(const char* title);
272 List<CpuProfile*>* profiles() { return &finished_profiles_; }
273 const char* GetName(Name* name) {
274 return function_and_resource_names_.GetName(name);
276 const char* GetName(int args_count) {
277 return function_and_resource_names_.GetName(args_count);
279 const char* GetFunctionName(Name* name) {
280 return function_and_resource_names_.GetFunctionName(name);
282 const char* GetFunctionName(const char* name) {
283 return function_and_resource_names_.GetFunctionName(name);
285 bool IsLastProfile(const char* title);
286 void RemoveProfile(CpuProfile* profile);
288 CodeEntry* NewCodeEntry(
289 Logger::LogEventsAndTags tag,
291 const char* name_prefix = CodeEntry::kEmptyNamePrefix,
292 const char* resource_name = CodeEntry::kEmptyResourceName,
293 int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
294 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo,
295 JITLineInfoTable* line_info = NULL);
297 // Called from profile generator thread.
298 void AddPathToCurrentProfiles(
299 TimeTicks timestamp, const Vector<CodeEntry*>& path, int src_line);
301 // Limits the number of profiles that can be simultaneously collected.
302 static const int kMaxSimultaneousProfiles = 100;
305 StringsStorage function_and_resource_names_;
306 List<CodeEntry*> code_entries_;
307 List<CpuProfile*> finished_profiles_;
309 // Accessed by VM thread and profile generator thread.
310 List<CpuProfile*> current_profiles_;
311 Semaphore current_profiles_semaphore_;
313 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
317 class ProfileGenerator {
319 explicit ProfileGenerator(CpuProfilesCollection* profiles);
321 void RecordTickSample(const TickSample& sample);
323 CodeMap* code_map() { return &code_map_; }
325 static const char* const kAnonymousFunctionName;
326 static const char* const kProgramEntryName;
327 static const char* const kIdleEntryName;
328 static const char* const kGarbageCollectorEntryName;
329 // Used to represent frames for which we have no reliable way to
331 static const char* const kUnresolvedFunctionName;
334 CodeEntry* EntryForVMState(StateTag tag);
336 CpuProfilesCollection* profiles_;
338 CodeEntry* program_entry_;
339 CodeEntry* idle_entry_;
340 CodeEntry* gc_entry_;
341 CodeEntry* unresolved_entry_;
343 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
347 } } // namespace v8::internal
349 #endif // V8_PROFILE_GENERATOR_H_