4726853cfe
Review URL: https://codereview.chromium.org//11881010 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@17036 260f80e4-7a28-3924-810f-c04153c831b5
338 lines
9.1 KiB
C++
338 lines
9.1 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#ifndef VM_HEAP_PROFILER_H_
|
|
#define VM_HEAP_PROFILER_H_
|
|
|
|
#include <set>
|
|
|
|
#include "include/dart_api.h"
|
|
#include "vm/globals.h"
|
|
#include "vm/handles.h"
|
|
#include "vm/object.h"
|
|
#include "vm/visitor.h"
|
|
|
|
namespace dart {
|
|
|
|
// A HeapProfiler writes a snapshot of the heap for off-line analysis.
|
|
// The heap is written in binary HPROF format, which is a sequence of
|
|
// self describing records. A description of the HPROF format can be
|
|
// found at
|
|
//
|
|
// http://java.net/downloads/heap-snapshot/hprof-binary-format.html
|
|
//
|
|
// HPROF was not designed for Dart, but most Dart concepts can be
|
|
// mapped directly into HPROF. Some features, such as immediate
|
|
// objects and variable length objects, require a translation.
|
|
class HeapProfiler {
|
|
public:
|
|
enum Tag {
|
|
kStringInUtf8 = 0x01,
|
|
kLoadClass = 0x02,
|
|
kUnloadClass = 0x03,
|
|
kStackFrame = 0x04,
|
|
kStackTrace = 0x05,
|
|
kAllocSites = 0x06,
|
|
kHeapSummary = 0x07,
|
|
kStartThread = 0x0A,
|
|
kEndThread = 0x0B,
|
|
kHeapDump = 0x0C,
|
|
kCpuSamples = 0x0D,
|
|
kControlSettings = 0x0E,
|
|
kHeapDumpSummary = 0x1C,
|
|
kHeapDumpEnd = 0x2C
|
|
};
|
|
|
|
// Sub-record tags describe sub-records within a heap dump.
|
|
enum Subtag {
|
|
kRootJniGlobal = 0x01,
|
|
kRootJniLocal = 0x01,
|
|
kRootJavaFrame = 0x03,
|
|
kRootNativeStack = 0x04,
|
|
kRootStickyClass = 0x05,
|
|
kRootThreadBlock = 0x06,
|
|
kRootMonitorUsed = 0x07,
|
|
kRootThreadObject = 0x08,
|
|
kClassDump = 0x20,
|
|
kInstanceDump = 0x21,
|
|
kObjectArrayDump = 0x22,
|
|
kPrimitiveArrayDump = 0x23,
|
|
kRootUnknown = 0xFF
|
|
};
|
|
|
|
// Tags for describing element and field types.
|
|
enum BasicType {
|
|
kObject = 2,
|
|
kBoolean = 4,
|
|
kChar = 5,
|
|
kFloat = 6,
|
|
kDouble = 7,
|
|
kByte = 8,
|
|
kShort = 9,
|
|
kInt = 10,
|
|
kLong = 11
|
|
};
|
|
|
|
// Object ids for fake classes.
|
|
//
|
|
// While not necessary to describe Dart programs, third party tools
|
|
// expect these types. These tools also interpret id values as raw
|
|
// addresses so we space them by 8 to not look like compressed oops.
|
|
enum FakeClass {
|
|
kJavaLangClass = 1,
|
|
kJavaLangClassLoader = 9,
|
|
kJavaLangObject = 17,
|
|
kJavaLangString = 25,
|
|
kArrayObject = 33,
|
|
kArrayBoolean = 41,
|
|
kArrayChar = 49,
|
|
kArrayFloat = 57,
|
|
kArrayDouble = 65,
|
|
kArrayByte = 73,
|
|
kArrayShort = 81,
|
|
kArrayInt = 89,
|
|
kArrayLong = 97
|
|
};
|
|
|
|
static const int kObjectIdSize = sizeof(uint64_t); // NOLINT
|
|
|
|
HeapProfiler(Dart_FileWriteCallback callback, void* stream);
|
|
~HeapProfiler();
|
|
|
|
// Writes a root to the heap dump.
|
|
void WriteRoot(const RawObject* raw_obj);
|
|
|
|
// Writes a object to the heap dump.
|
|
void WriteObject(const RawObject* raw_obj);
|
|
|
|
private:
|
|
// Record tags describe top-level records.
|
|
// A growable array of bytes used to build a record body.
|
|
class Buffer {
|
|
public:
|
|
Buffer() : data_(0), size_(0), capacity_(0) {
|
|
}
|
|
~Buffer();
|
|
|
|
// Writes an array of bytes to the buffer, increasing the capacity
|
|
// as needed.
|
|
void Write(const uint8_t* data, intptr_t length);
|
|
|
|
// Returns the underlying element storage.
|
|
const uint8_t* Data() const {
|
|
return data_;
|
|
}
|
|
|
|
// Returns the number of elements written to the buffer.
|
|
intptr_t Size() const {
|
|
return size_;
|
|
}
|
|
|
|
private:
|
|
// Resizes the element storage, if needed.
|
|
void EnsureCapacity(intptr_t size);
|
|
|
|
uint8_t* data_;
|
|
|
|
intptr_t size_;
|
|
|
|
// Size of the element storage.
|
|
intptr_t capacity_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(Buffer);
|
|
};
|
|
|
|
// A top-level data record.
|
|
class Record {
|
|
public:
|
|
Record(uint8_t tag, HeapProfiler* profiler)
|
|
: tag_(tag), profiler_(profiler) {
|
|
}
|
|
~Record() {
|
|
profiler_->WriteRecord(*this);
|
|
}
|
|
|
|
// Returns the tag describing the record format.
|
|
uint8_t Tag() const {
|
|
return tag_;
|
|
}
|
|
|
|
// Returns a millisecond time delta, always 0.
|
|
uint8_t Time() const {
|
|
return 0;
|
|
}
|
|
|
|
// Returns the record length in bytes.
|
|
uint32_t Length() const {
|
|
return body_.Size();
|
|
}
|
|
|
|
// Returns the record body.
|
|
const uint8_t* Body() const {
|
|
return body_.Data();
|
|
}
|
|
|
|
// Appends an array of 8-bit values to the record body.
|
|
void Write(const uint8_t* value, intptr_t size);
|
|
|
|
// Appends an 8-, 16-, 32- or 64-bit value to the body in
|
|
// big-endian format.
|
|
void Write8(uint8_t value);
|
|
void Write16(uint16_t value);
|
|
void Write32(uint32_t value);
|
|
void Write64(uint64_t value);
|
|
|
|
// Appends an ID to the body.
|
|
void WriteObjectId(const void* value);
|
|
|
|
private:
|
|
// A tag value that describes the record format.
|
|
uint8_t tag_;
|
|
|
|
// The payload of the record as described by the tag.
|
|
Buffer body_;
|
|
|
|
// Parent object.
|
|
HeapProfiler* profiler_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(Record);
|
|
};
|
|
|
|
// A sub-record within a heap dump record. Write calls are
|
|
// forwarded to the profilers heap dump record instance.
|
|
class SubRecord {
|
|
public:
|
|
// Starts a new sub-record within the heap dump record.
|
|
SubRecord(uint8_t sub_tag, HeapProfiler* profiler);
|
|
~SubRecord();
|
|
|
|
// Appends an array of 8-bit values to the heap dump record.
|
|
void Write(const uint8_t* value, intptr_t size);
|
|
|
|
// Appends an 8-, 16-, 32- or 64-bit value to the heap dump
|
|
// record.
|
|
void Write8(uint8_t value);
|
|
void Write16(uint16_t value);
|
|
void Write32(uint32_t value);
|
|
void Write64(uint64_t value);
|
|
|
|
// Appends an ID to the current heap dump record.
|
|
void WriteObjectId(const void* value);
|
|
|
|
private:
|
|
// The record instance that receives forwarded write calls.
|
|
Record* record_;
|
|
};
|
|
|
|
// Id canonizers.
|
|
const RawClass* ClassId(const RawClass* raw_class);
|
|
const RawObject* ObjectId(const RawObject* raw_obj);
|
|
const char* StringId(const char* c_string);
|
|
const RawString* StringId(const RawString* raw_string);
|
|
|
|
// Invokes the write callback.
|
|
void Write(const void* data, intptr_t size);
|
|
|
|
// Writes the binary hprof header to the output stream.
|
|
void WriteHeader();
|
|
|
|
// Writes a record to the output stream.
|
|
void WriteRecord(const Record& record);
|
|
|
|
// Writes a string in utf-8 record to the output stream.
|
|
void WriteStringInUtf8(const char* c_string);
|
|
void WriteStringInUtf8(const RawString* raw_string);
|
|
|
|
// Writes a load class record to the output stream.
|
|
void WriteLoadClass(const RawClass* raw_class);
|
|
void WriteFakeLoadClass(FakeClass fake_class, const char* class_name);
|
|
|
|
// Writes an empty stack trace to the output stream.
|
|
void WriteStackTrace();
|
|
|
|
// Writes a heap summary record to the output stream.
|
|
void WriteHeapSummary(uint32_t total_live_bytes,
|
|
uint32_t total_live_instances,
|
|
uint64_t total_bytes_allocated,
|
|
uint64_t total_instances_allocated);
|
|
|
|
// Writes a heap dump record to the output stream.
|
|
void WriteHeapDump();
|
|
|
|
// Writes a sub-record to the heap dump record.
|
|
void WriteClassDump(const RawClass* raw_class);
|
|
void WriteFakeClassDump(FakeClass fake_class, FakeClass fake_super_class);
|
|
void WriteInstanceDump(const RawObject* raw_obj);
|
|
void WriteSmiInstanceDump(const RawSmi* raw_smi);
|
|
void WriteObjectArrayDump(const RawArray* raw_array);
|
|
void WritePrimitiveArrayDump(const RawByteArray* raw_byte_array,
|
|
uint8_t tag,
|
|
const void* data);
|
|
|
|
static const RawClass* GetClass(const RawObject* raw_obj);
|
|
static const RawClass* GetSuperClass(const RawClass* raw_class);
|
|
|
|
Dart_FileWriteCallback write_callback_;
|
|
|
|
void* output_stream_;
|
|
|
|
Record* heap_dump_record_;
|
|
|
|
std::set<const RawSmi*> smi_table_;
|
|
std::set<const RawClass*> class_table_;
|
|
std::set<const RawString*> string_table_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(HeapProfiler);
|
|
};
|
|
|
|
|
|
// Writes a root sub-record to the heap dump for every strong handle.
|
|
class HeapProfilerRootVisitor : public ObjectPointerVisitor {
|
|
public:
|
|
explicit HeapProfilerRootVisitor(HeapProfiler* profiler)
|
|
: ObjectPointerVisitor(Isolate::Current()),
|
|
profiler_(profiler) {
|
|
}
|
|
|
|
virtual void VisitPointers(RawObject** first, RawObject** last);
|
|
|
|
private:
|
|
HeapProfiler* profiler_;
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(HeapProfilerRootVisitor);
|
|
};
|
|
|
|
|
|
// Writes a root sub-record to the heap dump for every weak handle.
|
|
class HeapProfilerWeakRootVisitor : public HandleVisitor {
|
|
public:
|
|
explicit HeapProfilerWeakRootVisitor(HeapProfilerRootVisitor* visitor)
|
|
: visitor_(visitor) {
|
|
}
|
|
|
|
virtual void VisitHandle(uword addr);
|
|
|
|
private:
|
|
HeapProfilerRootVisitor* visitor_;
|
|
DISALLOW_COPY_AND_ASSIGN(HeapProfilerWeakRootVisitor);
|
|
};
|
|
|
|
|
|
// Writes a sub-record to the heap dump for every object in the heap.
|
|
class HeapProfilerObjectVisitor : public ObjectVisitor {
|
|
public:
|
|
HeapProfilerObjectVisitor(Isolate* isolate, HeapProfiler* profiler)
|
|
: ObjectVisitor(isolate), profiler_(profiler) {
|
|
}
|
|
|
|
virtual void VisitObject(RawObject* obj);
|
|
|
|
private:
|
|
HeapProfiler* profiler_;
|
|
DISALLOW_COPY_AND_ASSIGN(HeapProfilerObjectVisitor);
|
|
};
|
|
|
|
} // namespace dart
|
|
|
|
#endif // VM_HEAP_PROFILER_H_
|