OLD | NEW |
| (Empty) |
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 <map> | |
9 #include "include/v8-profiler.h" | |
10 #include "src/allocation.h" | |
11 #include "src/compiler.h" | |
12 #include "src/hashmap.h" | |
13 #include "src/strings-storage.h" | |
14 | |
15 namespace v8 { | |
16 namespace internal { | |
17 | |
18 struct OffsetRange; | |
19 | |
20 // Provides a mapping from the offsets within generated code to | |
21 // the source line. | |
22 class JITLineInfoTable : public Malloced { | |
23 public: | |
24 JITLineInfoTable(); | |
25 ~JITLineInfoTable(); | |
26 | |
27 void SetPosition(int pc_offset, int line); | |
28 int GetSourceLineNumber(int pc_offset) const; | |
29 | |
30 bool empty() const { return pc_offset_map_.empty(); } | |
31 | |
32 private: | |
33 // pc_offset -> source line | |
34 typedef std::map<int, int> PcOffsetMap; | |
35 PcOffsetMap pc_offset_map_; | |
36 DISALLOW_COPY_AND_ASSIGN(JITLineInfoTable); | |
37 }; | |
38 | |
39 | |
40 class CodeEntry { | |
41 public: | |
42 // CodeEntry doesn't own name strings, just references them. | |
43 inline CodeEntry(Logger::LogEventsAndTags tag, const char* name, | |
44 const char* name_prefix = CodeEntry::kEmptyNamePrefix, | |
45 const char* resource_name = CodeEntry::kEmptyResourceName, | |
46 int line_number = v8::CpuProfileNode::kNoLineNumberInfo, | |
47 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo, | |
48 JITLineInfoTable* line_info = NULL, | |
49 Address instruction_start = NULL); | |
50 ~CodeEntry(); | |
51 | |
52 const char* name_prefix() const { return name_prefix_; } | |
53 bool has_name_prefix() const { return name_prefix_[0] != '\0'; } | |
54 const char* name() const { return name_; } | |
55 const char* resource_name() const { return resource_name_; } | |
56 int line_number() const { return line_number_; } | |
57 int column_number() const { return column_number_; } | |
58 const JITLineInfoTable* line_info() const { return line_info_; } | |
59 int script_id() const { return script_id_; } | |
60 void set_script_id(int script_id) { script_id_ = script_id; } | |
61 int position() const { return position_; } | |
62 void set_position(int position) { position_ = position; } | |
63 void set_bailout_reason(const char* bailout_reason) { | |
64 bailout_reason_ = bailout_reason; | |
65 } | |
66 const char* bailout_reason() const { return bailout_reason_; } | |
67 | |
68 void set_deopt_info(const char* deopt_reason, SourcePosition position, | |
69 size_t pc_offset) { | |
70 DCHECK(deopt_position_.IsUnknown()); | |
71 deopt_reason_ = deopt_reason; | |
72 deopt_position_ = position; | |
73 pc_offset_ = pc_offset; | |
74 } | |
75 CpuProfileDeoptInfo GetDeoptInfo(); | |
76 const char* deopt_reason() const { return deopt_reason_; } | |
77 SourcePosition deopt_position() const { return deopt_position_; } | |
78 bool has_deopt_info() const { return !deopt_position_.IsUnknown(); } | |
79 void clear_deopt_info() { | |
80 deopt_reason_ = kNoDeoptReason; | |
81 deopt_position_ = SourcePosition::Unknown(); | |
82 } | |
83 | |
84 void FillFunctionInfo(SharedFunctionInfo* shared); | |
85 | |
86 List<OffsetRange>* no_frame_ranges() const { return no_frame_ranges_; } | |
87 void set_no_frame_ranges(List<OffsetRange>* ranges) { | |
88 no_frame_ranges_ = ranges; | |
89 } | |
90 void set_inlined_function_infos( | |
91 const std::vector<InlinedFunctionInfo>& infos) { | |
92 inlined_function_infos_ = infos; | |
93 } | |
94 const std::vector<InlinedFunctionInfo> inlined_function_infos() { | |
95 return inlined_function_infos_; | |
96 } | |
97 | |
98 void SetBuiltinId(Builtins::Name id); | |
99 Builtins::Name builtin_id() const { | |
100 return BuiltinIdField::decode(bit_field_); | |
101 } | |
102 | |
103 uint32_t GetHash() const; | |
104 bool IsSameFunctionAs(CodeEntry* entry) const; | |
105 | |
106 int GetSourceLine(int pc_offset) const; | |
107 | |
108 Address instruction_start() const { return instruction_start_; } | |
109 | |
110 static const char* const kEmptyNamePrefix; | |
111 static const char* const kEmptyResourceName; | |
112 static const char* const kEmptyBailoutReason; | |
113 static const char* const kNoDeoptReason; | |
114 | |
115 private: | |
116 class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {}; | |
117 class BuiltinIdField : public BitField<Builtins::Name, 8, 8> {}; | |
118 Logger::LogEventsAndTags tag() const { return TagField::decode(bit_field_); } | |
119 | |
120 uint32_t bit_field_; | |
121 const char* name_prefix_; | |
122 const char* name_; | |
123 const char* resource_name_; | |
124 int line_number_; | |
125 int column_number_; | |
126 int script_id_; | |
127 int position_; | |
128 List<OffsetRange>* no_frame_ranges_; | |
129 const char* bailout_reason_; | |
130 const char* deopt_reason_; | |
131 SourcePosition deopt_position_; | |
132 size_t pc_offset_; | |
133 JITLineInfoTable* line_info_; | |
134 Address instruction_start_; | |
135 | |
136 std::vector<InlinedFunctionInfo> inlined_function_infos_; | |
137 | |
138 DISALLOW_COPY_AND_ASSIGN(CodeEntry); | |
139 }; | |
140 | |
141 | |
142 class ProfileTree; | |
143 | |
144 class ProfileNode { | |
145 public: | |
146 inline ProfileNode(ProfileTree* tree, CodeEntry* entry); | |
147 | |
148 ProfileNode* FindChild(CodeEntry* entry); | |
149 ProfileNode* FindOrAddChild(CodeEntry* entry); | |
150 void IncrementSelfTicks() { ++self_ticks_; } | |
151 void IncreaseSelfTicks(unsigned amount) { self_ticks_ += amount; } | |
152 void IncrementLineTicks(int src_line); | |
153 | |
154 CodeEntry* entry() const { return entry_; } | |
155 unsigned self_ticks() const { return self_ticks_; } | |
156 const List<ProfileNode*>* children() const { return &children_list_; } | |
157 unsigned id() const { return id_; } | |
158 unsigned function_id() const; | |
159 unsigned int GetHitLineCount() const { return line_ticks_.occupancy(); } | |
160 bool GetLineTicks(v8::CpuProfileNode::LineTick* entries, | |
161 unsigned int length) const; | |
162 void CollectDeoptInfo(CodeEntry* entry); | |
163 const std::vector<CpuProfileDeoptInfo>& deopt_infos() const { | |
164 return deopt_infos_; | |
165 } | |
166 | |
167 void Print(int indent); | |
168 | |
169 static bool CodeEntriesMatch(void* entry1, void* entry2) { | |
170 return reinterpret_cast<CodeEntry*>(entry1) | |
171 ->IsSameFunctionAs(reinterpret_cast<CodeEntry*>(entry2)); | |
172 } | |
173 | |
174 private: | |
175 static uint32_t CodeEntryHash(CodeEntry* entry) { return entry->GetHash(); } | |
176 | |
177 static bool LineTickMatch(void* a, void* b) { return a == b; } | |
178 | |
179 ProfileTree* tree_; | |
180 CodeEntry* entry_; | |
181 unsigned self_ticks_; | |
182 // Mapping from CodeEntry* to ProfileNode* | |
183 HashMap children_; | |
184 List<ProfileNode*> children_list_; | |
185 unsigned id_; | |
186 HashMap line_ticks_; | |
187 | |
188 std::vector<CpuProfileDeoptInfo> deopt_infos_; | |
189 | |
190 DISALLOW_COPY_AND_ASSIGN(ProfileNode); | |
191 }; | |
192 | |
193 | |
194 class ProfileTree { | |
195 public: | |
196 ProfileTree(); | |
197 ~ProfileTree(); | |
198 | |
199 ProfileNode* AddPathFromEnd( | |
200 const Vector<CodeEntry*>& path, | |
201 int src_line = v8::CpuProfileNode::kNoLineNumberInfo); | |
202 ProfileNode* root() const { return root_; } | |
203 unsigned next_node_id() { return next_node_id_++; } | |
204 unsigned GetFunctionId(const ProfileNode* node); | |
205 | |
206 void Print() { | |
207 root_->Print(0); | |
208 } | |
209 | |
210 private: | |
211 template <typename Callback> | |
212 void TraverseDepthFirst(Callback* callback); | |
213 | |
214 CodeEntry root_entry_; | |
215 unsigned next_node_id_; | |
216 ProfileNode* root_; | |
217 | |
218 unsigned next_function_id_; | |
219 HashMap function_ids_; | |
220 | |
221 DISALLOW_COPY_AND_ASSIGN(ProfileTree); | |
222 }; | |
223 | |
224 | |
225 class CpuProfile { | |
226 public: | |
227 CpuProfile(const char* title, bool record_samples); | |
228 | |
229 // Add pc -> ... -> main() call path to the profile. | |
230 void AddPath(base::TimeTicks timestamp, const Vector<CodeEntry*>& path, | |
231 int src_line); | |
232 void CalculateTotalTicksAndSamplingRate(); | |
233 | |
234 const char* title() const { return title_; } | |
235 const ProfileTree* top_down() const { return &top_down_; } | |
236 | |
237 int samples_count() const { return samples_.length(); } | |
238 ProfileNode* sample(int index) const { return samples_.at(index); } | |
239 base::TimeTicks sample_timestamp(int index) const { | |
240 return timestamps_.at(index); | |
241 } | |
242 | |
243 base::TimeTicks start_time() const { return start_time_; } | |
244 base::TimeTicks end_time() const { return end_time_; } | |
245 | |
246 void UpdateTicksScale(); | |
247 | |
248 void Print(); | |
249 | |
250 private: | |
251 const char* title_; | |
252 bool record_samples_; | |
253 base::TimeTicks start_time_; | |
254 base::TimeTicks end_time_; | |
255 List<ProfileNode*> samples_; | |
256 List<base::TimeTicks> timestamps_; | |
257 ProfileTree top_down_; | |
258 | |
259 DISALLOW_COPY_AND_ASSIGN(CpuProfile); | |
260 }; | |
261 | |
262 | |
263 class CodeMap { | |
264 public: | |
265 CodeMap() {} | |
266 ~CodeMap(); | |
267 void AddCode(Address addr, CodeEntry* entry, unsigned size); | |
268 void MoveCode(Address from, Address to); | |
269 CodeEntry* FindEntry(Address addr); | |
270 int GetSharedId(Address addr); | |
271 | |
272 void Print(); | |
273 | |
274 private: | |
275 struct CodeEntryInfo { | |
276 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) | |
277 : entry(an_entry), size(a_size) { } | |
278 CodeEntry* entry; | |
279 unsigned size; | |
280 }; | |
281 | |
282 struct CodeTreeConfig { | |
283 typedef Address Key; | |
284 typedef CodeEntryInfo Value; | |
285 static const Key kNoKey; | |
286 static const Value NoValue() { return CodeEntryInfo(NULL, 0); } | |
287 static int Compare(const Key& a, const Key& b) { | |
288 return a < b ? -1 : (a > b ? 1 : 0); | |
289 } | |
290 }; | |
291 typedef SplayTree<CodeTreeConfig> CodeTree; | |
292 | |
293 class CodeTreePrinter { | |
294 public: | |
295 void Call(const Address& key, const CodeEntryInfo& value); | |
296 }; | |
297 | |
298 void DeleteAllCoveredCode(Address start, Address end); | |
299 | |
300 CodeTree tree_; | |
301 | |
302 DISALLOW_COPY_AND_ASSIGN(CodeMap); | |
303 }; | |
304 | |
305 | |
306 class CpuProfilesCollection { | |
307 public: | |
308 explicit CpuProfilesCollection(Heap* heap); | |
309 ~CpuProfilesCollection(); | |
310 | |
311 bool StartProfiling(const char* title, bool record_samples); | |
312 CpuProfile* StopProfiling(const char* title); | |
313 List<CpuProfile*>* profiles() { return &finished_profiles_; } | |
314 const char* GetName(Name* name) { | |
315 return function_and_resource_names_.GetName(name); | |
316 } | |
317 const char* GetName(int args_count) { | |
318 return function_and_resource_names_.GetName(args_count); | |
319 } | |
320 const char* GetFunctionName(Name* name) { | |
321 return function_and_resource_names_.GetFunctionName(name); | |
322 } | |
323 const char* GetFunctionName(const char* name) { | |
324 return function_and_resource_names_.GetFunctionName(name); | |
325 } | |
326 bool IsLastProfile(const char* title); | |
327 void RemoveProfile(CpuProfile* profile); | |
328 | |
329 CodeEntry* NewCodeEntry( | |
330 Logger::LogEventsAndTags tag, const char* name, | |
331 const char* name_prefix = CodeEntry::kEmptyNamePrefix, | |
332 const char* resource_name = CodeEntry::kEmptyResourceName, | |
333 int line_number = v8::CpuProfileNode::kNoLineNumberInfo, | |
334 int column_number = v8::CpuProfileNode::kNoColumnNumberInfo, | |
335 JITLineInfoTable* line_info = NULL, Address instruction_start = NULL); | |
336 | |
337 // Called from profile generator thread. | |
338 void AddPathToCurrentProfiles(base::TimeTicks timestamp, | |
339 const Vector<CodeEntry*>& path, int src_line); | |
340 | |
341 // Limits the number of profiles that can be simultaneously collected. | |
342 static const int kMaxSimultaneousProfiles = 100; | |
343 | |
344 private: | |
345 StringsStorage function_and_resource_names_; | |
346 List<CodeEntry*> code_entries_; | |
347 List<CpuProfile*> finished_profiles_; | |
348 | |
349 // Accessed by VM thread and profile generator thread. | |
350 List<CpuProfile*> current_profiles_; | |
351 base::Semaphore current_profiles_semaphore_; | |
352 | |
353 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); | |
354 }; | |
355 | |
356 | |
357 class ProfileGenerator { | |
358 public: | |
359 explicit ProfileGenerator(CpuProfilesCollection* profiles); | |
360 | |
361 void RecordTickSample(const TickSample& sample); | |
362 | |
363 CodeMap* code_map() { return &code_map_; } | |
364 | |
365 static const char* const kProgramEntryName; | |
366 static const char* const kIdleEntryName; | |
367 static const char* const kGarbageCollectorEntryName; | |
368 // Used to represent frames for which we have no reliable way to | |
369 // detect function. | |
370 static const char* const kUnresolvedFunctionName; | |
371 | |
372 private: | |
373 CodeEntry* EntryForVMState(StateTag tag); | |
374 | |
375 CpuProfilesCollection* profiles_; | |
376 CodeMap code_map_; | |
377 CodeEntry* program_entry_; | |
378 CodeEntry* idle_entry_; | |
379 CodeEntry* gc_entry_; | |
380 CodeEntry* unresolved_entry_; | |
381 | |
382 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); | |
383 }; | |
384 | |
385 | |
386 } } // namespace v8::internal | |
387 | |
388 #endif // V8_PROFILE_GENERATOR_H_ | |
OLD | NEW |