From c748e7bbc9c0a3bbeff26bc899ae7f7401115c17 Mon Sep 17 00:00:00 2001 From: "loislo@chromium.org" Date: Fri, 18 Oct 2013 09:40:00 +0000 Subject: [PATCH] HeapProfiler: for the test purposes we would like to trace object movements. When we have an untracked allocations we need to fix it. It is a bit tricky process due to lack of logging. I added FLAG_heap_profiler_trace_objects that enables log for object movements. Drive by fix: with help of logging I found a bug in LeftTrim method for FixedArray. BUG=none R=svenpanne@chromium.org, yurys@chromium.org Committed: https://code.google.com/p/v8/source/detail?r=17258 Review URL: https://codereview.chromium.org/27694004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17263 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/builtins.cc | 9 +-- src/flag-definitions.h | 6 ++ src/heap-snapshot-generator.cc | 127 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 136 insertions(+), 6 deletions(-) diff --git a/src/builtins.cc b/src/builtins.cc index 03fac2d..4b8865a 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -273,14 +273,15 @@ static FixedArrayBase* LeftTrimFixedArray(Heap* heap, MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); } + FixedArrayBase* new_elms = FixedArrayBase::cast(HeapObject::FromAddress( + elms->address() + size_delta)); HeapProfiler* profiler = heap->isolate()->heap_profiler(); if (profiler->is_profiling()) { profiler->ObjectMoveEvent(elms->address(), - elms->address() + size_delta, - elms->Size()); + new_elms->address(), + new_elms->Size()); } - return FixedArrayBase::cast(HeapObject::FromAddress( - elms->address() + to_trim * entry_size)); + return new_elms; } diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 379ae69..e7180a0 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -541,6 +541,12 @@ DEFINE_int(sweeper_threads, 0, DEFINE_bool(verify_heap, false, "verify heap pointers before and after GC") #endif + +// heap-snapshot-generator.cc +DEFINE_bool(heap_profiler_trace_objects, false, + "Dump heap object allocations/movements/size_updates") + + // v8.cc DEFINE_bool(use_idle_notification, true, "Use idle notification to reduce memory footprint.") diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc index 444bebf..2debeb0 100644 --- a/src/heap-snapshot-generator.cc +++ b/src/heap-snapshot-generator.cc @@ -431,6 +431,13 @@ void HeapObjectsMap::MoveObject(Address from, Address to, int object_size) { // Size of an object can change during its life, so to keep information // about the object in entries_ consistent, we have to adjust size when the // object is migrated. + if (FLAG_heap_profiler_trace_objects) { + PrintF("Move object from %p to %p old size %6d new size %6d\n", + from, + to, + entries_.at(from_entry_info_index).size, + object_size); + } entries_.at(from_entry_info_index).size = object_size; to_entry->value = from_value; } @@ -438,6 +445,12 @@ void HeapObjectsMap::MoveObject(Address from, Address to, int object_size) { void HeapObjectsMap::NewObject(Address addr, int size) { + if (FLAG_heap_profiler_trace_objects) { + PrintF("New object : %p %6d. Next address is %p\n", + addr, + size, + addr + size); + } ASSERT(addr != NULL); FindOrAddEntry(addr, size, false); } @@ -470,6 +483,12 @@ SnapshotObjectId HeapObjectsMap::FindOrAddEntry(Address addr, static_cast(reinterpret_cast(entry->value)); EntryInfo& entry_info = entries_.at(entry_index); entry_info.accessed = accessed; + if (FLAG_heap_profiler_trace_objects) { + PrintF("Update object size : %p with old size %d and new size %d\n", + addr, + entry_info.size, + size); + } entry_info.size = size; return entry_info.id; } @@ -488,6 +507,10 @@ void HeapObjectsMap::StopHeapObjectsTracking() { void HeapObjectsMap::UpdateHeapObjectsMap() { + if (FLAG_heap_profiler_trace_objects) { + PrintF("Begin HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n", + entries_map_.occupancy()); + } heap_->CollectAllGarbage(Heap::kMakeHeapIterableMask, "HeapSnapshotsCollection::UpdateHeapObjectsMap"); HeapIterator iterator(heap_); @@ -495,12 +518,70 @@ void HeapObjectsMap::UpdateHeapObjectsMap() { obj != NULL; obj = iterator.next()) { FindOrAddEntry(obj->address(), obj->Size()); + if (FLAG_heap_profiler_trace_objects) { + PrintF("Update object : %p %6d. Next address is %p\n", + obj->address(), + obj->Size(), + obj->address() + obj->Size()); + } } RemoveDeadEntries(); + if (FLAG_heap_profiler_trace_objects) { + PrintF("End HeapObjectsMap::UpdateHeapObjectsMap. map has %d entries.\n", + entries_map_.occupancy()); + } +} + + +namespace { + + +struct HeapObjectInfo { + HeapObjectInfo(HeapObject* obj, size_t expected_size) + : obj(obj), + expected_size(expected_size) { + } + + HeapObject* obj; + size_t expected_size; + + bool IsValid() const { return expected_size == obj->Size(); } + + void Print() const { + if (expected_size == 0) { + PrintF("Untracked object : %p %6d. Next address is %p\n", + obj->address(), + obj->Size(), + obj->address() + obj->Size()); + } else if (obj->Size() != expected_size) { + PrintF("Wrong size %6d: %p %6d. Next address is %p\n", + expected_size, + obj->address(), + obj->Size(), + obj->address() + obj->Size()); + } else { + PrintF("Good object : %p %6d. Next address is %p\n", + obj->address(), + expected_size, + obj->address() + obj->Size()); + } + } +}; + + +static int comparator(const HeapObjectInfo* a, const HeapObjectInfo* b) { + if (a->obj < b->obj) return -1; + if (a->obj > b->obj) return 1; + return 0; } +} // namespace + + int HeapObjectsMap::FindUntrackedObjects() { + List heap_objects(1000); + HeapIterator iterator(heap_); int untracked = 0; for (HeapObject* obj = iterator.next(); @@ -509,13 +590,55 @@ int HeapObjectsMap::FindUntrackedObjects() { HashMap::Entry* entry = entries_map_.Lookup( obj->address(), ComputePointerHash(obj->address()), false); if (entry == NULL) { - untracked++; + ++untracked; + if (FLAG_heap_profiler_trace_objects) { + heap_objects.Add(HeapObjectInfo(obj, 0)); + } } else { int entry_index = static_cast( reinterpret_cast(entry->value)); EntryInfo& entry_info = entries_.at(entry_index); - CHECK_EQ(obj->Size(), static_cast(entry_info.size)); + if (FLAG_heap_profiler_trace_objects) { + heap_objects.Add(HeapObjectInfo(obj, + static_cast(entry_info.size))); + if (obj->Size() != static_cast(entry_info.size)) + ++untracked; + } else { + CHECK_EQ(obj->Size(), static_cast(entry_info.size)); + } + } + } + if (FLAG_heap_profiler_trace_objects) { + PrintF("\nBegin HeapObjectsMap::FindUntrackedObjects. %d entries in map.\n", + entries_map_.occupancy()); + heap_objects.Sort(comparator); + int last_printed_object = -1; + bool print_next_object = false; + for (int i = 0; i < heap_objects.length(); ++i) { + const HeapObjectInfo& object_info = heap_objects[i]; + if (!object_info.IsValid()) { + ++untracked; + if (last_printed_object != i - 1) { + if (i > 0) { + PrintF("%d objects were skipped\n", i - 1 - last_printed_object); + heap_objects[i - 1].Print(); + } + } + object_info.Print(); + last_printed_object = i; + print_next_object = true; + } else if (print_next_object) { + object_info.Print(); + print_next_object = false; + last_printed_object = i; + } + } + if (last_printed_object < heap_objects.length() - 1) { + PrintF("Last %d objects were skipped\n", + heap_objects.length() - 1 - last_printed_object); } + PrintF("End HeapObjectsMap::FindUntrackedObjects. %d entries in map.\n\n", + entries_map_.occupancy()); } return untracked; } -- 2.7.4