| 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 |