blob: fdd87f336f18ddc5ed0c3a86f3a601a02adead0b [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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_PROFILER_PROFILE_GENERATOR_H_
6#define V8_PROFILER_PROFILE_GENERATOR_H_
7
8#include <map>
9#include "include/v8-profiler.h"
10#include "src/allocation.h"
Ben Murdoch61f157c2016-09-16 13:49:30 +010011#include "src/base/hashmap.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000012#include "src/compiler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/profiler/strings-storage.h"
14
15namespace v8 {
16namespace internal {
17
18// Provides a mapping from the offsets within generated code to
19// the source line.
20class JITLineInfoTable : public Malloced {
21 public:
22 JITLineInfoTable();
23 ~JITLineInfoTable();
24
25 void SetPosition(int pc_offset, int line);
26 int GetSourceLineNumber(int pc_offset) const;
27
28 bool empty() const { return pc_offset_map_.empty(); }
29
30 private:
31 // pc_offset -> source line
32 typedef std::map<int, int> PcOffsetMap;
33 PcOffsetMap pc_offset_map_;
34 DISALLOW_COPY_AND_ASSIGN(JITLineInfoTable);
35};
36
37
38class CodeEntry {
39 public:
40 // CodeEntry doesn't own name strings, just references them.
Ben Murdoch61f157c2016-09-16 13:49:30 +010041 inline CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000042 const char* name_prefix = CodeEntry::kEmptyNamePrefix,
43 const char* resource_name = CodeEntry::kEmptyResourceName,
44 int line_number = v8::CpuProfileNode::kNoLineNumberInfo,
45 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo,
46 JITLineInfoTable* line_info = NULL,
47 Address instruction_start = NULL);
48 ~CodeEntry();
49
Ben Murdochc5610432016-08-08 18:44:38 +010050 // Container describing inlined frames at eager deopt points. Is eventually
51 // being translated into v8::CpuProfileDeoptFrame by the profiler.
52 struct DeoptInlinedFrame {
53 int position;
54 int script_id;
55 };
56
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000057 const char* name_prefix() const { return name_prefix_; }
58 bool has_name_prefix() const { return name_prefix_[0] != '\0'; }
59 const char* name() const { return name_; }
60 const char* resource_name() const { return resource_name_; }
61 int line_number() const { return line_number_; }
62 int column_number() const { return column_number_; }
63 const JITLineInfoTable* line_info() const { return line_info_; }
64 int script_id() const { return script_id_; }
65 void set_script_id(int script_id) { script_id_ = script_id; }
66 int position() const { return position_; }
67 void set_position(int position) { position_ = position; }
68 void set_bailout_reason(const char* bailout_reason) {
69 bailout_reason_ = bailout_reason;
70 }
71 const char* bailout_reason() const { return bailout_reason_; }
72
73 void set_deopt_info(const char* deopt_reason, SourcePosition position,
Ben Murdochc5610432016-08-08 18:44:38 +010074 int deopt_id) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000075 DCHECK(deopt_position_.IsUnknown());
76 deopt_reason_ = deopt_reason;
77 deopt_position_ = position;
Ben Murdochc5610432016-08-08 18:44:38 +010078 deopt_id_ = deopt_id;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079 }
80 CpuProfileDeoptInfo GetDeoptInfo();
81 const char* deopt_reason() const { return deopt_reason_; }
82 SourcePosition deopt_position() const { return deopt_position_; }
83 bool has_deopt_info() const { return !deopt_position_.IsUnknown(); }
84 void clear_deopt_info() {
85 deopt_reason_ = kNoDeoptReason;
86 deopt_position_ = SourcePosition::Unknown();
87 }
88
89 void FillFunctionInfo(SharedFunctionInfo* shared);
90
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 void SetBuiltinId(Builtins::Name id);
92 Builtins::Name builtin_id() const {
93 return BuiltinIdField::decode(bit_field_);
94 }
95
96 uint32_t GetHash() const;
97 bool IsSameFunctionAs(CodeEntry* entry) const;
98
99 int GetSourceLine(int pc_offset) const;
100
Ben Murdochda12d292016-06-02 14:46:10 +0100101 void AddInlineStack(int pc_offset, std::vector<CodeEntry*>& inline_stack);
102 const std::vector<CodeEntry*>* GetInlineStack(int pc_offset) const;
103
Ben Murdochc5610432016-08-08 18:44:38 +0100104 void AddDeoptInlinedFrames(int deopt_id, std::vector<DeoptInlinedFrame>&);
105 bool HasDeoptInlinedFramesFor(int deopt_id) const;
106
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000107 Address instruction_start() const { return instruction_start_; }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100108 CodeEventListener::LogEventsAndTags tag() const {
109 return TagField::decode(bit_field_);
110 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111
112 static const char* const kEmptyNamePrefix;
113 static const char* const kEmptyResourceName;
114 static const char* const kEmptyBailoutReason;
115 static const char* const kNoDeoptReason;
116
Ben Murdoch61f157c2016-09-16 13:49:30 +0100117 static const char* const kProgramEntryName;
118 static const char* const kIdleEntryName;
119 static const char* const kGarbageCollectorEntryName;
120 // Used to represent frames for which we have no reliable way to
121 // detect function.
122 static const char* const kUnresolvedFunctionName;
123
124 V8_INLINE static CodeEntry* program_entry() {
125 return kProgramEntry.Pointer();
126 }
127 V8_INLINE static CodeEntry* idle_entry() { return kIdleEntry.Pointer(); }
128 V8_INLINE static CodeEntry* gc_entry() { return kGCEntry.Pointer(); }
129 V8_INLINE static CodeEntry* unresolved_entry() {
130 return kUnresolvedEntry.Pointer();
131 }
132
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000133 private:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100134 struct ProgramEntryCreateTrait {
135 static CodeEntry* Create();
136 };
137 struct IdleEntryCreateTrait {
138 static CodeEntry* Create();
139 };
140 struct GCEntryCreateTrait {
141 static CodeEntry* Create();
142 };
143 struct UnresolvedEntryCreateTrait {
144 static CodeEntry* Create();
145 };
146
147 static base::LazyDynamicInstance<CodeEntry, ProgramEntryCreateTrait>::type
148 kProgramEntry;
149 static base::LazyDynamicInstance<CodeEntry, IdleEntryCreateTrait>::type
150 kIdleEntry;
151 static base::LazyDynamicInstance<CodeEntry, GCEntryCreateTrait>::type
152 kGCEntry;
153 static base::LazyDynamicInstance<CodeEntry, UnresolvedEntryCreateTrait>::type
154 kUnresolvedEntry;
155
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156 class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {};
Ben Murdoch61f157c2016-09-16 13:49:30 +0100157 class BuiltinIdField : public BitField<Builtins::Name, 8, 24> {};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000158
159 uint32_t bit_field_;
160 const char* name_prefix_;
161 const char* name_;
162 const char* resource_name_;
163 int line_number_;
164 int column_number_;
165 int script_id_;
166 int position_;
167 const char* bailout_reason_;
168 const char* deopt_reason_;
169 SourcePosition deopt_position_;
Ben Murdochc5610432016-08-08 18:44:38 +0100170 int deopt_id_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000171 JITLineInfoTable* line_info_;
172 Address instruction_start_;
Ben Murdochda12d292016-06-02 14:46:10 +0100173 // Should be an unordered_map, but it doesn't currently work on Win & MacOS.
174 std::map<int, std::vector<CodeEntry*>> inline_locations_;
Ben Murdochc5610432016-08-08 18:44:38 +0100175 std::map<int, std::vector<DeoptInlinedFrame>> deopt_inlined_frames_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176
177 DISALLOW_COPY_AND_ASSIGN(CodeEntry);
178};
179
180
181class ProfileTree;
182
183class ProfileNode {
184 public:
185 inline ProfileNode(ProfileTree* tree, CodeEntry* entry);
186
187 ProfileNode* FindChild(CodeEntry* entry);
188 ProfileNode* FindOrAddChild(CodeEntry* entry);
189 void IncrementSelfTicks() { ++self_ticks_; }
190 void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; }
191 void IncrementLineTicks(int src_line);
192
193 CodeEntry* entry() const { return entry_; }
194 unsigned self_ticks() const { return self_ticks_; }
195 const List<ProfileNode*>* children() const { return &children_list_; }
196 unsigned id() const { return id_; }
197 unsigned function_id() const;
198 unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); }
199 bool GetLineTicks(v8::CpuProfileNode::LineTick* entries,
200 unsigned int length) const;
201 void CollectDeoptInfo(CodeEntry* entry);
202 const std::vector<CpuProfileDeoptInfo>& deopt_infos() const {
203 return deopt_infos_;
204 }
205 Isolate* isolate() const;
206
207 void Print(int indent);
208
209 static bool CodeEntriesMatch(void* entry1, void* entry2) {
210 return reinterpret_cast<CodeEntry*>(entry1)
211 ->IsSameFunctionAs(reinterpret_cast<CodeEntry*>(entry2));
212 }
213
214 private:
215 static uint32_t CodeEntryHash(CodeEntry* entry) { return entry->GetHash(); }
216
217 static bool LineTickMatch(void* a, void* b) { return a == b; }
218
219 ProfileTree* tree_;
220 CodeEntry* entry_;
221 unsigned self_ticks_;
222 // Mapping from CodeEntry* to ProfileNode*
Ben Murdoch61f157c2016-09-16 13:49:30 +0100223 base::HashMap children_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 List<ProfileNode*> children_list_;
225 unsigned id_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100226 base::HashMap line_ticks_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227
228 std::vector<CpuProfileDeoptInfo> deopt_infos_;
229
230 DISALLOW_COPY_AND_ASSIGN(ProfileNode);
231};
232
233
234class ProfileTree {
235 public:
236 explicit ProfileTree(Isolate* isolate);
237 ~ProfileTree();
238
239 ProfileNode* AddPathFromEnd(
Ben Murdochda12d292016-06-02 14:46:10 +0100240 const std::vector<CodeEntry*>& path,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100241 int src_line = v8::CpuProfileNode::kNoLineNumberInfo,
242 bool update_stats = true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000243 ProfileNode* root() const { return root_; }
244 unsigned next_node_id() { return next_node_id_++; }
245 unsigned GetFunctionId(const ProfileNode* node);
246
247 void Print() {
248 root_->Print(0);
249 }
250
251 Isolate* isolate() const { return isolate_; }
252
253 private:
254 template <typename Callback>
255 void TraverseDepthFirst(Callback* callback);
256
257 CodeEntry root_entry_;
258 unsigned next_node_id_;
259 ProfileNode* root_;
260 Isolate* isolate_;
261
262 unsigned next_function_id_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100263 base::HashMap function_ids_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264
265 DISALLOW_COPY_AND_ASSIGN(ProfileTree);
266};
267
268
269class CpuProfile {
270 public:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100271 CpuProfile(CpuProfiler* profiler, const char* title, bool record_samples);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000272
273 // Add pc -> ... -> main() call path to the profile.
Ben Murdochda12d292016-06-02 14:46:10 +0100274 void AddPath(base::TimeTicks timestamp, const std::vector<CodeEntry*>& path,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100275 int src_line, bool update_stats);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000276 void CalculateTotalTicksAndSamplingRate();
277
278 const char* title() const { return title_; }
279 const ProfileTree* top_down() const { return &top_down_; }
280
281 int samples_count() const { return samples_.length(); }
282 ProfileNode* sample(int index) const { return samples_.at(index); }
283 base::TimeTicks sample_timestamp(int index) const {
284 return timestamps_.at(index);
285 }
286
287 base::TimeTicks start_time() const { return start_time_; }
288 base::TimeTicks end_time() const { return end_time_; }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100289 CpuProfiler* cpu_profiler() const { return profiler_; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290
291 void UpdateTicksScale();
292
293 void Print();
294
295 private:
296 const char* title_;
297 bool record_samples_;
298 base::TimeTicks start_time_;
299 base::TimeTicks end_time_;
300 List<ProfileNode*> samples_;
301 List<base::TimeTicks> timestamps_;
302 ProfileTree top_down_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100303 CpuProfiler* const profiler_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000304
305 DISALLOW_COPY_AND_ASSIGN(CpuProfile);
306};
307
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000308class CodeMap {
309 public:
310 CodeMap() {}
Ben Murdoch61f157c2016-09-16 13:49:30 +0100311
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000312 void AddCode(Address addr, CodeEntry* entry, unsigned size);
313 void MoveCode(Address from, Address to);
314 CodeEntry* FindEntry(Address addr);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000315 void Print();
316
317 private:
318 struct CodeEntryInfo {
319 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
320 : entry(an_entry), size(a_size) { }
321 CodeEntry* entry;
322 unsigned size;
323 };
324
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000325 void DeleteAllCoveredCode(Address start, Address end);
326
Ben Murdoch61f157c2016-09-16 13:49:30 +0100327 std::map<Address, CodeEntryInfo> code_map_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000328
329 DISALLOW_COPY_AND_ASSIGN(CodeMap);
330};
331
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332class CpuProfilesCollection {
333 public:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100334 explicit CpuProfilesCollection(Isolate* isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335 ~CpuProfilesCollection();
336
Ben Murdoch61f157c2016-09-16 13:49:30 +0100337 void set_cpu_profiler(CpuProfiler* profiler) { profiler_ = profiler; }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338 bool StartProfiling(const char* title, bool record_samples);
339 CpuProfile* StopProfiling(const char* title);
340 List<CpuProfile*>* profiles() { return &finished_profiles_; }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100341 const char* GetName(Name* name) { return resource_names_.GetName(name); }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000342 bool IsLastProfile(const char* title);
343 void RemoveProfile(CpuProfile* profile);
344
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345 // Called from profile generator thread.
346 void AddPathToCurrentProfiles(base::TimeTicks timestamp,
Ben Murdochda12d292016-06-02 14:46:10 +0100347 const std::vector<CodeEntry*>& path,
348 int src_line, bool update_stats);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000349
350 // Limits the number of profiles that can be simultaneously collected.
351 static const int kMaxSimultaneousProfiles = 100;
352
353 private:
Ben Murdoch61f157c2016-09-16 13:49:30 +0100354 StringsStorage resource_names_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000355 List<CpuProfile*> finished_profiles_;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100356 CpuProfiler* profiler_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000357
358 // Accessed by VM thread and profile generator thread.
359 List<CpuProfile*> current_profiles_;
360 base::Semaphore current_profiles_semaphore_;
361
362 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
363};
364
365
366class ProfileGenerator {
367 public:
368 explicit ProfileGenerator(CpuProfilesCollection* profiles);
369
370 void RecordTickSample(const TickSample& sample);
371
372 CodeMap* code_map() { return &code_map_; }
373
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 private:
375 CodeEntry* EntryForVMState(StateTag tag);
376
377 CpuProfilesCollection* profiles_;
378 CodeMap code_map_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379
380 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
381};
382
383
384} // namespace internal
385} // namespace v8
386
387#endif // V8_PROFILER_PROFILE_GENERATOR_H_