blob: 117b46f467073251541955a8ecad7bceab38c20e [file] [log] [blame]
// 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 RawTypedData* raw_byte_array, uint8_t tag);
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_