Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2710)

Unified Diff: runtime/vm/heap_trace.cc

Issue 11428067: Merge the Merlin heap tracing to top-of-trunk. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: address review comments Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/heap_trace.h ('k') | runtime/vm/heap_trace_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/heap_trace.cc
diff --git a/runtime/vm/heap_trace.cc b/runtime/vm/heap_trace.cc
new file mode 100644
index 0000000000000000000000000000000000000000..56282c22cc013f110b9cdead17f932e50396c9aa
--- /dev/null
+++ b/runtime/vm/heap_trace.cc
@@ -0,0 +1,488 @@
+// 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.
+
+#include "vm/heap_trace.h"
+
+#include "include/dart_api.h"
+#include "vm/dart_api_state.h"
+#include "vm/debugger.h"
+#include "vm/isolate.h"
+#include "vm/object.h"
+#include "vm/object_set.h"
+#include "vm/object_store.h"
+#include "vm/os.h"
+#include "vm/stack_frame.h"
+#include "vm/unicode.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, heap_trace, false, "Enable heap tracing.");
+
+Dart_FileOpenCallback HeapTrace::open_callback_ = NULL;
+Dart_FileWriteCallback HeapTrace::write_callback_ = NULL;
+Dart_FileCloseCallback HeapTrace::close_callback_ = NULL;
+bool HeapTrace::is_enabled_ = false;
+
+class HeapTraceVisitor : public ObjectPointerVisitor {
+ public:
+ HeapTraceVisitor(Isolate* isolate,
+ HeapTrace* heap_trace,
+ ObjectSet* object_set)
+ : ObjectPointerVisitor(isolate),
+ heap_trace_(heap_trace),
+ vm_isolate_(Dart::vm_isolate()),
+ object_set_(object_set) {
+ }
+
+ void VisitPointers(RawObject** first, RawObject** last) {
+ for (RawObject** current = first; current <= last; current++) {
+ RawObject* raw_obj = *current;
+
+ // We only care about objects in the heap
+ // Also, since this visitor will frequently be encountering redudant
+ // roots, we use an object_set to skip the duplicates.
+ if (raw_obj->IsHeapObject() &&
+ raw_obj != reinterpret_cast<RawObject*>(0x1) &&
+ raw_obj != reinterpret_cast<RawObject*>(0xabababab) &&
+ !object_set_->Contains(raw_obj) &&
+ !vm_isolate_->heap()->Contains(RawObject::ToAddr(raw_obj))) {
+ object_set_->Add(raw_obj);
+ uword addr = RawObject::ToAddr(raw_obj);
+ heap_trace_->TraceSingleRoot(addr);
+ }
+ }
+ }
+
+ private:
+ HeapTrace* heap_trace_;
+ Isolate* vm_isolate_;
+ // TODO(cshapiro): replace with a sparse data structure.
+ ObjectSet* object_set_;
+ DISALLOW_COPY_AND_ASSIGN(HeapTraceVisitor);
+};
+
+
+class HeapTraceScopedHandleVisitor : public ObjectPointerVisitor {
+ public:
+ HeapTraceScopedHandleVisitor(Isolate* isolate, HeapTrace* heap_trace)
+ : ObjectPointerVisitor(isolate), heap_trace_(heap_trace) {
+ }
+
+ void VisitPointers(RawObject** first, RawObject** last) {
+ for (RawObject** current = first; current <= last; current++) {
+ RawObject* raw_obj = *current;
+ Heap* heap = isolate()->heap();
+
+ // We only care about objects in the heap
+ if (raw_obj->IsHeapObject() &&
+ raw_obj != reinterpret_cast<RawObject*>(0x1) &&
+ raw_obj != reinterpret_cast<RawObject*>(0xabababab) &&
+ heap->Contains(RawObject::ToAddr(raw_obj))) {
+ uword addr = RawObject::ToAddr(raw_obj);
+ heap_trace_->TraceScopedHandle(addr);
+ }
+ }
+ }
+
+ private:
+ HeapTrace* heap_trace_;
+ DISALLOW_COPY_AND_ASSIGN(HeapTraceScopedHandleVisitor);
+};
+
+
+class HeapTraceObjectStoreVisitor : public ObjectPointerVisitor {
+ public:
+ HeapTraceObjectStoreVisitor(Isolate* isolate, HeapTrace* heap_trace)
+ : ObjectPointerVisitor(isolate), heap_trace_(heap_trace) {
+ }
+
+ void VisitPointers(RawObject** first, RawObject** last) {
+ for (RawObject** current = first; current <= last; current++) {
+ RawObject* raw_obj = *current;
+
+ // We only care about obects in the heap.
+ if (raw_obj->IsHeapObject() &&
+ raw_obj != reinterpret_cast<RawObject*>(0x1) &&
+ raw_obj != reinterpret_cast<RawObject*>(0xabababab)) {
+ uword addr = RawObject::ToAddr(raw_obj);
+ heap_trace_->TraceObjectStorePointer(addr);
+ }
+ }
+ }
+
+ private:
+ HeapTrace* heap_trace_;
+ DISALLOW_COPY_AND_ASSIGN(HeapTraceObjectStoreVisitor);
+};
+
+
+class HeapTraceInitialHeapVisitor : public ObjectVisitor {
+ public:
+ HeapTraceInitialHeapVisitor(Isolate* isolate, HeapTrace* heap_trace)
+ : ObjectVisitor(isolate), heap_trace_(heap_trace) {}
+
+ void VisitObject(RawObject* raw_obj) {
+ heap_trace_->TraceSnapshotAlloc(raw_obj, raw_obj->Size());
+ }
+
+ private:
+ HeapTrace* heap_trace_;
+ DISALLOW_COPY_AND_ASSIGN(HeapTraceInitialHeapVisitor);
+};
+
+
+HeapTrace::HeapTrace() : isolate_initialized_(false), output_stream_(NULL) {
+}
+
+
+HeapTrace::~HeapTrace() {
+ if (isolate_initialized_) {
+ (*close_callback_)(output_stream_);
+ }
+}
+
+
+void HeapTrace::InitOnce(Dart_FileOpenCallback open_callback,
+ Dart_FileWriteCallback write_callback,
+ Dart_FileCloseCallback close_callback) {
+ ASSERT(open_callback != NULL);
+ ASSERT(write_callback != NULL);
+ ASSERT(close_callback != NULL);
+ HeapTrace::open_callback_ = open_callback;
+ HeapTrace::write_callback_ = write_callback;
+ HeapTrace::close_callback_ = close_callback;
+ HeapTrace::is_enabled_ = true;
+}
+
+
+ObjectSet* HeapTrace::CreateEmptyObjectSet() const {
+ Isolate* isolate = Isolate::Current();
+ uword start, end;
+ isolate->heap()->StartEndAddress(&start, &end);
+
+ Isolate* vm_isolate = Dart::vm_isolate();
+ uword vm_start, vm_end;
+ vm_isolate->heap()->StartEndAddress(&vm_start, &vm_end);
+
+ ObjectSet* allocated_set = new ObjectSet(Utils::Minimum(start, vm_start),
+ Utils::Maximum(end, vm_end));
+
+ return allocated_set;
+}
+
+
+void HeapTrace::ResizeObjectSet() {
+ Isolate* isolate = Isolate::Current();
+ uword start, end;
+ isolate->heap()->StartEndAddress(&start, &end);
+ Isolate* vm_isolate = Dart::vm_isolate();
+ uword vm_start, vm_end;
+ vm_isolate->heap()->StartEndAddress(&vm_start, &vm_end);
+ object_set_.Resize(Utils::Minimum(start, vm_start),
+ Utils::Maximum(end, vm_end));
+}
+
+
+void HeapTrace::Init(Isolate* isolate) {
+ // Do not trace the VM isolate
+ if (isolate == Dart::vm_isolate()) {
+ return;
+ }
+ ASSERT(isolate_initialized_ == false);
+ const char* format = "%s.htrace";
+ intptr_t len = OS::SNPrint(NULL, 0, format, isolate->name());
+ char* filename = new char[len + 1];
+ OS::SNPrint(filename, len + 1, format, isolate->name());
+ output_stream_ = (*open_callback_)(filename);
+ ASSERT(output_stream_ != NULL);
+ delete[] filename;
+ isolate_initialized_ = true;
+
+ HeapTraceObjectStoreVisitor object_store_visitor(isolate, this);
+ isolate->object_store()->VisitObjectPointers(&object_store_visitor);
+
+ // Visit any objects that may have been allocated during startup,
+ // before we started tracing.
+ HeapTraceInitialHeapVisitor heap_visitor(isolate, this);
+ isolate->heap()->IterateObjects(&heap_visitor);
+ TraceRoots(isolate);
+}
+
+
+// Allocation Record - 'A' (0x41)
+//
+// Format:
+// 'A'
+// uword - address of allocated object
+// uword - size of allocated object
+void HeapTrace::TraceAllocation(uword addr, intptr_t size) {
+ if (isolate_initialized_) {
+ {
+ AllocationRecord rec(this);
+ rec.Write(addr);
+ rec.Write(size);
+ }
+ TraceRoots(Isolate::Current());
+ }
+}
+
+
+// Snapshot Allocation Record - 'B' (0x41)
+//
+// Format:
+// 'B'
+// uword - address of allocated object
+// uword - size of allocated object
+void HeapTrace::TraceSnapshotAlloc(RawObject* obj, intptr_t size) {
+ if (isolate_initialized_) {
+ SnapshotAllocationRecord rec(this);
+ rec.Write(RawObject::ToAddr(obj));
+ rec.Write(static_cast<uword>(size));
+ }
+}
+
+
+// Allocate Zone Handle Record - 'Z' (0x5a)
+//
+// Format:
+// 'Z'
+// uword - handle address (where the handle is pointing)
+// uword - zone address (address of the zone the handle is in)
+void HeapTrace::TraceAllocateZoneHandle(uword handle, uword zone_addr) {
+ if (isolate_initialized_) {
+ AllocZoneHandleRecord rec(this);
+ rec.Write(handle);
+ rec.Write(zone_addr);
+ }
+}
+
+
+// Delete Zone Record - 'z' (0x7a)
+//
+// Format:
+// 'z'
+// uword - zone address (all the handles in that zone are now gone)
+void HeapTrace::TraceDeleteZone(Zone* zone) {
+ if (isolate_initialized_) {
+ DeleteZoneRecord rec(this);
+ rec.Write(reinterpret_cast<uword>(zone));
+ }
+}
+
+
+// Delete Scoped Hanldes Record - 's' (0x73)
+//
+// Format:
+// 's'
+void HeapTrace::TraceDeleteScopedHandles() {
+ if (isolate_initialized_) {
+ DeleteScopedHandlesRecord rec(this);
+ }
+}
+
+
+// Copy Record - 'C' (0x43)
+//
+// Format:
+// 'C'
+// uword - old address
+// uword - new address
+void HeapTrace::TraceCopy(uword from_addr, uword to_addr) {
+ if (isolate_initialized_) {
+ CopyRecord rec(this);
+ rec.Write(from_addr);
+ rec.Write(to_addr);
+ }
+}
+
+
+// Object Store Recorda - 'O'(0x4f)
+//
+// Format:
+// 'O'
+// uword - address
+void HeapTrace::TraceObjectStorePointer(uword addr) {
+ if (isolate_initialized_) {
+ ObjectStoreRecord rec(this);
+ rec.Write(addr);
+ }
+}
+
+
+// Promotion Records - 'P' (0x50)
+//
+// Format:
+// 'P'
+// uword - old address
+// uword - new address
+void HeapTrace::TracePromotion(uword old_addr, uword promoted_addr) {
+ if (isolate_initialized_) {
+ PromotionRecord rec(this);
+ rec.Write(old_addr);
+ rec.Write(promoted_addr);
+ }
+}
+
+
+// Death Range Record - 'L' (0x4c)
+//
+// Format:
+// 'L'
+// uword - inclusive start address of the space being left
+// uword - exclusive end address of the space being left
+void HeapTrace::TraceDeathRange(uword inclusive_start, uword exclusive_end) {
+ if (isolate_initialized_) {
+ DeathRangeRecord rec(this);
+ rec.Write(inclusive_start);
+ rec.Write(exclusive_end);
+ }
+}
+
+
+// Register Class Record - 'K' (0x4b)
+//
+// Format:
+// 'K'
+// uword - address ( the address of the class)
+void HeapTrace::TraceRegisterClass(const Class& cls) {
+ if (isolate_initialized_) {
+ RegisterClassRecord rec(this);
+ rec.Write(RawObject::ToAddr(cls.raw()));
+ }
+}
+
+
+// Scoped Handle Record - 'H' (0x48)
+//
+// Format:
+// 'H'
+// uword - adress of the scoped handle (where it is pointing)
+void HeapTrace::TraceScopedHandle(uword handle) {
+ if (isolate_initialized_) {
+ AllocScopedHandleRecord rec(this);
+ rec.Write(handle);
+ }
+}
+
+
+// Root Record - 'R' (0x52)
+//
+// Format:
+// 'R'
+// uword - address
+void HeapTrace::TraceSingleRoot(uword root_addr) {
+ if (isolate_initialized_) {
+ RootRecord rec(this);
+ rec.Write(root_addr);
+ }
+}
+
+
+// Sweep Record - 'S'
+//
+// Format:
+// 'S'
+// uword - address
+void HeapTrace::TraceSweep(uword sweept_addr) {
+ if (isolate_initialized_) {
+ SweepRecord rec(this);
+ rec.Write(sweept_addr);
+ }
+}
+
+
+// Does not output any records directly,
+// but does call TraceSingleRoot
+void HeapTrace::TraceRoots(Isolate* isolate) {
+ if (isolate_initialized_) {
+ ResizeObjectSet();
+ HeapTraceVisitor visitor(isolate, this, &object_set_);
+ HeapTraceScopedHandleVisitor handle_visitor(isolate, this);
+
+ bool visit_prologue_weak_handles = true;
+ bool validate_frames = false;
+
+ // Visit objects in per isolate stubs.
+ StubCode::VisitObjectPointers(&visitor);
+
+ // stack
+ StackFrameIterator frames_iterator(validate_frames);
+ StackFrame* frame = frames_iterator.NextFrame();
+ while (frame != NULL) {
+ frame->VisitObjectPointers(&visitor);
+ frame = frames_iterator.NextFrame();
+ }
+
+ if (isolate->api_state() != NULL) {
+ isolate->api_state()->VisitObjectPointers(&visitor,
+ visit_prologue_weak_handles);
+ }
+
+ // Visit the top context which is stored in the isolate.
+ RawContext* top_context = isolate->top_context();
+ visitor.VisitPointer(reinterpret_cast<RawObject**>(&top_context));
+
+ // Visit the currently active IC data array.
+ RawArray* ic_data_array = isolate->ic_data_array();
+ visitor.VisitPointer(reinterpret_cast<RawObject**>(&ic_data_array));
+
+ // Visit objects in the debugger.
+ isolate->debugger()->VisitObjectPointers(&visitor);
+
+ isolate->current_zone()->handles()->
+ VisitUnvisitedScopedHandles(&handle_visitor);
+
+ object_set_.FastClear();
+ }
+}
+
+
+// Store Record - 'U' (0x55)
+//
+// Format:
+// 'U'
+// uword - originating object address (where a pointer is being stored)
+// uword - byte offset into origin where the pointer is being stored
+// uword - value of the pointer being stored
+void HeapTrace::TraceStoreIntoObject(uword object,
+ uword field_addr,
+ uword value) {
+ if (isolate_initialized_) {
+ // We don't care about pointers into the VM_Islate heap, so skip them.
+ // There should not be any pointers /out/ of the VM isolate; so we
+ // do not check object.
+ if (Isolate::Current()->heap()->Contains(value)) {
+ StoreRecord rec(this);
+ uword slot_offset = field_addr - object;
+
+ rec.Write(object);
+ rec.Write(slot_offset);
+ rec.Write(value);
+ }
+ }
+}
+
+
+// Mark Sweep Start Record - '{' (0x7b)
+//
+// Format:
+// '{'
+void HeapTrace::TraceMarkSweepStart() {
+ if (isolate_initialized_) {
+ MarkSweepStartRecord rec(this);
+ }
+}
+
+
+// Mark Sweep Finish Record - '}' (0x7d)
+//
+// Format:
+// '}'
+void HeapTrace::TraceMarkSweepFinish() {
+ if (isolate_initialized_) {
+ MarkSweepFinishRecord rec(this);
+ }
+}
+
+} // namespace dart
« no previous file with comments | « runtime/vm/heap_trace.h ('k') | runtime/vm/heap_trace_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698