OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
11 // with the distribution. | 11 // with the distribution. |
12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
15 // | 15 // |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #ifndef V8_PROFILE_GENERATOR_H_ | 28 #ifndef V8_HEAP_SNAPSHOT_GENERATOR_H_ |
29 #define V8_PROFILE_GENERATOR_H_ | 29 #define V8_HEAP_SNAPSHOT_GENERATOR_H_ |
30 | |
31 #include "allocation.h" | |
32 #include "hashmap.h" | |
33 #include "../include/v8-profiler.h" | |
34 | 30 |
35 namespace v8 { | 31 namespace v8 { |
36 namespace internal { | 32 namespace internal { |
37 | 33 |
38 class TokenEnumerator { | |
39 public: | |
40 TokenEnumerator(); | |
41 ~TokenEnumerator(); | |
42 int GetTokenId(Object* token); | |
43 | |
44 static const int kNoSecurityToken = -1; | |
45 static const int kInheritsSecurityToken = -2; | |
46 | |
47 private: | |
48 static void TokenRemovedCallback(v8::Isolate* isolate, | |
49 v8::Persistent<v8::Value> handle, | |
50 void* parameter); | |
51 void TokenRemoved(Object** token_location); | |
52 | |
53 List<Object**> token_locations_; | |
54 List<bool> token_removed_; | |
55 | |
56 friend class TokenEnumeratorTester; | |
57 | |
58 DISALLOW_COPY_AND_ASSIGN(TokenEnumerator); | |
59 }; | |
60 | |
61 | |
62 // Provides a storage of strings allocated in C++ heap, to hold them | |
63 // forever, even if they disappear from JS heap or external storage. | |
64 class StringsStorage { | |
65 public: | |
66 StringsStorage(); | |
67 ~StringsStorage(); | |
68 | |
69 const char* GetCopy(const char* src); | |
70 const char* GetFormatted(const char* format, ...); | |
71 const char* GetVFormatted(const char* format, va_list args); | |
72 const char* GetName(String* name); | |
73 const char* GetName(int index); | |
74 inline const char* GetFunctionName(String* name); | |
75 inline const char* GetFunctionName(const char* name); | |
76 size_t GetUsedMemorySize() const; | |
77 | |
78 private: | |
79 static const int kMaxNameSize = 1024; | |
80 | |
81 INLINE(static bool StringsMatch(void* key1, void* key2)) { | |
82 return strcmp(reinterpret_cast<char*>(key1), | |
83 reinterpret_cast<char*>(key2)) == 0; | |
84 } | |
85 const char* AddOrDisposeString(char* str, uint32_t hash); | |
86 | |
87 // Mapping of strings by String::Hash to const char* strings. | |
88 HashMap names_; | |
89 | |
90 DISALLOW_COPY_AND_ASSIGN(StringsStorage); | |
91 }; | |
92 | |
93 | |
94 class CodeEntry { | |
95 public: | |
96 // CodeEntry doesn't own name strings, just references them. | |
97 INLINE(CodeEntry(Logger::LogEventsAndTags tag, | |
98 const char* name_prefix, | |
99 const char* name, | |
100 const char* resource_name, | |
101 int line_number, | |
102 int security_token_id)); | |
103 | |
104 INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); } | |
105 INLINE(const char* name_prefix() const) { return name_prefix_; } | |
106 INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; } | |
107 INLINE(const char* name() const) { return name_; } | |
108 INLINE(const char* resource_name() const) { return resource_name_; } | |
109 INLINE(int line_number() const) { return line_number_; } | |
110 INLINE(int shared_id() const) { return shared_id_; } | |
111 INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; } | |
112 INLINE(int security_token_id() const) { return security_token_id_; } | |
113 | |
114 INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag)); | |
115 | |
116 void CopyData(const CodeEntry& source); | |
117 uint32_t GetCallUid() const; | |
118 bool IsSameAs(CodeEntry* entry) const; | |
119 | |
120 static const char* const kEmptyNamePrefix; | |
121 | |
122 private: | |
123 Logger::LogEventsAndTags tag_; | |
124 const char* name_prefix_; | |
125 const char* name_; | |
126 const char* resource_name_; | |
127 int line_number_; | |
128 int shared_id_; | |
129 int security_token_id_; | |
130 | |
131 DISALLOW_COPY_AND_ASSIGN(CodeEntry); | |
132 }; | |
133 | |
134 | |
135 class ProfileTree; | |
136 | |
137 class ProfileNode { | |
138 public: | |
139 INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry)); | |
140 | |
141 ProfileNode* FindChild(CodeEntry* entry); | |
142 ProfileNode* FindOrAddChild(CodeEntry* entry); | |
143 INLINE(void IncrementSelfTicks()) { ++self_ticks_; } | |
144 INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; } | |
145 INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; } | |
146 | |
147 INLINE(CodeEntry* entry() const) { return entry_; } | |
148 INLINE(unsigned self_ticks() const) { return self_ticks_; } | |
149 INLINE(unsigned total_ticks() const) { return total_ticks_; } | |
150 INLINE(const List<ProfileNode*>* children() const) { return &children_list_; } | |
151 double GetSelfMillis() const; | |
152 double GetTotalMillis() const; | |
153 | |
154 void Print(int indent); | |
155 | |
156 private: | |
157 INLINE(static bool CodeEntriesMatch(void* entry1, void* entry2)) { | |
158 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs( | |
159 reinterpret_cast<CodeEntry*>(entry2)); | |
160 } | |
161 | |
162 INLINE(static uint32_t CodeEntryHash(CodeEntry* entry)) { | |
163 return entry->GetCallUid(); | |
164 } | |
165 | |
166 ProfileTree* tree_; | |
167 CodeEntry* entry_; | |
168 unsigned total_ticks_; | |
169 unsigned self_ticks_; | |
170 // Mapping from CodeEntry* to ProfileNode* | |
171 HashMap children_; | |
172 List<ProfileNode*> children_list_; | |
173 | |
174 DISALLOW_COPY_AND_ASSIGN(ProfileNode); | |
175 }; | |
176 | |
177 | |
178 class ProfileTree { | |
179 public: | |
180 ProfileTree(); | |
181 ~ProfileTree(); | |
182 | |
183 void AddPathFromEnd(const Vector<CodeEntry*>& path); | |
184 void AddPathFromStart(const Vector<CodeEntry*>& path); | |
185 void CalculateTotalTicks(); | |
186 void FilteredClone(ProfileTree* src, int security_token_id); | |
187 | |
188 double TicksToMillis(unsigned ticks) const { | |
189 return ticks * ms_to_ticks_scale_; | |
190 } | |
191 ProfileNode* root() const { return root_; } | |
192 void SetTickRatePerMs(double ticks_per_ms); | |
193 | |
194 void ShortPrint(); | |
195 void Print() { | |
196 root_->Print(0); | |
197 } | |
198 | |
199 private: | |
200 template <typename Callback> | |
201 void TraverseDepthFirst(Callback* callback); | |
202 | |
203 CodeEntry root_entry_; | |
204 ProfileNode* root_; | |
205 double ms_to_ticks_scale_; | |
206 | |
207 DISALLOW_COPY_AND_ASSIGN(ProfileTree); | |
208 }; | |
209 | |
210 | |
211 class CpuProfile { | |
212 public: | |
213 CpuProfile(const char* title, unsigned uid) | |
214 : title_(title), uid_(uid) { } | |
215 | |
216 // Add pc -> ... -> main() call path to the profile. | |
217 void AddPath(const Vector<CodeEntry*>& path); | |
218 void CalculateTotalTicks(); | |
219 void SetActualSamplingRate(double actual_sampling_rate); | |
220 CpuProfile* FilteredClone(int security_token_id); | |
221 | |
222 INLINE(const char* title() const) { return title_; } | |
223 INLINE(unsigned uid() const) { return uid_; } | |
224 INLINE(const ProfileTree* top_down() const) { return &top_down_; } | |
225 INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; } | |
226 | |
227 void UpdateTicksScale(); | |
228 | |
229 void ShortPrint(); | |
230 void Print(); | |
231 | |
232 private: | |
233 const char* title_; | |
234 unsigned uid_; | |
235 ProfileTree top_down_; | |
236 ProfileTree bottom_up_; | |
237 | |
238 DISALLOW_COPY_AND_ASSIGN(CpuProfile); | |
239 }; | |
240 | |
241 | |
242 class CodeMap { | |
243 public: | |
244 CodeMap() : next_shared_id_(1) { } | |
245 void AddCode(Address addr, CodeEntry* entry, unsigned size); | |
246 void MoveCode(Address from, Address to); | |
247 CodeEntry* FindEntry(Address addr); | |
248 int GetSharedId(Address addr); | |
249 | |
250 void Print(); | |
251 | |
252 private: | |
253 struct CodeEntryInfo { | |
254 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size) | |
255 : entry(an_entry), size(a_size) { } | |
256 CodeEntry* entry; | |
257 unsigned size; | |
258 }; | |
259 | |
260 struct CodeTreeConfig { | |
261 typedef Address Key; | |
262 typedef CodeEntryInfo Value; | |
263 static const Key kNoKey; | |
264 static const Value NoValue() { return CodeEntryInfo(NULL, 0); } | |
265 static int Compare(const Key& a, const Key& b) { | |
266 return a < b ? -1 : (a > b ? 1 : 0); | |
267 } | |
268 }; | |
269 typedef SplayTree<CodeTreeConfig> CodeTree; | |
270 | |
271 class CodeTreePrinter { | |
272 public: | |
273 void Call(const Address& key, const CodeEntryInfo& value); | |
274 }; | |
275 | |
276 void DeleteAllCoveredCode(Address start, Address end); | |
277 | |
278 // Fake CodeEntry pointer to distinguish shared function entries. | |
279 static CodeEntry* const kSharedFunctionCodeEntry; | |
280 | |
281 CodeTree tree_; | |
282 int next_shared_id_; | |
283 | |
284 DISALLOW_COPY_AND_ASSIGN(CodeMap); | |
285 }; | |
286 | |
287 | |
288 class CpuProfilesCollection { | |
289 public: | |
290 CpuProfilesCollection(); | |
291 ~CpuProfilesCollection(); | |
292 | |
293 bool StartProfiling(const char* title, unsigned uid); | |
294 bool StartProfiling(String* title, unsigned uid); | |
295 CpuProfile* StopProfiling(int security_token_id, | |
296 const char* title, | |
297 double actual_sampling_rate); | |
298 List<CpuProfile*>* Profiles(int security_token_id); | |
299 const char* GetName(String* name) { | |
300 return function_and_resource_names_.GetName(name); | |
301 } | |
302 const char* GetName(int args_count) { | |
303 return function_and_resource_names_.GetName(args_count); | |
304 } | |
305 CpuProfile* GetProfile(int security_token_id, unsigned uid); | |
306 bool IsLastProfile(const char* title); | |
307 void RemoveProfile(CpuProfile* profile); | |
308 bool HasDetachedProfiles() { return detached_profiles_.length() > 0; } | |
309 | |
310 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
311 String* name, String* resource_name, int line_number); | |
312 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name); | |
313 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
314 const char* name_prefix, String* name); | |
315 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count); | |
316 CodeEntry* NewCodeEntry(int security_token_id); | |
317 | |
318 // Called from profile generator thread. | |
319 void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path); | |
320 | |
321 // Limits the number of profiles that can be simultaneously collected. | |
322 static const int kMaxSimultaneousProfiles = 100; | |
323 | |
324 private: | |
325 const char* GetFunctionName(String* name) { | |
326 return function_and_resource_names_.GetFunctionName(name); | |
327 } | |
328 const char* GetFunctionName(const char* name) { | |
329 return function_and_resource_names_.GetFunctionName(name); | |
330 } | |
331 int GetProfileIndex(unsigned uid); | |
332 List<CpuProfile*>* GetProfilesList(int security_token_id); | |
333 int TokenToIndex(int security_token_id); | |
334 | |
335 INLINE(static bool UidsMatch(void* key1, void* key2)) { | |
336 return key1 == key2; | |
337 } | |
338 | |
339 StringsStorage function_and_resource_names_; | |
340 List<CodeEntry*> code_entries_; | |
341 List<List<CpuProfile*>* > profiles_by_token_; | |
342 // Mapping from profiles' uids to indexes in the second nested list | |
343 // of profiles_by_token_. | |
344 HashMap profiles_uids_; | |
345 List<CpuProfile*> detached_profiles_; | |
346 | |
347 // Accessed by VM thread and profile generator thread. | |
348 List<CpuProfile*> current_profiles_; | |
349 Semaphore* current_profiles_semaphore_; | |
350 | |
351 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection); | |
352 }; | |
353 | |
354 | |
355 class SampleRateCalculator { | |
356 public: | |
357 SampleRateCalculator() | |
358 : result_(Logger::kSamplingIntervalMs * kResultScale), | |
359 ticks_per_ms_(Logger::kSamplingIntervalMs), | |
360 measurements_count_(0), | |
361 wall_time_query_countdown_(1) { | |
362 } | |
363 | |
364 double ticks_per_ms() { | |
365 return result_ / static_cast<double>(kResultScale); | |
366 } | |
367 void Tick(); | |
368 void UpdateMeasurements(double current_time); | |
369 | |
370 // Instead of querying current wall time each tick, | |
371 // we use this constant to control query intervals. | |
372 static const unsigned kWallTimeQueryIntervalMs = 100; | |
373 | |
374 private: | |
375 // As the result needs to be accessed from a different thread, we | |
376 // use type that guarantees atomic writes to memory. There should | |
377 // be <= 1000 ticks per second, thus storing a value of a 10 ** 5 | |
378 // order should provide enough precision while keeping away from a | |
379 // potential overflow. | |
380 static const int kResultScale = 100000; | |
381 | |
382 AtomicWord result_; | |
383 // All other fields are accessed only from the sampler thread. | |
384 double ticks_per_ms_; | |
385 unsigned measurements_count_; | |
386 unsigned wall_time_query_countdown_; | |
387 double last_wall_time_; | |
388 | |
389 DISALLOW_COPY_AND_ASSIGN(SampleRateCalculator); | |
390 }; | |
391 | |
392 | |
393 class ProfileGenerator { | |
394 public: | |
395 explicit ProfileGenerator(CpuProfilesCollection* profiles); | |
396 | |
397 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
398 String* name, | |
399 String* resource_name, | |
400 int line_number)) { | |
401 return profiles_->NewCodeEntry(tag, name, resource_name, line_number); | |
402 } | |
403 | |
404 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
405 const char* name)) { | |
406 return profiles_->NewCodeEntry(tag, name); | |
407 } | |
408 | |
409 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
410 const char* name_prefix, | |
411 String* name)) { | |
412 return profiles_->NewCodeEntry(tag, name_prefix, name); | |
413 } | |
414 | |
415 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, | |
416 int args_count)) { | |
417 return profiles_->NewCodeEntry(tag, args_count); | |
418 } | |
419 | |
420 INLINE(CodeEntry* NewCodeEntry(int security_token_id)) { | |
421 return profiles_->NewCodeEntry(security_token_id); | |
422 } | |
423 | |
424 void RecordTickSample(const TickSample& sample); | |
425 | |
426 INLINE(CodeMap* code_map()) { return &code_map_; } | |
427 | |
428 INLINE(void Tick()) { sample_rate_calc_.Tick(); } | |
429 INLINE(double actual_sampling_rate()) { | |
430 return sample_rate_calc_.ticks_per_ms(); | |
431 } | |
432 | |
433 static const char* const kAnonymousFunctionName; | |
434 static const char* const kProgramEntryName; | |
435 static const char* const kGarbageCollectorEntryName; | |
436 | |
437 private: | |
438 INLINE(CodeEntry* EntryForVMState(StateTag tag)); | |
439 | |
440 CpuProfilesCollection* profiles_; | |
441 CodeMap code_map_; | |
442 CodeEntry* program_entry_; | |
443 CodeEntry* gc_entry_; | |
444 SampleRateCalculator sample_rate_calc_; | |
445 | |
446 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator); | |
447 }; | |
448 | |
449 | |
450 class HeapEntry; | 34 class HeapEntry; |
451 class HeapSnapshot; | 35 class HeapSnapshot; |
452 | 36 |
453 class HeapGraphEdge BASE_EMBEDDED { | 37 class HeapGraphEdge BASE_EMBEDDED { |
454 public: | 38 public: |
455 enum Type { | 39 enum Type { |
456 kContextVariable = v8::HeapGraphEdge::kContextVariable, | 40 kContextVariable = v8::HeapGraphEdge::kContextVariable, |
457 kElement = v8::HeapGraphEdge::kElement, | 41 kElement = v8::HeapGraphEdge::kElement, |
458 kProperty = v8::HeapGraphEdge::kProperty, | 42 kProperty = v8::HeapGraphEdge::kProperty, |
459 kInternal = v8::HeapGraphEdge::kInternal, | 43 kInternal = v8::HeapGraphEdge::kInternal, |
(...skipping 639 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1099 int next_node_id_; | 683 int next_node_id_; |
1100 int next_string_id_; | 684 int next_string_id_; |
1101 OutputStreamWriter* writer_; | 685 OutputStreamWriter* writer_; |
1102 | 686 |
1103 friend class HeapSnapshotJSONSerializerEnumerator; | 687 friend class HeapSnapshotJSONSerializerEnumerator; |
1104 friend class HeapSnapshotJSONSerializerIterator; | 688 friend class HeapSnapshotJSONSerializerIterator; |
1105 | 689 |
1106 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer); | 690 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer); |
1107 }; | 691 }; |
1108 | 692 |
| 693 |
1109 } } // namespace v8::internal | 694 } } // namespace v8::internal |
1110 | 695 |
1111 #endif // V8_PROFILE_GENERATOR_H_ | 696 #endif // V8_HEAP_SNAPSHOT_GENERATOR_H_ |
| 697 |
OLD | NEW |