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_
9 #include "include/v8-profiler.h"
10 #include "src/allocation.h"
11 #include "src/hashmap.h"
18 // Provides a storage of strings allocated in C++ heap, to hold them
19 // forever, even if they disappear from JS heap or external storage.
20 class StringsStorage {
22 explicit StringsStorage(Heap* heap);
25 const char* GetCopy(const char* src);
26 const char* GetFormatted(const char* format, ...);
27 const char* GetVFormatted(const char* format, va_list args);
28 const char* GetName(Name* name);
29 const char* GetName(int index);
30 const char* GetFunctionName(Name* name);
31 const char* GetFunctionName(const char* name);
32 size_t GetUsedMemorySize() const;
35 static const int kMaxNameSize = 1024;
37 static bool StringsMatch(void* key1, void* key2);
38 const char* AddOrDisposeString(char* str, int len);
39 HashMap::Entry* GetEntry(const char* str, int len);
44 DISALLOW_COPY_AND_ASSIGN(StringsStorage);
48 // Provides a mapping from the offsets within generated code to
50 class JITLineInfoTable : public Malloced {
55 void SetPosition(int pc_offset, int line);
56 int GetSourceLineNumber(int pc_offset) const;
58 bool empty() const { return pc_offset_map_.empty(); }
61 // pc_offset -> source line
62 typedef std::map<int, int> PcOffsetMap;
63 PcOffsetMap pc_offset_map_;
64 DISALLOW_COPY_AND_ASSIGN(JITLineInfoTable);
69 // CodeEntry doesn't own name strings, just references them.
70 inline CodeEntry(Logger::LogEventsAndTags tag,
72 const char* name_prefix = CodeEntry::kEmptyNamePrefix,
73 const char* resource_name = CodeEntry::kEmptyResourceName,
74 int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
75 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo,
76 JITLineInfoTable* line_info = NULL,
77 Address instruction_start = NULL);
80 bool is_js_function() const { return is_js_function_tag(tag_); }
81 const char* name_prefix() const { return name_prefix_; }
82 bool has_name_prefix() const { return name_prefix_[0] != '\0'; }
83 const char* name() const { return name_; }
84 const char* resource_name() const { return resource_name_; }
85 int line_number() const { return line_number_; }
86 int column_number() const { return column_number_; }
87 const JITLineInfoTable* line_info() const { return line_info_; }
88 void set_shared_id(int shared_id) { shared_id_ = shared_id; }
89 int script_id() const { return script_id_; }
90 void set_script_id(int script_id) { script_id_ = script_id; }
91 void set_bailout_reason(const char* bailout_reason) {
92 bailout_reason_ = bailout_reason;
94 const char* bailout_reason() const { return bailout_reason_; }
96 static inline bool is_js_function_tag(Logger::LogEventsAndTags tag);
98 List<OffsetRange>* no_frame_ranges() const { return no_frame_ranges_; }
99 void set_no_frame_ranges(List<OffsetRange>* ranges) {
100 no_frame_ranges_ = ranges;
103 void SetBuiltinId(Builtins::Name id);
104 Builtins::Name builtin_id() const { return builtin_id_; }
106 uint32_t GetCallUid() const;
107 bool IsSameAs(CodeEntry* entry) const;
109 int GetSourceLine(int pc_offset) const;
111 Address instruction_start() const { return instruction_start_; }
113 static const char* const kEmptyNamePrefix;
114 static const char* const kEmptyResourceName;
115 static const char* const kEmptyBailoutReason;
118 Logger::LogEventsAndTags tag_ : 8;
119 Builtins::Name builtin_id_ : 8;
120 const char* name_prefix_;
122 const char* resource_name_;
127 List<OffsetRange>* no_frame_ranges_;
128 const char* bailout_reason_;
129 JITLineInfoTable* line_info_;
130 Address instruction_start_;
132 DISALLOW_COPY_AND_ASSIGN(CodeEntry);
140 inline ProfileNode(ProfileTree* tree, CodeEntry* entry);
142 ProfileNode* FindChild(CodeEntry* entry);
143 ProfileNode* FindOrAddChild(CodeEntry* entry);
144 void IncrementSelfTicks() { ++self_ticks_; }
145 void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; }
146 void IncrementLineTicks(int src_line);
148 CodeEntry* entry() const { return entry_; }
149 unsigned self_ticks() const { return self_ticks_; }
150 const List<ProfileNode*>* children() const { return &children_list_; }
151 unsigned id() const { return id_; }
152 unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); }
153 bool GetLineTicks(v8::CpuProfileNode::LineTick* entries,
154 unsigned int length) const;
156 void Print(int indent);
159 static bool CodeEntriesMatch(void* entry1, void* entry2) {
160 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs(
161 reinterpret_cast<CodeEntry*>(entry2));
164 static uint32_t CodeEntryHash(CodeEntry* entry) {
165 return entry->GetCallUid();
170 unsigned self_ticks_;
171 // Mapping from CodeEntry* to ProfileNode*
173 List<ProfileNode*> children_list_;
177 DISALLOW_COPY_AND_ASSIGN(ProfileNode);
186 ProfileNode* AddPathFromEnd(
187 const Vector<CodeEntry*>& path,
188 int src_line = v8::CpuProfileNode::kNoLineNumberInfo);
189 void AddPathFromStart(const Vector<CodeEntry*>& path,
190 int src_line = v8::CpuProfileNode::kNoLineNumberInfo);
191 ProfileNode* root() const { return root_; }
192 unsigned next_node_id() { return next_node_id_++; }
199 template <typename Callback>
200 void TraverseDepthFirst(Callback* callback);
202 CodeEntry root_entry_;
203 unsigned next_node_id_;
206 DISALLOW_COPY_AND_ASSIGN(ProfileTree);
212 CpuProfile(const char* title, bool record_samples);
214 // Add pc -> ... -> main() call path to the profile.
215 void AddPath(base::TimeTicks timestamp,
216 const Vector<CodeEntry*>& path,
218 void CalculateTotalTicksAndSamplingRate();
220 const char* title() const { return title_; }
221 const ProfileTree* top_down() const { return &top_down_; }
223 int samples_count() const { return samples_.length(); }
224 ProfileNode* sample(int index) const { return samples_.at(index); }
225 base::TimeTicks sample_timestamp(int index) const {
226 return timestamps_.at(index);
229 base::TimeTicks start_time() const { return start_time_; }
230 base::TimeTicks end_time() const { return end_time_; }
232 void UpdateTicksScale();
238 bool record_samples_;
239 base::TimeTicks start_time_;
240 base::TimeTicks end_time_;
241 List<ProfileNode*> samples_;
242 List<base::TimeTicks> timestamps_;
243 ProfileTree top_down_;
245 DISALLOW_COPY_AND_ASSIGN(CpuProfile);
251 CodeMap() : next_shared_id_(1) { }
252 void AddCode(Address addr, CodeEntry* entry, unsigned size);
253 void MoveCode(Address from, Address to);
254 CodeEntry* FindEntry(Address addr, Address* start = NULL);
255 int GetSharedId(Address addr);
260 struct CodeEntryInfo {
261 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
262 : entry(an_entry), size(a_size) { }
267 struct CodeTreeConfig {
269 typedef CodeEntryInfo Value;
270 static const Key kNoKey;
271 static const Value NoValue() { return CodeEntryInfo(NULL, 0); }
272 static int Compare(const Key& a, const Key& b) {
273 return a < b ? -1 : (a > b ? 1 : 0);
276 typedef SplayTree<CodeTreeConfig> CodeTree;
278 class CodeTreePrinter {
280 void Call(const Address& key, const CodeEntryInfo& value);
283 void DeleteAllCoveredCode(Address start, Address end);
285 // Fake CodeEntry pointer to distinguish shared function entries.
286 static CodeEntry* const kSharedFunctionCodeEntry;
291 DISALLOW_COPY_AND_ASSIGN(CodeMap);
295 class CpuProfilesCollection {
297 explicit CpuProfilesCollection(Heap* heap);
298 ~CpuProfilesCollection();
300 bool StartProfiling(const char* title, bool record_samples);
301 CpuProfile* StopProfiling(const char* title);
302 List<CpuProfile*>* profiles() { return &finished_profiles_; }
303 const char* GetName(Name* name) {
304 return function_and_resource_names_.GetName(name);
306 const char* GetName(int args_count) {
307 return function_and_resource_names_.GetName(args_count);
309 const char* GetFunctionName(Name* name) {
310 return function_and_resource_names_.GetFunctionName(name);
312 const char* GetFunctionName(const char* name) {
313 return function_and_resource_names_.GetFunctionName(name);
315 bool IsLastProfile(const char* title);
316 void RemoveProfile(CpuProfile* profile);
318 CodeEntry* NewCodeEntry(
319 Logger::LogEventsAndTags tag,
321 const char* name_prefix = CodeEntry::kEmptyNamePrefix,
322 const char* resource_name = CodeEntry::kEmptyResourceName,
323 int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
324 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo,
325 JITLineInfoTable* line_info = NULL,
326 Address instruction_start = NULL);
328 // Called from profile generator thread.
329 void AddPathToCurrentProfiles(base::TimeTicks timestamp,
330 const Vector<CodeEntry*>& path,
333 // Limits the number of profiles that can be simultaneously collected.
334 static const int kMaxSimultaneousProfiles = 100;
337 StringsStorage function_and_resource_names_;
338 List<CodeEntry*> code_entries_;
339 List<CpuProfile*> finished_profiles_;
341 // Accessed by VM thread and profile generator thread.
342 List<CpuProfile*> current_profiles_;
343 base::Semaphore current_profiles_semaphore_;
345 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
349 class ProfileGenerator {
351 explicit ProfileGenerator(CpuProfilesCollection* profiles);
353 void RecordTickSample(const TickSample& sample);
355 CodeMap* code_map() { return &code_map_; }
357 static const char* const kProgramEntryName;
358 static const char* const kIdleEntryName;
359 static const char* const kGarbageCollectorEntryName;
360 // Used to represent frames for which we have no reliable way to
362 static const char* const kUnresolvedFunctionName;
365 CodeEntry* EntryForVMState(StateTag tag);
367 CpuProfilesCollection* profiles_;
369 CodeEntry* program_entry_;
370 CodeEntry* idle_entry_;
371 CodeEntry* gc_entry_;
372 CodeEntry* unresolved_entry_;
374 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
378 } } // namespace v8::internal
380 #endif // V8_PROFILE_GENERATOR_H_