OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 #ifndef VM_HEAP_PROFILER_H_ | |
6 #define VM_HEAP_PROFILER_H_ | |
7 | |
8 #include <set> | |
9 | |
10 #include "include/dart_api.h" | |
11 #include "vm/globals.h" | |
12 #include "vm/handles.h" | |
13 #include "vm/object.h" | |
14 #include "vm/visitor.h" | |
15 | |
16 namespace dart { | |
17 | |
18 // A HeapProfiler writes a snapshot of the heap for off-line analysis. | |
19 // The heap is written in binary HPROF format, which is a sequence of | |
20 // self describing records. A description of the HPROF format can be | |
21 // found at | |
22 // | |
23 // http://java.net/downloads/heap-snapshot/hprof-binary-format.html | |
24 // | |
25 // HPROF was not designed for Dart, but most Dart concepts can be | |
26 // mapped directly into HPROF. Some features, such as immediate | |
27 // objects and variable length objects, require a translation. | |
28 class HeapProfiler { | |
29 public: | |
30 enum Tag { | |
31 kStringInUtf8 = 0x01, | |
32 kLoadClass = 0x02, | |
33 kUnloadClass = 0x03, | |
34 kStackFrame = 0x04, | |
35 kStackTrace = 0x05, | |
36 kAllocSites = 0x06, | |
37 kHeapSummary = 0x07, | |
38 kStartThread = 0x0A, | |
39 kEndThread = 0x0B, | |
40 kHeapDump = 0x0C, | |
41 kCpuSamples = 0x0D, | |
42 kControlSettings = 0x0E, | |
43 kHeapDumpSummary = 0x1C, | |
44 kHeapDumpEnd = 0x2C | |
45 }; | |
46 | |
47 // Sub-record tags describe sub-records within a heap dump. | |
48 enum Subtag { | |
49 kRootJniGlobal = 0x01, | |
50 kRootJniLocal = 0x01, | |
51 kRootJavaFrame = 0x03, | |
52 kRootNativeStack = 0x04, | |
53 kRootStickyClass = 0x05, | |
54 kRootThreadBlock = 0x06, | |
55 kRootMonitorUsed = 0x07, | |
56 kRootThreadObject = 0x08, | |
57 kClassDump = 0x20, | |
58 kInstanceDump = 0x21, | |
59 kObjectArrayDump = 0x22, | |
60 kPrimitiveArrayDump = 0x23, | |
61 kRootUnknown = 0xFF | |
62 }; | |
63 | |
64 // Tags for describing element and field types. | |
65 enum BasicType { | |
66 kObject = 2, | |
67 kBoolean = 4, | |
68 kChar = 5, | |
69 kFloat = 6, | |
70 kDouble = 7, | |
71 kByte = 8, | |
72 kShort = 9, | |
73 kInt = 10, | |
74 kLong = 11 | |
75 }; | |
76 | |
77 // Object ids for fake classes. | |
78 // | |
79 // While not necessary to describe Dart programs, third party tools | |
80 // expect these types. These tools also interpret id values as raw | |
81 // addresses so we space them by 8 to not look like compressed oops. | |
82 enum FakeClass { | |
83 kJavaLangClass = 1, | |
84 kJavaLangClassLoader = 9, | |
85 kJavaLangObject = 17, | |
86 kJavaLangString = 25, | |
87 kArrayObject = 33, | |
88 kArrayBoolean = 41, | |
89 kArrayChar = 49, | |
90 kArrayFloat = 57, | |
91 kArrayDouble = 65, | |
92 kArrayByte = 73, | |
93 kArrayShort = 81, | |
94 kArrayInt = 89, | |
95 kArrayLong = 97 | |
96 }; | |
97 | |
98 static const int kObjectIdSize = sizeof(uint64_t); // NOLINT | |
99 | |
100 HeapProfiler(Dart_FileWriteCallback callback, void* stream); | |
101 ~HeapProfiler(); | |
102 | |
103 // Writes a root to the heap dump. | |
104 void WriteRoot(const RawObject* raw_obj); | |
105 | |
106 // Writes a object to the heap dump. | |
107 void WriteObject(const RawObject* raw_obj); | |
108 | |
109 private: | |
110 // Record tags describe top-level records. | |
111 // A growable array of bytes used to build a record body. | |
112 class Buffer { | |
113 public: | |
114 Buffer() : data_(0), size_(0), capacity_(0) { | |
115 } | |
116 ~Buffer(); | |
117 | |
118 // Writes an array of bytes to the buffer, increasing the capacity | |
119 // as needed. | |
120 void Write(const uint8_t* data, intptr_t length); | |
121 | |
122 // Returns the underlying element storage. | |
123 const uint8_t* Data() const { | |
124 return data_; | |
125 } | |
126 | |
127 // Returns the number of elements written to the buffer. | |
128 intptr_t Size() const { | |
129 return size_; | |
130 } | |
131 | |
132 private: | |
133 // Resizes the element storage, if needed. | |
134 void EnsureCapacity(intptr_t size); | |
135 | |
136 uint8_t* data_; | |
137 | |
138 intptr_t size_; | |
139 | |
140 // Size of the element storage. | |
141 intptr_t capacity_; | |
142 | |
143 DISALLOW_COPY_AND_ASSIGN(Buffer); | |
144 }; | |
145 | |
146 // A top-level data record. | |
147 class Record { | |
148 public: | |
149 Record(uint8_t tag, HeapProfiler* profiler) | |
150 : tag_(tag), profiler_(profiler) { | |
151 } | |
152 ~Record() { | |
153 profiler_->WriteRecord(*this); | |
154 } | |
155 | |
156 // Returns the tag describing the record format. | |
157 uint8_t Tag() const { | |
158 return tag_; | |
159 } | |
160 | |
161 // Returns a millisecond time delta, always 0. | |
162 uint8_t Time() const { | |
163 return 0; | |
164 } | |
165 | |
166 // Returns the record length in bytes. | |
167 uint32_t Length() const { | |
168 return body_.Size(); | |
169 } | |
170 | |
171 // Returns the record body. | |
172 const uint8_t* Body() const { | |
173 return body_.Data(); | |
174 } | |
175 | |
176 // Appends an array of 8-bit values to the record body. | |
177 void Write(const uint8_t* value, intptr_t size); | |
178 | |
179 // Appends an 8-, 16-, 32- or 64-bit value to the body in | |
180 // big-endian format. | |
181 void Write8(uint8_t value); | |
182 void Write16(uint16_t value); | |
183 void Write32(uint32_t value); | |
184 void Write64(uint64_t value); | |
185 | |
186 // Appends an ID to the body. | |
187 void WriteObjectId(const void* value); | |
188 | |
189 private: | |
190 // A tag value that describes the record format. | |
191 uint8_t tag_; | |
192 | |
193 // The payload of the record as described by the tag. | |
194 Buffer body_; | |
195 | |
196 // Parent object. | |
197 HeapProfiler* profiler_; | |
198 | |
199 DISALLOW_COPY_AND_ASSIGN(Record); | |
200 }; | |
201 | |
202 // A sub-record within a heap dump record. Write calls are | |
203 // forwarded to the profilers heap dump record instance. | |
204 class SubRecord { | |
205 public: | |
206 // Starts a new sub-record within the heap dump record. | |
207 SubRecord(uint8_t sub_tag, HeapProfiler* profiler); | |
208 ~SubRecord(); | |
209 | |
210 // Appends an array of 8-bit values to the heap dump record. | |
211 void Write(const uint8_t* value, intptr_t size); | |
212 | |
213 // Appends an 8-, 16-, 32- or 64-bit value to the heap dump | |
214 // record. | |
215 void Write8(uint8_t value); | |
216 void Write16(uint16_t value); | |
217 void Write32(uint32_t value); | |
218 void Write64(uint64_t value); | |
219 | |
220 // Appends an ID to the current heap dump record. | |
221 void WriteObjectId(const void* value); | |
222 | |
223 private: | |
224 // The record instance that receives forwarded write calls. | |
225 Record* record_; | |
226 }; | |
227 | |
228 // Id canonizers. | |
229 const RawClass* ClassId(const RawClass* raw_class); | |
230 const RawObject* ObjectId(const RawObject* raw_obj); | |
231 const char* StringId(const char* c_string); | |
232 const RawString* StringId(const RawString* raw_string); | |
233 | |
234 // Invokes the write callback. | |
235 void Write(const void* data, intptr_t size); | |
236 | |
237 // Writes the binary hprof header to the output stream. | |
238 void WriteHeader(); | |
239 | |
240 // Writes a record to the output stream. | |
241 void WriteRecord(const Record& record); | |
242 | |
243 // Writes a string in utf-8 record to the output stream. | |
244 void WriteStringInUtf8(const char* c_string); | |
245 void WriteStringInUtf8(const RawString* raw_string); | |
246 | |
247 // Writes a load class record to the output stream. | |
248 void WriteLoadClass(const RawClass* raw_class); | |
249 void WriteFakeLoadClass(FakeClass fake_class, const char* class_name); | |
250 | |
251 // Writes an empty stack trace to the output stream. | |
252 void WriteStackTrace(); | |
253 | |
254 // Writes a heap summary record to the output stream. | |
255 void WriteHeapSummary(uint32_t total_live_bytes, | |
256 uint32_t total_live_instances, | |
257 uint64_t total_bytes_allocated, | |
258 uint64_t total_instances_allocated); | |
259 | |
260 // Writes a heap dump record to the output stream. | |
261 void WriteHeapDump(); | |
262 | |
263 // Writes a sub-record to the heap dump record. | |
264 void WriteClassDump(const RawClass* raw_class); | |
265 void WriteFakeClassDump(FakeClass fake_class, FakeClass fake_super_class); | |
266 void WriteInstanceDump(const RawObject* raw_obj); | |
267 void WriteSmiInstanceDump(const RawSmi* raw_smi); | |
268 void WriteObjectArrayDump(const RawArray* raw_array); | |
269 void WritePrimitiveArrayDump(const RawTypedData* raw_byte_array, uint8_t tag); | |
270 | |
271 static const RawClass* GetClass(const RawObject* raw_obj); | |
272 static const RawClass* GetSuperClass(const RawClass* raw_class); | |
273 | |
274 Dart_FileWriteCallback write_callback_; | |
275 | |
276 void* output_stream_; | |
277 | |
278 Record* heap_dump_record_; | |
279 | |
280 std::set<const RawSmi*> smi_table_; | |
281 std::set<const RawClass*> class_table_; | |
282 std::set<const RawString*> string_table_; | |
283 | |
284 DISALLOW_COPY_AND_ASSIGN(HeapProfiler); | |
285 }; | |
286 | |
287 | |
288 // Writes a root sub-record to the heap dump for every strong handle. | |
289 class HeapProfilerRootVisitor : public ObjectPointerVisitor { | |
290 public: | |
291 explicit HeapProfilerRootVisitor(HeapProfiler* profiler) | |
292 : ObjectPointerVisitor(Isolate::Current()), | |
293 profiler_(profiler) { | |
294 } | |
295 | |
296 virtual void VisitPointers(RawObject** first, RawObject** last); | |
297 | |
298 private: | |
299 HeapProfiler* profiler_; | |
300 DISALLOW_IMPLICIT_CONSTRUCTORS(HeapProfilerRootVisitor); | |
301 }; | |
302 | |
303 | |
304 // Writes a root sub-record to the heap dump for every weak handle. | |
305 class HeapProfilerWeakRootVisitor : public HandleVisitor { | |
306 public: | |
307 explicit HeapProfilerWeakRootVisitor(HeapProfilerRootVisitor* visitor) | |
308 : visitor_(visitor) { | |
309 } | |
310 | |
311 virtual void VisitHandle(uword addr); | |
312 | |
313 private: | |
314 HeapProfilerRootVisitor* visitor_; | |
315 DISALLOW_COPY_AND_ASSIGN(HeapProfilerWeakRootVisitor); | |
316 }; | |
317 | |
318 | |
319 // Writes a sub-record to the heap dump for every object in the heap. | |
320 class HeapProfilerObjectVisitor : public ObjectVisitor { | |
321 public: | |
322 HeapProfilerObjectVisitor(Isolate* isolate, HeapProfiler* profiler) | |
323 : ObjectVisitor(isolate), profiler_(profiler) { | |
324 } | |
325 | |
326 virtual void VisitObject(RawObject* obj); | |
327 | |
328 private: | |
329 HeapProfiler* profiler_; | |
330 DISALLOW_COPY_AND_ASSIGN(HeapProfilerObjectVisitor); | |
331 }; | |
332 | |
333 } // namespace dart | |
334 | |
335 #endif // VM_HEAP_PROFILER_H_ | |
OLD | NEW |