blob: d1c2b3804af6b65e584b5d72e5fe4e3f056375d0 [file] [log] [blame]
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001// Copyright 2010 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27
28#ifndef V8_PROFILE_GENERATOR_H_
29#define V8_PROFILE_GENERATOR_H_
30
lrn@chromium.org1c092762011-05-09 09:42:16 +000031#include "allocation.h"
fschneider@chromium.org086aac62010-03-17 13:18:24 +000032#include "hashmap.h"
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000033#include "../include/v8-profiler.h"
fschneider@chromium.org086aac62010-03-17 13:18:24 +000034
35namespace v8 {
36namespace internal {
37
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000038class TokenEnumerator {
39 public:
40 TokenEnumerator();
41 ~TokenEnumerator();
42 int GetTokenId(Object* token);
43
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000044 static const int kNoSecurityToken = -1;
45 static const int kInheritsSecurityToken = -2;
46
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000047 private:
48 static void TokenRemovedCallback(v8::Persistent<v8::Value> handle,
49 void* parameter);
50 void TokenRemoved(Object** token_location);
51
52 List<Object**> token_locations_;
53 List<bool> token_removed_;
54
55 friend class TokenEnumeratorTester;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000056
57 DISALLOW_COPY_AND_ASSIGN(TokenEnumerator);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000058};
59
60
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000061// Provides a storage of strings allocated in C++ heap, to hold them
62// forever, even if they disappear from JS heap or external storage.
63class StringsStorage {
64 public:
65 StringsStorage();
66 ~StringsStorage();
67
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000068 const char* GetCopy(const char* src);
69 const char* GetFormatted(const char* format, ...);
70 const char* GetVFormatted(const char* format, va_list args);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000071 const char* GetName(String* name);
vegorov@chromium.org42841962010-10-18 11:18:59 +000072 const char* GetName(int index);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000073 inline const char* GetFunctionName(String* name);
74 inline const char* GetFunctionName(const char* name);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000075
76 private:
77 INLINE(static bool StringsMatch(void* key1, void* key2)) {
78 return strcmp(reinterpret_cast<char*>(key1),
79 reinterpret_cast<char*>(key2)) == 0;
80 }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +000081 const char* AddOrDisposeString(char* str, uint32_t hash);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000082
ricow@chromium.org4980dff2010-07-19 08:33:45 +000083 // Mapping of strings by String::Hash to const char* strings.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000084 HashMap names_;
85
86 DISALLOW_COPY_AND_ASSIGN(StringsStorage);
87};
88
89
fschneider@chromium.org086aac62010-03-17 13:18:24 +000090class CodeEntry {
91 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +000092 // CodeEntry doesn't own name strings, just references them.
lrn@chromium.org25156de2010-04-06 13:10:27 +000093 INLINE(CodeEntry(Logger::LogEventsAndTags tag,
94 const char* name_prefix,
95 const char* name,
96 const char* resource_name,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000097 int line_number,
98 int security_token_id));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000099
ager@chromium.org357bf652010-04-12 11:30:10 +0000100 INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000101 INLINE(const char* name_prefix() const) { return name_prefix_; }
102 INLINE(bool has_name_prefix() const) { return name_prefix_[0] != '\0'; }
103 INLINE(const char* name() const) { return name_; }
104 INLINE(const char* resource_name() const) { return resource_name_; }
105 INLINE(int line_number() const) { return line_number_; }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000106 INLINE(int shared_id() const) { return shared_id_; }
107 INLINE(void set_shared_id(int shared_id)) { shared_id_ = shared_id; }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000108 INLINE(int security_token_id() const) { return security_token_id_; }
ager@chromium.org357bf652010-04-12 11:30:10 +0000109
110 INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
lrn@chromium.org25156de2010-04-06 13:10:27 +0000111
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000112 void CopyData(const CodeEntry& source);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000113 uint32_t GetCallUid() const;
114 bool IsSameAs(CodeEntry* entry) const;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000116 static const char* const kEmptyNamePrefix;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000117
118 private:
119 Logger::LogEventsAndTags tag_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000120 const char* name_prefix_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000121 const char* name_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000122 const char* resource_name_;
123 int line_number_;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000124 int shared_id_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000125 int security_token_id_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000126
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000127 DISALLOW_COPY_AND_ASSIGN(CodeEntry);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000128};
129
130
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000131class ProfileTree;
132
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000133class ProfileNode {
134 public:
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000135 INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000136
137 ProfileNode* FindChild(CodeEntry* entry);
138 ProfileNode* FindOrAddChild(CodeEntry* entry);
139 INLINE(void IncrementSelfTicks()) { ++self_ticks_; }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000140 INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000141 INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; }
142
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000143 INLINE(CodeEntry* entry() const) { return entry_; }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000144 INLINE(unsigned self_ticks() const) { return self_ticks_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000145 INLINE(unsigned total_ticks() const) { return total_ticks_; }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000146 INLINE(const List<ProfileNode*>* children() const) { return &children_list_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000147 double GetSelfMillis() const;
148 double GetTotalMillis() const;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000149
150 void Print(int indent);
151
152 private:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000153 INLINE(static bool CodeEntriesMatch(void* entry1, void* entry2)) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000154 return reinterpret_cast<CodeEntry*>(entry1)->IsSameAs(
155 reinterpret_cast<CodeEntry*>(entry2));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000156 }
157
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000158 INLINE(static uint32_t CodeEntryHash(CodeEntry* entry)) {
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000159 return entry->GetCallUid();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000160 }
161
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000162 ProfileTree* tree_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000163 CodeEntry* entry_;
164 unsigned total_ticks_;
165 unsigned self_ticks_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000166 // Mapping from CodeEntry* to ProfileNode*
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000167 HashMap children_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000168 List<ProfileNode*> children_list_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000169
170 DISALLOW_COPY_AND_ASSIGN(ProfileNode);
171};
172
173
lrn@chromium.org25156de2010-04-06 13:10:27 +0000174class ProfileTree {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000175 public:
ager@chromium.org357bf652010-04-12 11:30:10 +0000176 ProfileTree();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000177 ~ProfileTree();
178
179 void AddPathFromEnd(const Vector<CodeEntry*>& path);
180 void AddPathFromStart(const Vector<CodeEntry*>& path);
181 void CalculateTotalTicks();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000182 void FilteredClone(ProfileTree* src, int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000183
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000184 double TicksToMillis(unsigned ticks) const {
185 return ticks * ms_to_ticks_scale_;
186 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000187 ProfileNode* root() const { return root_; }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000188 void SetTickRatePerMs(double ticks_per_ms);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000189
190 void ShortPrint();
191 void Print() {
192 root_->Print(0);
193 }
194
195 private:
196 template <typename Callback>
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000197 void TraverseDepthFirst(Callback* callback);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000198
ager@chromium.org357bf652010-04-12 11:30:10 +0000199 CodeEntry root_entry_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000200 ProfileNode* root_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000201 double ms_to_ticks_scale_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000202
203 DISALLOW_COPY_AND_ASSIGN(ProfileTree);
204};
205
206
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000207class CpuProfile {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000208 public:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000209 CpuProfile(const char* title, unsigned uid)
210 : title_(title), uid_(uid) { }
211
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000212 // Add pc -> ... -> main() call path to the profile.
213 void AddPath(const Vector<CodeEntry*>& path);
214 void CalculateTotalTicks();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000215 void SetActualSamplingRate(double actual_sampling_rate);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000216 CpuProfile* FilteredClone(int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000217
lrn@chromium.org25156de2010-04-06 13:10:27 +0000218 INLINE(const char* title() const) { return title_; }
219 INLINE(unsigned uid() const) { return uid_; }
220 INLINE(const ProfileTree* top_down() const) { return &top_down_; }
221 INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000222
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000223 void UpdateTicksScale();
224
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000225 void ShortPrint();
226 void Print();
227
228 private:
lrn@chromium.org25156de2010-04-06 13:10:27 +0000229 const char* title_;
230 unsigned uid_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000231 ProfileTree top_down_;
232 ProfileTree bottom_up_;
233
234 DISALLOW_COPY_AND_ASSIGN(CpuProfile);
235};
236
237
lrn@chromium.org25156de2010-04-06 13:10:27 +0000238class CodeMap {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000239 public:
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000240 CodeMap() : next_shared_id_(1) { }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000241 INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
242 INLINE(void MoveCode(Address from, Address to));
243 INLINE(void DeleteCode(Address addr));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000244 CodeEntry* FindEntry(Address addr);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000245 int GetSharedId(Address addr);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000246
lrn@chromium.org25156de2010-04-06 13:10:27 +0000247 void Print();
248
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000249 private:
250 struct CodeEntryInfo {
251 CodeEntryInfo(CodeEntry* an_entry, unsigned a_size)
252 : entry(an_entry), size(a_size) { }
253 CodeEntry* entry;
254 unsigned size;
255 };
256
257 struct CodeTreeConfig {
258 typedef Address Key;
259 typedef CodeEntryInfo Value;
260 static const Key kNoKey;
261 static const Value kNoValue;
262 static int Compare(const Key& a, const Key& b) {
263 return a < b ? -1 : (a > b ? 1 : 0);
264 }
265 };
266 typedef SplayTree<CodeTreeConfig> CodeTree;
267
lrn@chromium.org25156de2010-04-06 13:10:27 +0000268 class CodeTreePrinter {
269 public:
270 void Call(const Address& key, const CodeEntryInfo& value);
271 };
272
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000273 // Fake CodeEntry pointer to distinguish shared function entries.
274 static CodeEntry* const kSharedFunctionCodeEntry;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000275
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000276 CodeTree tree_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000277 int next_shared_id_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000278
279 DISALLOW_COPY_AND_ASSIGN(CodeMap);
280};
281
282
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000283class CpuProfilesCollection {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000284 public:
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000285 CpuProfilesCollection();
286 ~CpuProfilesCollection();
287
lrn@chromium.org25156de2010-04-06 13:10:27 +0000288 bool StartProfiling(const char* title, unsigned uid);
289 bool StartProfiling(String* title, unsigned uid);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000290 CpuProfile* StopProfiling(int security_token_id,
291 const char* title,
292 double actual_sampling_rate);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000293 List<CpuProfile*>* Profiles(int security_token_id);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000294 const char* GetName(String* name) {
295 return function_and_resource_names_.GetName(name);
296 }
vegorov@chromium.org42841962010-10-18 11:18:59 +0000297 const char* GetName(int args_count) {
298 return function_and_resource_names_.GetName(args_count);
299 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000300 CpuProfile* GetProfile(int security_token_id, unsigned uid);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000301 bool IsLastProfile(const char* title);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 void RemoveProfile(CpuProfile* profile);
303 bool HasDetachedProfiles() { return detached_profiles_.length() > 0; }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000304
305 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
306 String* name, String* resource_name, int line_number);
307 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, const char* name);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000308 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
309 const char* name_prefix, String* name);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000310 CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000311 CodeEntry* NewCodeEntry(int security_token_id);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000312
lrn@chromium.org25156de2010-04-06 13:10:27 +0000313 // Called from profile generator thread.
314 void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000315
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000316 // Limits the number of profiles that can be simultaneously collected.
317 static const int kMaxSimultaneousProfiles = 100;
318
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000319 private:
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000320 const char* GetFunctionName(String* 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 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000326 int GetProfileIndex(unsigned uid);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000327 List<CpuProfile*>* GetProfilesList(int security_token_id);
328 int TokenToIndex(int security_token_id);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000329
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000330 INLINE(static bool UidsMatch(void* key1, void* key2)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000331 return key1 == key2;
332 }
333
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000334 StringsStorage function_and_resource_names_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000335 List<CodeEntry*> code_entries_;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000336 List<List<CpuProfile*>* > profiles_by_token_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000337 // Mapping from profiles' uids to indexes in the second nested list
338 // of profiles_by_token_.
lrn@chromium.org25156de2010-04-06 13:10:27 +0000339 HashMap profiles_uids_;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 List<CpuProfile*> detached_profiles_;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000341
342 // Accessed by VM thread and profile generator thread.
343 List<CpuProfile*> current_profiles_;
344 Semaphore* current_profiles_semaphore_;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000345
346 DISALLOW_COPY_AND_ASSIGN(CpuProfilesCollection);
347};
348
349
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000350class SampleRateCalculator {
351 public:
352 SampleRateCalculator()
353 : result_(Logger::kSamplingIntervalMs * kResultScale),
354 ticks_per_ms_(Logger::kSamplingIntervalMs),
355 measurements_count_(0),
356 wall_time_query_countdown_(1) {
357 }
358
359 double ticks_per_ms() {
360 return result_ / static_cast<double>(kResultScale);
361 }
362 void Tick();
363 void UpdateMeasurements(double current_time);
364
365 // Instead of querying current wall time each tick,
366 // we use this constant to control query intervals.
367 static const unsigned kWallTimeQueryIntervalMs = 100;
368
369 private:
370 // As the result needs to be accessed from a different thread, we
371 // use type that guarantees atomic writes to memory. There should
372 // be <= 1000 ticks per second, thus storing a value of a 10 ** 5
373 // order should provide enough precision while keeping away from a
374 // potential overflow.
375 static const int kResultScale = 100000;
376
377 AtomicWord result_;
378 // All other fields are accessed only from the sampler thread.
379 double ticks_per_ms_;
380 unsigned measurements_count_;
381 unsigned wall_time_query_countdown_;
382 double last_wall_time_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000383
384 DISALLOW_COPY_AND_ASSIGN(SampleRateCalculator);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000385};
386
387
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000388class ProfileGenerator {
389 public:
390 explicit ProfileGenerator(CpuProfilesCollection* profiles);
391
392 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
393 String* name,
394 String* resource_name,
395 int line_number)) {
396 return profiles_->NewCodeEntry(tag, name, resource_name, line_number);
397 }
398
399 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
400 const char* name)) {
401 return profiles_->NewCodeEntry(tag, name);
402 }
403
404 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000405 const char* name_prefix,
406 String* name)) {
407 return profiles_->NewCodeEntry(tag, name_prefix, name);
408 }
409
410 INLINE(CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000411 int args_count)) {
412 return profiles_->NewCodeEntry(tag, args_count);
413 }
414
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000415 INLINE(CodeEntry* NewCodeEntry(int security_token_id)) {
416 return profiles_->NewCodeEntry(security_token_id);
417 }
418
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000419 void RecordTickSample(const TickSample& sample);
420
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000421 INLINE(CodeMap* code_map()) { return &code_map_; }
422
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000423 INLINE(void Tick()) { sample_rate_calc_.Tick(); }
424 INLINE(double actual_sampling_rate()) {
425 return sample_rate_calc_.ticks_per_ms();
426 }
427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000428 static const char* const kAnonymousFunctionName;
429 static const char* const kProgramEntryName;
430 static const char* const kGarbageCollectorEntryName;
ager@chromium.org357bf652010-04-12 11:30:10 +0000431
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000432 private:
ager@chromium.org357bf652010-04-12 11:30:10 +0000433 INLINE(CodeEntry* EntryForVMState(StateTag tag));
434
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000435 CpuProfilesCollection* profiles_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000436 CodeMap code_map_;
ager@chromium.org357bf652010-04-12 11:30:10 +0000437 CodeEntry* program_entry_;
438 CodeEntry* gc_entry_;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000439 SampleRateCalculator sample_rate_calc_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000440
441 DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
442};
443
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000444
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000445class HeapEntry;
446
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000447class HeapGraphEdge BASE_EMBEDDED {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000448 public:
449 enum Type {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000450 kContextVariable = v8::HeapGraphEdge::kContextVariable,
451 kElement = v8::HeapGraphEdge::kElement,
452 kProperty = v8::HeapGraphEdge::kProperty,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000453 kInternal = v8::HeapGraphEdge::kInternal,
454 kHidden = v8::HeapGraphEdge::kHidden,
455 kShortcut = v8::HeapGraphEdge::kShortcut
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000456 };
457
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000458 HeapGraphEdge() { }
459 void Init(int child_index, Type type, const char* name, HeapEntry* to);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000460 void Init(int child_index, Type type, int index, HeapEntry* to);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000461 void Init(int child_index, int index, HeapEntry* to);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000462
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000463 Type type() { return static_cast<Type>(type_); }
464 int index() {
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000465 ASSERT(type_ == kElement || type_ == kHidden);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000466 return index_;
467 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000468 const char* name() {
469 ASSERT(type_ == kContextVariable
470 || type_ == kProperty
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000471 || type_ == kInternal
472 || type_ == kShortcut);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000473 return name_;
474 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000475 HeapEntry* to() { return to_; }
476
477 HeapEntry* From();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000478
479 private:
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000480 int child_index_ : 29;
481 unsigned type_ : 3;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000482 union {
483 int index_;
484 const char* name_;
485 };
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000486 HeapEntry* to_;
487
488 DISALLOW_COPY_AND_ASSIGN(HeapGraphEdge);
489};
490
491
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000492class HeapSnapshot;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000493
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000494// HeapEntry instances represent an entity from the heap (or a special
495// virtual node, e.g. root). To make heap snapshots more compact,
496// HeapEntries has a special memory layout (no Vectors or Lists used):
497//
498// +-----------------+
499// HeapEntry
500// +-----------------+
501// HeapGraphEdge |
502// ... } children_count
503// HeapGraphEdge |
504// +-----------------+
505// HeapGraphEdge* |
506// ... } retainers_count
507// HeapGraphEdge* |
508// +-----------------+
509//
510// In a HeapSnapshot, all entries are hand-allocated in a continuous array
511// of raw bytes.
512//
513class HeapEntry BASE_EMBEDDED {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000514 public:
515 enum Type {
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000516 kHidden = v8::HeapGraphNode::kHidden,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000517 kArray = v8::HeapGraphNode::kArray,
518 kString = v8::HeapGraphNode::kString,
519 kObject = v8::HeapGraphNode::kObject,
520 kCode = v8::HeapGraphNode::kCode,
vegorov@chromium.org42841962010-10-18 11:18:59 +0000521 kClosure = v8::HeapGraphNode::kClosure,
522 kRegExp = v8::HeapGraphNode::kRegExp,
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000523 kHeapNumber = v8::HeapGraphNode::kHeapNumber,
524 kNative = v8::HeapGraphNode::kNative
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000525 };
526
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000527 HeapEntry() { }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000528 void Init(HeapSnapshot* snapshot,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000529 Type type,
530 const char* name,
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000531 uint64_t id,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000532 int self_size,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000533 int children_count,
534 int retainers_count);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000535
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000536 HeapSnapshot* snapshot() { return snapshot_; }
537 Type type() { return static_cast<Type>(type_); }
538 const char* name() { return name_; }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000539 inline uint64_t id();
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000540 int self_size() { return self_size_; }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000541 int retained_size() { return retained_size_; }
542 void add_retained_size(int size) { retained_size_ += size; }
543 void set_retained_size(int value) { retained_size_ = value; }
544 int ordered_index() { return ordered_index_; }
545 void set_ordered_index(int value) { ordered_index_ = value; }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000546
547 Vector<HeapGraphEdge> children() {
548 return Vector<HeapGraphEdge>(children_arr(), children_count_); }
549 Vector<HeapGraphEdge*> retainers() {
550 return Vector<HeapGraphEdge*>(retainers_arr(), retainers_count_); }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000551 HeapEntry* dominator() { return dominator_; }
552 void set_dominator(HeapEntry* entry) { dominator_ = entry; }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000553
554 void clear_paint() { painted_ = kUnpainted; }
555 bool painted_reachable() { return painted_ == kPainted; }
556 void paint_reachable() {
557 ASSERT(painted_ == kUnpainted);
558 painted_ = kPainted;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000559 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000560 bool not_painted_reachable_from_others() {
561 return painted_ != kPaintedReachableFromOthers;
562 }
563 void paint_reachable_from_others() {
564 painted_ = kPaintedReachableFromOthers;
565 }
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000566 template<class Visitor>
567 void ApplyAndPaintAllReachable(Visitor* visitor);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000568 void PaintAllReachable();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000569
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000570 void SetIndexedReference(HeapGraphEdge::Type type,
571 int child_index,
572 int index,
573 HeapEntry* entry,
574 int retainer_index);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000575 void SetNamedReference(HeapGraphEdge::Type type,
576 int child_index,
577 const char* name,
578 HeapEntry* entry,
579 int retainer_index);
580 void SetUnidirElementReference(int child_index, int index, HeapEntry* entry);
581
582 int EntrySize() { return EntriesSize(1, children_count_, retainers_count_); }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000583 int RetainedSize(bool exact);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000584
585 void Print(int max_depth, int indent);
586
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000587 static int EntriesSize(int entries_count,
588 int children_count,
589 int retainers_count);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000590
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000591 private:
592 HeapGraphEdge* children_arr() {
593 return reinterpret_cast<HeapGraphEdge*>(this + 1);
594 }
595 HeapGraphEdge** retainers_arr() {
596 return reinterpret_cast<HeapGraphEdge**>(children_arr() + children_count_);
597 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000598 void CalculateExactRetainedSize();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000599 const char* TypeAsString();
600
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000601 unsigned painted_: 2;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000602 unsigned type_: 4;
603 int children_count_: 26;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000604 int retainers_count_;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000605 int self_size_;
606 union {
607 int ordered_index_; // Used during dominator tree building.
608 int retained_size_; // At that moment, there is no retained size yet.
609 };
610 HeapEntry* dominator_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000611 HeapSnapshot* snapshot_;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000612 struct Id {
613 uint32_t id1_;
614 uint32_t id2_;
615 } id_; // This is to avoid extra padding of 64-bit value.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000616 const char* name_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000617
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000618 // Paints used for exact retained sizes calculation.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000619 static const unsigned kUnpainted = 0;
620 static const unsigned kPainted = 1;
621 static const unsigned kPaintedReachableFromOthers = 2;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000622
623 static const int kExactRetainedSizeTag = 1;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000624
625 DISALLOW_COPY_AND_ASSIGN(HeapEntry);
626};
627
628
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000629class HeapSnapshotsCollection;
630
631// HeapSnapshot represents a single heap snapshot. It is stored in
632// HeapSnapshotsCollection, which is also a factory for
633// HeapSnapshots. All HeapSnapshots share strings copied from JS heap
634// to be able to return them even if they were collected.
635// HeapSnapshotGenerator fills in a HeapSnapshot.
636class HeapSnapshot {
637 public:
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000638 enum Type {
ager@chromium.org04921a82011-06-27 13:21:41 +0000639 kFull = v8::HeapSnapshot::kFull
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000640 };
641
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000642 HeapSnapshot(HeapSnapshotsCollection* collection,
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000643 Type type,
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000644 const char* title,
645 unsigned uid);
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000646 ~HeapSnapshot();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 void Delete();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000648
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000649 HeapSnapshotsCollection* collection() { return collection_; }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000650 Type type() { return type_; }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000651 const char* title() { return title_; }
652 unsigned uid() { return uid_; }
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000653 HeapEntry* root() { return root_entry_; }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000654 HeapEntry* gc_roots() { return gc_roots_entry_; }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000655 HeapEntry* natives_root() { return natives_root_entry_; }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000656 List<HeapEntry*>* entries() { return &entries_; }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000657
658 void AllocateEntries(
659 int entries_count, int children_count, int retainers_count);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000660 HeapEntry* AddEntry(HeapEntry::Type type,
661 const char* name,
662 uint64_t id,
663 int size,
664 int children_count,
665 int retainers_count);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000666 HeapEntry* AddRootEntry(int children_count);
667 HeapEntry* AddGcRootsEntry(int children_count, int retainers_count);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000668 HeapEntry* AddNativesRootEntry(int children_count, int retainers_count);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000669 void ClearPaint();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000670 HeapEntry* GetEntryById(uint64_t id);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000671 List<HeapEntry*>* GetSortedEntriesList();
672 template<class Visitor>
673 void IterateEntries(Visitor* visitor) { entries_.Iterate(visitor); }
ager@chromium.orgbeb25712010-11-29 08:02:25 +0000674 void SetDominatorsToSelf();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000675
676 void Print(int max_depth);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000677 void PrintEntriesSize();
678
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000679 private:
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000680 HeapEntry* GetNextEntryToInit();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000681
682 HeapSnapshotsCollection* collection_;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000683 Type type_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000684 const char* title_;
685 unsigned uid_;
ricow@chromium.orgeb7c1442010-10-04 08:54:21 +0000686 HeapEntry* root_entry_;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000687 HeapEntry* gc_roots_entry_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000688 HeapEntry* natives_root_entry_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000689 char* raw_entries_;
690 List<HeapEntry*> entries_;
691 bool entries_sorted_;
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000692#ifdef DEBUG
693 int raw_entries_size_;
694#endif
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000695
696 friend class HeapSnapshotTester;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000697
698 DISALLOW_COPY_AND_ASSIGN(HeapSnapshot);
699};
700
701
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000702class HeapObjectsMap {
703 public:
704 HeapObjectsMap();
705 ~HeapObjectsMap();
706
707 void SnapshotGenerationFinished();
708 uint64_t FindObject(Address addr);
709 void MoveObject(Address from, Address to);
710
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000711 static uint64_t GenerateId(v8::RetainedObjectInfo* info);
712
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000713 static const uint64_t kInternalRootObjectId;
714 static const uint64_t kGcRootsObjectId;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000715 static const uint64_t kNativesRootObjectId;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000716 static const uint64_t kFirstAvailableObjectId;
717
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000718 private:
719 struct EntryInfo {
720 explicit EntryInfo(uint64_t id) : id(id), accessed(true) { }
721 EntryInfo(uint64_t id, bool accessed) : id(id), accessed(accessed) { }
722 uint64_t id;
723 bool accessed;
724 };
725
726 void AddEntry(Address addr, uint64_t id);
727 uint64_t FindEntry(Address addr);
728 void RemoveDeadEntries();
729
730 static bool AddressesMatch(void* key1, void* key2) {
731 return key1 == key2;
732 }
733
734 static uint32_t AddressHash(Address addr) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000735 return ComputeIntegerHash(
736 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr)));
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000737 }
738
739 bool initial_fill_mode_;
740 uint64_t next_id_;
741 HashMap entries_map_;
742 List<EntryInfo>* entries_;
743
744 DISALLOW_COPY_AND_ASSIGN(HeapObjectsMap);
745};
746
747
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000748class HeapSnapshotsCollection {
749 public:
750 HeapSnapshotsCollection();
751 ~HeapSnapshotsCollection();
752
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000753 bool is_tracking_objects() { return is_tracking_objects_; }
754
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000755 HeapSnapshot* NewSnapshot(
756 HeapSnapshot::Type type, const char* name, unsigned uid);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000757 void SnapshotGenerationFinished(HeapSnapshot* snapshot);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000758 List<HeapSnapshot*>* snapshots() { return &snapshots_; }
759 HeapSnapshot* GetSnapshot(unsigned uid);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000760 void RemoveSnapshot(HeapSnapshot* snapshot);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000761
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000762 StringsStorage* names() { return &names_; }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000763 TokenEnumerator* token_enumerator() { return token_enumerator_; }
764
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000765 uint64_t GetObjectId(Address addr) { return ids_.FindObject(addr); }
766 void ObjectMoveEvent(Address from, Address to) { ids_.MoveObject(from, to); }
767
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000768 private:
769 INLINE(static bool HeapSnapshotsMatch(void* key1, void* key2)) {
770 return key1 == key2;
771 }
772
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000773 bool is_tracking_objects_; // Whether tracking object moves is needed.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000774 List<HeapSnapshot*> snapshots_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000775 // Mapping from snapshots' uids to HeapSnapshot* pointers.
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000776 HashMap snapshots_uids_;
777 StringsStorage names_;
778 TokenEnumerator* token_enumerator_;
ricow@chromium.org4980dff2010-07-19 08:33:45 +0000779 // Mapping from HeapObject addresses to objects' uids.
780 HeapObjectsMap ids_;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000781
782 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotsCollection);
783};
784
785
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000786// A typedef for referencing anything that can be snapshotted living
787// in any kind of heap memory.
788typedef void* HeapThing;
789
790
791// An interface that creates HeapEntries by HeapThings.
792class HeapEntriesAllocator {
793 public:
794 virtual ~HeapEntriesAllocator() { }
795 virtual HeapEntry* AllocateEntry(
796 HeapThing ptr, int children_count, int retainers_count) = 0;
797};
798
799
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000800// The HeapEntriesMap instance is used to track a mapping between
801// real heap objects and their representations in heap snapshots.
802class HeapEntriesMap {
803 public:
804 HeapEntriesMap();
805 ~HeapEntriesMap();
806
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000807 void AllocateEntries();
808 HeapEntry* Map(HeapThing thing);
809 void Pair(HeapThing thing, HeapEntriesAllocator* allocator, HeapEntry* entry);
810 void CountReference(HeapThing from, HeapThing to,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000811 int* prev_children_count = NULL,
812 int* prev_retainers_count = NULL);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000813
814 int entries_count() { return entries_count_; }
815 int total_children_count() { return total_children_count_; }
816 int total_retainers_count() { return total_retainers_count_; }
817
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000818 static HeapEntry *const kHeapEntryPlaceholder;
819
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000820 private:
821 struct EntryInfo {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000822 EntryInfo(HeapEntry* entry, HeapEntriesAllocator* allocator)
823 : entry(entry),
824 allocator(allocator),
825 children_count(0),
826 retainers_count(0) {
827 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000828 HeapEntry* entry;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000829 HeapEntriesAllocator* allocator;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000830 int children_count;
831 int retainers_count;
832 };
833
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000834 static uint32_t Hash(HeapThing thing) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000835 return ComputeIntegerHash(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000836 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(thing)));
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000837 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000838 static bool HeapThingsMatch(HeapThing key1, HeapThing key2) {
839 return key1 == key2;
840 }
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000841
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000842 HashMap entries_;
843 int entries_count_;
844 int total_children_count_;
845 int total_retainers_count_;
846
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000847 friend class HeapObjectsSet;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000848
849 DISALLOW_COPY_AND_ASSIGN(HeapEntriesMap);
850};
851
852
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000853class HeapObjectsSet {
854 public:
855 HeapObjectsSet();
856 void Clear();
857 bool Contains(Object* object);
858 void Insert(Object* obj);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000859 const char* GetTag(Object* obj);
860 void SetTag(Object* obj, const char* tag);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000861
862 private:
863 HashMap entries_;
864
865 DISALLOW_COPY_AND_ASSIGN(HeapObjectsSet);
866};
867
868
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000869// An interface used to populate a snapshot with nodes and edges.
870class SnapshotFillerInterface {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000871 public:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000872 virtual ~SnapshotFillerInterface() { }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000873 virtual HeapEntry* AddEntry(HeapThing ptr,
874 HeapEntriesAllocator* allocator) = 0;
875 virtual HeapEntry* FindEntry(HeapThing ptr) = 0;
876 virtual HeapEntry* FindOrAddEntry(HeapThing ptr,
877 HeapEntriesAllocator* allocator) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000878 virtual void SetIndexedReference(HeapGraphEdge::Type type,
879 HeapThing parent_ptr,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000880 HeapEntry* parent_entry,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000881 int index,
882 HeapThing child_ptr,
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000883 HeapEntry* child_entry) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000884 virtual void SetIndexedAutoIndexReference(HeapGraphEdge::Type type,
885 HeapThing parent_ptr,
886 HeapEntry* parent_entry,
887 HeapThing child_ptr,
888 HeapEntry* child_entry) = 0;
889 virtual void SetNamedReference(HeapGraphEdge::Type type,
890 HeapThing parent_ptr,
891 HeapEntry* parent_entry,
892 const char* reference_name,
893 HeapThing child_ptr,
894 HeapEntry* child_entry) = 0;
895 virtual void SetNamedAutoIndexReference(HeapGraphEdge::Type type,
896 HeapThing parent_ptr,
897 HeapEntry* parent_entry,
898 HeapThing child_ptr,
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000899 HeapEntry* child_entry) = 0;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000900};
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000901
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000902
903class SnapshottingProgressReportingInterface {
904 public:
905 virtual ~SnapshottingProgressReportingInterface() { }
906 virtual void ProgressStep() = 0;
907 virtual bool ProgressReport(bool force) = 0;
908};
909
910
911// An implementation of V8 heap graph extractor.
912class V8HeapExplorer : public HeapEntriesAllocator {
913 public:
914 V8HeapExplorer(HeapSnapshot* snapshot,
915 SnapshottingProgressReportingInterface* progress);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000916 virtual ~V8HeapExplorer();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000917 virtual HeapEntry* AllocateEntry(
918 HeapThing ptr, int children_count, int retainers_count);
919 void AddRootEntries(SnapshotFillerInterface* filler);
920 int EstimateObjectsCount();
921 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000922 void TagGlobalObjects();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000923
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000924 static HeapObject* const kInternalRootObject;
925
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000926 private:
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000927 HeapEntry* AddEntry(
928 HeapObject* object, int children_count, int retainers_count);
929 HeapEntry* AddEntry(HeapObject* object,
930 HeapEntry::Type type,
931 const char* name,
932 int children_count,
933 int retainers_count);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000934 const char* GetSystemEntryName(HeapObject* object);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000935 void ExtractReferences(HeapObject* obj);
936 void ExtractClosureReferences(JSObject* js_obj, HeapEntry* entry);
937 void ExtractPropertyReferences(JSObject* js_obj, HeapEntry* entry);
938 void ExtractElementReferences(JSObject* js_obj, HeapEntry* entry);
vegorov@chromium.org42841962010-10-18 11:18:59 +0000939 void ExtractInternalReferences(JSObject* js_obj, HeapEntry* entry);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000940 void SetClosureReference(HeapObject* parent_obj,
941 HeapEntry* parent,
942 String* reference_name,
943 Object* child);
944 void SetElementReference(HeapObject* parent_obj,
945 HeapEntry* parent,
946 int index,
947 Object* child);
948 void SetInternalReference(HeapObject* parent_obj,
949 HeapEntry* parent,
950 const char* reference_name,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000951 Object* child,
952 int field_offset = -1);
vegorov@chromium.org42841962010-10-18 11:18:59 +0000953 void SetInternalReference(HeapObject* parent_obj,
954 HeapEntry* parent,
955 int index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000956 Object* child,
957 int field_offset = -1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000958 void SetHiddenReference(HeapObject* parent_obj,
959 HeapEntry* parent,
960 int index,
961 Object* child);
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000962 void SetPropertyReference(HeapObject* parent_obj,
963 HeapEntry* parent,
964 String* reference_name,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 Object* child,
966 int field_offset = -1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000967 void SetPropertyShortcutReference(HeapObject* parent_obj,
968 HeapEntry* parent,
969 String* reference_name,
970 Object* child);
971 void SetRootShortcutReference(Object* child);
972 void SetRootGcRootsReference();
973 void SetGcRootsReference(Object* child);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000974 void TagObject(Object* obj, const char* tag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000975
976 HeapEntry* GetEntry(Object* obj);
977
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000978 Heap* heap_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000979 HeapSnapshot* snapshot_;
980 HeapSnapshotsCollection* collection_;
981 SnapshottingProgressReportingInterface* progress_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000982 SnapshotFillerInterface* filler_;
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000983 HeapObjectsSet objects_tags_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000984
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000985 static HeapObject* const kGcRootsObject;
986
987 friend class IndexedReferencesExtractor;
988 friend class RootsReferencesExtractor;
989
990 DISALLOW_COPY_AND_ASSIGN(V8HeapExplorer);
991};
992
993
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000994// An implementation of retained native objects extractor.
995class NativeObjectsExplorer : public HeapEntriesAllocator {
996 public:
997 NativeObjectsExplorer(HeapSnapshot* snapshot,
998 SnapshottingProgressReportingInterface* progress);
999 virtual ~NativeObjectsExplorer();
1000 virtual HeapEntry* AllocateEntry(
1001 HeapThing ptr, int children_count, int retainers_count);
1002 void AddRootEntries(SnapshotFillerInterface* filler);
1003 int EstimateObjectsCount();
1004 bool IterateAndExtractReferences(SnapshotFillerInterface* filler);
1005
1006 private:
1007 void FillRetainedObjects();
1008 List<HeapObject*>* GetListMaybeDisposeInfo(v8::RetainedObjectInfo* info);
1009 void SetNativeRootReference(v8::RetainedObjectInfo* info);
1010 void SetRootNativesRootReference();
1011 void SetWrapperNativeReferences(HeapObject* wrapper,
1012 v8::RetainedObjectInfo* info);
1013 void VisitSubtreeWrapper(Object** p, uint16_t class_id);
1014
1015 static uint32_t InfoHash(v8::RetainedObjectInfo* info) {
1016 return ComputeIntegerHash(static_cast<uint32_t>(info->GetHash()));
1017 }
1018 static bool RetainedInfosMatch(void* key1, void* key2) {
1019 return key1 == key2 ||
1020 (reinterpret_cast<v8::RetainedObjectInfo*>(key1))->IsEquivalent(
1021 reinterpret_cast<v8::RetainedObjectInfo*>(key2));
1022 }
1023
1024 HeapSnapshot* snapshot_;
1025 HeapSnapshotsCollection* collection_;
1026 SnapshottingProgressReportingInterface* progress_;
1027 bool embedder_queried_;
1028 HeapObjectsSet in_groups_;
1029 // RetainedObjectInfo* -> List<HeapObject*>*
1030 HashMap objects_by_info_;
1031 // Used during references extraction.
1032 SnapshotFillerInterface* filler_;
1033
1034 static HeapThing const kNativesRootObject;
1035
1036 friend class GlobalHandlesExtractor;
1037
1038 DISALLOW_COPY_AND_ASSIGN(NativeObjectsExplorer);
1039};
1040
1041
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001042class HeapSnapshotGenerator : public SnapshottingProgressReportingInterface {
1043 public:
1044 HeapSnapshotGenerator(HeapSnapshot* snapshot,
1045 v8::ActivityControl* control);
1046 bool GenerateSnapshot();
1047
1048 private:
1049 bool ApproximateRetainedSizes();
1050 bool BuildDominatorTree(const Vector<HeapEntry*>& entries,
1051 Vector<HeapEntry*>* dominators);
1052 bool CountEntriesAndReferences();
1053 bool FillReferences();
1054 void FillReversePostorderIndexes(Vector<HeapEntry*>* entries);
1055 void ProgressStep();
1056 bool ProgressReport(bool force = false);
1057 bool SetEntriesDominators();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001058 void SetProgressTotal(int iterations_count);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001059
1060 HeapSnapshot* snapshot_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001061 v8::ActivityControl* control_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001062 V8HeapExplorer v8_heap_explorer_;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +00001063 NativeObjectsExplorer dom_explorer_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001064 // Mapping from HeapThing pointers to HeapEntry* pointers.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001065 HeapEntriesMap entries_;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001066 // Used during snapshot generation.
1067 int progress_counter_;
1068 int progress_total_;
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00001069
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001070 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotGenerator);
1071};
1072
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001073class OutputStreamWriter;
1074
1075class HeapSnapshotJSONSerializer {
1076 public:
1077 explicit HeapSnapshotJSONSerializer(HeapSnapshot* snapshot)
1078 : snapshot_(snapshot),
1079 nodes_(ObjectsMatch),
1080 strings_(ObjectsMatch),
1081 next_node_id_(1),
1082 next_string_id_(1),
1083 writer_(NULL) {
1084 }
1085 void Serialize(v8::OutputStream* stream);
1086
1087 private:
1088 INLINE(static bool ObjectsMatch(void* key1, void* key2)) {
1089 return key1 == key2;
1090 }
1091
1092 INLINE(static uint32_t ObjectHash(const void* key)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001093 return ComputeIntegerHash(
1094 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(key)));
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001095 }
1096
1097 void EnumerateNodes();
1098 int GetNodeId(HeapEntry* entry);
1099 int GetStringId(const char* s);
1100 void SerializeEdge(HeapGraphEdge* edge);
1101 void SerializeImpl();
1102 void SerializeNode(HeapEntry* entry);
1103 void SerializeNodes();
1104 void SerializeSnapshot();
1105 void SerializeString(const unsigned char* s);
1106 void SerializeStrings();
1107 void SortHashMap(HashMap* map, List<HashMap::Entry*>* sorted_entries);
1108
1109 HeapSnapshot* snapshot_;
1110 HashMap nodes_;
1111 HashMap strings_;
1112 int next_node_id_;
1113 int next_string_id_;
1114 OutputStreamWriter* writer_;
1115
1116 friend class HeapSnapshotJSONSerializerEnumerator;
1117 friend class HeapSnapshotJSONSerializerIterator;
1118
1119 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotJSONSerializer);
1120};
1121
ager@chromium.orgbeb25712010-11-29 08:02:25 +00001122
1123String* GetConstructorNameForHeapProfile(JSObject* object);
1124
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001125} } // namespace v8::internal
1126
fschneider@chromium.org086aac62010-03-17 13:18:24 +00001127#endif // V8_PROFILE_GENERATOR_H_