Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: src/heap-snapshot-generator.h

Issue 12314027: Split profile-generator (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698