Revision: 19728
Author: [email protected]
Date: Fri Mar 7 16:13:22 2014 UTC
Log: AllocationTracker now maintains a map from address range to stack
trace that allocated the range. When snapshot is generated the map is used
to find construction stack trace for an object using its address.
BUG=chromium:277984
LOG=Y
[email protected], [email protected]
Review URL: https://codereview.chromium.org/177983003
http://code.google.com/p/v8/source/detail?r=19728
Modified:
/branches/bleeding_edge/src/allocation-tracker.cc
/branches/bleeding_edge/src/allocation-tracker.h
/branches/bleeding_edge/src/heap-profiler.cc
/branches/bleeding_edge/src/heap-snapshot-generator.cc
/branches/bleeding_edge/src/heap-snapshot-generator.h
/branches/bleeding_edge/test/cctest/test-heap-profiler.cc
=======================================
--- /branches/bleeding_edge/src/allocation-tracker.cc Fri Mar 7 11:32:01
2014 UTC
+++ /branches/bleeding_edge/src/allocation-tracker.cc Fri Mar 7 16:13:22
2014 UTC
@@ -137,6 +137,78 @@
line(-1),
column(-1) {
}
+
+
+void AddressToTraceMap::AddRange(Address start, int size,
+ unsigned trace_node_id) {
+ Address end = start + size;
+ RemoveRange(start, end);
+
+ RangeStack new_range(start, trace_node_id);
+ ranges_.insert(RangeMap::value_type(end, new_range));
+}
+
+
+unsigned AddressToTraceMap::GetTraceNodeId(Address addr) {
+ RangeMap::const_iterator it = ranges_.upper_bound(addr);
+ if (it == ranges_.end()) return 0;
+ if (it->second.start <= addr) {
+ return it->second.trace_node_id;
+ }
+ return 0;
+}
+
+
+void AddressToTraceMap::MoveObject(Address from, Address to, int size) {
+ unsigned trace_node_id = GetTraceNodeId(from);
+ if (trace_node_id == 0) return;
+ RemoveRange(from, from + size);
+ AddRange(to, size, trace_node_id);
+}
+
+
+void AddressToTraceMap::Clear() {
+ ranges_.clear();
+}
+
+
+void AddressToTraceMap::Print() {
+ PrintF("[AddressToTraceMap (%lu): \n", ranges_.size());
+ for (RangeMap::iterator it = ranges_.begin(); it != ranges_.end(); ++it)
{
+ PrintF("[%p - %p] => %u\n", it->second.start, it->first,
+ it->second.trace_node_id);
+ }
+ PrintF("]\n");
+}
+
+
+void AddressToTraceMap::RemoveRange(Address start, Address end) {
+ RangeMap::iterator it = ranges_.upper_bound(start);
+ if (it == ranges_.end()) return;
+
+ RangeStack prev_range(0, 0);
+
+ RangeMap::iterator to_remove_begin = it;
+ if (it->second.start < start) {
+ prev_range = it->second;
+ }
+ do {
+ if (it->first > end) {
+ if (it->second.start < end) {
+ it->second.start = end;
+ }
+ break;
+ }
+ ++it;
+ }
+ while (it != ranges_.end());
+
+ ranges_.erase(to_remove_begin, it);
+
+ if (prev_range.start != 0) {
+ ranges_.insert(RangeMap::value_type(start, prev_range));
+ }
+}
static bool AddressesMatch(void* key1, void* key2) {
@@ -208,6 +280,8 @@
AllocationTraceNode* top_node = trace_tree_.AddPathFromEnd(
Vector<unsigned>(allocation_trace_buffer_, length));
top_node->AddAllocation(size);
+
+ address_to_trace_.AddRange(addr, size, top_node->id());
}
=======================================
--- /branches/bleeding_edge/src/allocation-tracker.h Fri Mar 7 11:32:01
2014 UTC
+++ /branches/bleeding_edge/src/allocation-tracker.h Fri Mar 7 16:13:22
2014 UTC
@@ -28,6 +28,8 @@
#ifndef V8_ALLOCATION_TRACKER_H_
#define V8_ALLOCATION_TRACKER_H_
+#include <map>
+
namespace v8 {
namespace internal {
@@ -81,6 +83,30 @@
};
+class AddressToTraceMap {
+ public:
+ void AddRange(Address addr, int size, unsigned node_id);
+ unsigned GetTraceNodeId(Address addr);
+ void MoveObject(Address from, Address to, int size);
+ void Clear();
+ size_t size() { return ranges_.size(); }
+ void Print();
+
+ private:
+ struct RangeStack {
+ RangeStack(Address start, unsigned node_id)
+ : start(start), trace_node_id(node_id) {}
+ Address start;
+ unsigned trace_node_id;
+ };
+ // [start, end) -> trace
+ typedef std::map<Address, RangeStack> RangeMap;
+
+ void RemoveRange(Address start, Address end);
+
+ RangeMap ranges_;
+};
+
class AllocationTracker {
public:
struct FunctionInfo {
@@ -103,6 +129,7 @@
const List<FunctionInfo*>& function_info_list() const {
return function_info_list_;
}
+ AddressToTraceMap* address_to_trace() { return &address_to_trace_; }
private:
unsigned AddFunctionInfo(SharedFunctionInfo* info, SnapshotObjectId id);
@@ -134,6 +161,7 @@
HashMap id_to_function_info_index_;
List<UnresolvedLocation*> unresolved_locations_;
unsigned info_index_for_other_state_;
+ AddressToTraceMap address_to_trace_;
DISALLOW_COPY_AND_ASSIGN(AllocationTracker);
};
=======================================
--- /branches/bleeding_edge/src/heap-profiler.cc Wed Dec 18 08:17:03 2013
UTC
+++ /branches/bleeding_edge/src/heap-profiler.cc Fri Mar 7 16:13:22 2014
UTC
@@ -168,7 +168,10 @@
void HeapProfiler::ObjectMoveEvent(Address from, Address to, int size) {
- ids_->MoveObject(from, to, size);
+ bool known_object = ids_->MoveObject(from, to, size);
+ if (!known_object && !allocation_tracker_.is_empty()) {
+ allocation_tracker_->address_to_trace()->MoveObject(from, to, size);
+ }
}
=======================================
--- /branches/bleeding_edge/src/heap-snapshot-generator.cc Fri Mar 7
11:32:01 2014 UTC
+++ /branches/bleeding_edge/src/heap-snapshot-generator.cc Fri Mar 7
16:13:22 2014 UTC
@@ -73,14 +73,16 @@
Type type,
const char* name,
SnapshotObjectId id,
- size_t self_size)
+ size_t self_size,
+ unsigned trace_node_id)
: type_(type),
children_count_(0),
children_index_(-1),
self_size_(self_size),
- id_(id),
snapshot_(snapshot),
- name_(name) { }
+ name_(name),
+ id_(id),
+ trace_node_id_(trace_node_id) { }
void HeapEntry::SetNamedReference(HeapGraphEdge::Type type,
@@ -189,7 +191,7 @@
template <> struct SnapshotSizeConstants<4> {
static const int kExpectedHeapGraphEdgeSize = 12;
- static const int kExpectedHeapEntrySize = 24;
+ static const int kExpectedHeapEntrySize = 28;
};
template <> struct SnapshotSizeConstants<8> {
@@ -243,6 +245,7 @@
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
"",
HeapObjectsMap::kInternalRootObjectId,
+ 0,
0);
root_index_ = entry->index();
ASSERT(root_index_ == 0);
@@ -255,6 +258,7 @@
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
"(GC roots)",
HeapObjectsMap::kGcRootsObjectId,
+ 0,
0);
gc_roots_index_ = entry->index();
return entry;
@@ -268,6 +272,7 @@
HeapEntry::kSynthetic,
VisitorSynchronization::kTagNames[tag],
HeapObjectsMap::GetNthGcSubrootId(tag),
+ 0,
0);
gc_subroot_indexes_[tag] = entry->index();
return entry;
@@ -277,8 +282,9 @@
HeapEntry* HeapSnapshot::AddEntry(HeapEntry::Type type,
const char* name,
SnapshotObjectId id,
- size_t size) {
- HeapEntry entry(this, type, name, id, size);
+ size_t size,
+ unsigned trace_node_id) {
+ HeapEntry entry(this, type, name, id, size, trace_node_id);
entries_.Add(entry);
return &entries_.last();
}
@@ -390,10 +396,10 @@
}
-void HeapObjectsMap::MoveObject(Address from, Address to, int object_size)
{
+bool HeapObjectsMap::MoveObject(Address from, Address to, int object_size)
{
ASSERT(to != NULL);
ASSERT(from != NULL);
- if (from == to) return;
+ if (from == to) return false;
void* from_value = entries_map_.Remove(from, ComputePointerHash(from));
if (from_value == NULL) {
// It may occur that some untracked object moves to an address X and
there
@@ -434,6 +440,7 @@
entries_.at(from_entry_info_index).size = object_size;
to_entry->value = from_value;
}
+ return from_value != NULL;
}
@@ -910,7 +917,13 @@
size_t size) {
SnapshotObjectId object_id = heap_object_map_->FindOrAddEntry(
address, static_cast<unsigned int>(size));
- return snapshot_->AddEntry(type, name, object_id, size);
+ unsigned trace_node_id = 0;
+ if (AllocationTracker* allocation_tracker =
+ snapshot_->profiler()->allocation_tracker()) {
+ trace_node_id =
+ allocation_tracker->address_to_trace()->GetTraceNodeId(address);
+ }
+ return snapshot_->AddEntry(type, name, object_id, size, trace_node_id);
}
@@ -2143,7 +2156,8 @@
entries_type_,
name,
heap_object_map_->GenerateId(info),
- size != -1 ? static_cast<int>(size) : 0);
+ size != -1 ? static_cast<int>(size) : 0,
+ 0);
}
@@ -2642,8 +2656,8 @@
// type, name|index, to_node.
const int HeapSnapshotJSONSerializer::kEdgeFieldsCount = 3;
-// type, name, id, self_size, children_index.
-const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 5;
+// type, name, id, self_size, edge_count, trace_node_id.
+const int HeapSnapshotJSONSerializer::kNodeFieldsCount = 6;
void HeapSnapshotJSONSerializer::Serialize(v8::OutputStream* stream) {
if (AllocationTracker* allocation_tracker =
@@ -2783,9 +2797,9 @@
void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
// The buffer needs space for 4 unsigned ints, 1 size_t, 5 commas, \n
and \0
static const int kBufferSize =
- 4 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT
+ 5 * MaxDecimalDigitsIn<sizeof(unsigned)>::kUnsigned // NOLINT
+ MaxDecimalDigitsIn<sizeof(size_t)>::kUnsigned // NOLINT
- + 5 + 1 + 1;
+ + 6 + 1 + 1;
EmbeddedVector<char, kBufferSize> buffer;
int buffer_pos = 0;
if (entry_index(entry) != 0) {
@@ -2800,6 +2814,8 @@
buffer_pos = utoa(entry->self_size(), buffer, buffer_pos);
buffer[buffer_pos++] = ',';
buffer_pos = utoa(entry->children_count(), buffer, buffer_pos);
+ buffer[buffer_pos++] = ',';
+ buffer_pos = utoa(entry->trace_node_id(), buffer, buffer_pos);
buffer[buffer_pos++] = '\n';
buffer[buffer_pos++] = '\0';
writer_->AddString(buffer.start());
@@ -2833,7 +2849,8 @@
JSON_S("name") ","
JSON_S("id") ","
JSON_S("self_size") ","
- JSON_S("edge_count")) ","
+ JSON_S("edge_count") ","
+ JSON_S("trace_node_id")) ","
JSON_S("node_types") ":" JSON_A(
JSON_A(
JSON_S("hidden") ","
=======================================
--- /branches/bleeding_edge/src/heap-snapshot-generator.h Tue Feb 18
13:22:07 2014 UTC
+++ /branches/bleeding_edge/src/heap-snapshot-generator.h Fri Mar 7
16:13:22 2014 UTC
@@ -114,7 +114,8 @@
Type type,
const char* name,
SnapshotObjectId id,
- size_t self_size);
+ size_t self_size,
+ unsigned trace_node_id);
HeapSnapshot* snapshot() { return snapshot_; }
Type type() { return static_cast<Type>(type_); }
@@ -122,6 +123,7 @@
void set_name(const char* name) { name_ = name; }
inline SnapshotObjectId id() { return id_; }
size_t self_size() { return self_size_; }
+ unsigned trace_node_id() const { return trace_node_id_; }
INLINE(int index() const);
int children_count() const { return children_count_; }
INLINE(int set_children_index(int index));
@@ -147,9 +149,11 @@
int children_count_: 28;
int children_index_;
size_t self_size_;
- SnapshotObjectId id_;
HeapSnapshot* snapshot_;
const char* name_;
+ SnapshotObjectId id_;
+ // id of allocation stack trace top node
+ unsigned trace_node_id_;
};
@@ -186,7 +190,8 @@
HeapEntry* AddEntry(HeapEntry::Type type,
const char* name,
SnapshotObjectId id,
- size_t size);
+ size_t size,
+ unsigned trace_node_id);
HeapEntry* AddRootEntry();
HeapEntry* AddGcRootsEntry();
HeapEntry* AddGcSubrootEntry(int tag);
@@ -228,7 +233,7 @@
SnapshotObjectId FindOrAddEntry(Address addr,
unsigned int size,
bool accessed = true);
- void MoveObject(Address from, Address to, int size);
+ bool MoveObject(Address from, Address to, int size);
void UpdateObjectSize(Address addr, int size);
SnapshotObjectId last_assigned_id() const {
return next_id_ - kObjectIdStep;
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Fri Mar 7
11:32:01 2014 UTC
+++ /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Fri Mar 7
16:13:22 2014 UTC
@@ -2506,3 +2506,63 @@
GetProperty(box_node, v8::HeapGraphEdge::kInternal, "value");
CHECK_NE(NULL, box_value);
}
+
+
+static inline i::Address ToAddress(int n) {
+ return reinterpret_cast<i::Address>(n);
+}
+
+
+TEST(AddressToTraceMap) {
+ i::AddressToTraceMap map;
+
+ CHECK_EQ(0, map.GetTraceNodeId(ToAddress(150)));
+
+ // [0x100, 0x200) -> 1
+ map.AddRange(ToAddress(0x100), 0x100, 1U);
+ CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x50)));
+ CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x100)));
+ CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x150)));
+ CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x100 + 0x100)));
+ CHECK_EQ(1, map.size());
+
+ // [0x100, 0x200) -> 1, [0x200, 0x300) -> 2
+ map.AddRange(ToAddress(0x200), 0x100, 2U);
+ CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x2a0)));
+ CHECK_EQ(2, map.size());
+
+ // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2
+ map.AddRange(ToAddress(0x180), 0x100, 3U);
+ CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x17F)));
+ CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x280)));
+ CHECK_EQ(3, map.GetTraceNodeId(ToAddress(0x180)));
+ CHECK_EQ(3, map.size());
+
+ // [0x100, 0x180) -> 1, [0x180, 0x280) -> 3, [0x280, 0x300) -> 2,
+ // [0x400, 0x500) -> 4
+ map.AddRange(ToAddress(0x400), 0x100, 4U);
+ CHECK_EQ(1, map.GetTraceNodeId(ToAddress(0x17F)));
+ CHECK_EQ(2, map.GetTraceNodeId(ToAddress(0x280)));
+ CHECK_EQ(3, map.GetTraceNodeId(ToAddress(0x180)));
+ CHECK_EQ(4, map.GetTraceNodeId(ToAddress(0x450)));
+ CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x500)));
+ CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x350)));
+ CHECK_EQ(4, map.size());
+
+ // [0x100, 0x180) -> 1, [0x180, 0x200) -> 3, [0x200, 0x600) -> 5
+ map.AddRange(ToAddress(0x200), 0x400, 5U);
+ CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x200)));
+ CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x400)));
+ CHECK_EQ(3, map.size());
+
+ // [0x100, 0x180) -> 1, [0x180, 0x200) -> 7, [0x200, 0x600) ->5
+ map.AddRange(ToAddress(0x180), 0x80, 6U);
+ map.AddRange(ToAddress(0x180), 0x80, 7U);
+ CHECK_EQ(7, map.GetTraceNodeId(ToAddress(0x180)));
+ CHECK_EQ(5, map.GetTraceNodeId(ToAddress(0x200)));
+ CHECK_EQ(3, map.size());
+
+ map.Clear();
+ CHECK_EQ(0, map.size());
+ CHECK_EQ(0, map.GetTraceNodeId(ToAddress(0x400)));
+}
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.