Commit 74546c03 authored by yurys@chromium.org's avatar yurys@chromium.org

AllocationTracker now maintains a map from address range to stack trace that...

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
R=alph@chromium.org, mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/177983003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19728 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 40325916
......@@ -139,6 +139,78 @@ AllocationTracker::FunctionInfo::FunctionInfo()
}
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) {
return key1 == key2;
}
......@@ -208,6 +280,8 @@ void AllocationTracker::AllocationEvent(Address addr, int size) {
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());
}
......
......@@ -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 AllocationTraceTree {
};
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 @@ class AllocationTracker {
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 @@ class AllocationTracker {
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);
};
......
......@@ -168,7 +168,10 @@ SnapshotObjectId HeapProfiler::GetSnapshotObjectId(Handle<Object> obj) {
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);
}
}
......
......@@ -73,14 +73,16 @@ HeapEntry::HeapEntry(HeapSnapshot* snapshot,
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 <size_t ptr_size> struct SnapshotSizeConstants;
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* HeapSnapshot::AddRootEntry() {
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
"",
HeapObjectsMap::kInternalRootObjectId,
0,
0);
root_index_ = entry->index();
ASSERT(root_index_ == 0);
......@@ -255,6 +258,7 @@ HeapEntry* HeapSnapshot::AddGcRootsEntry() {
HeapEntry* entry = AddEntry(HeapEntry::kSynthetic,
"(GC roots)",
HeapObjectsMap::kGcRootsObjectId,
0,
0);
gc_roots_index_ = entry->index();
return entry;
......@@ -268,6 +272,7 @@ HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) {
HeapEntry::kSynthetic,
VisitorSynchronization::kTagNames[tag],
HeapObjectsMap::GetNthGcSubrootId(tag),
0,
0);
gc_subroot_indexes_[tag] = entry->index();
return entry;
......@@ -277,8 +282,9 @@ HeapEntry* HeapSnapshot::AddGcSubrootEntry(int tag) {
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 @@ HeapObjectsMap::HeapObjectsMap(Heap* heap)
}
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 @@ void HeapObjectsMap::MoveObject(Address from, Address to, int object_size) {
entries_.at(from_entry_info_index).size = object_size;
to_entry->value = from_value;
}
return from_value != NULL;
}
......@@ -910,7 +917,13 @@ HeapEntry* V8HeapExplorer::AddEntry(Address address,
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 @@ HeapEntry* BasicHeapEntriesAllocator::AllocateEntry(HeapThing ptr) {
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 @@ class OutputStreamWriter {
// 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::SerializeEdges() {
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 @@ void HeapSnapshotJSONSerializer::SerializeNode(HeapEntry* entry) {
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 @@ void HeapSnapshotJSONSerializer::SerializeSnapshot() {
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") ","
......
......@@ -114,7 +114,8 @@ class HeapEntry BASE_EMBEDDED {
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 @@ class HeapEntry BASE_EMBEDDED {
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 @@ class HeapEntry BASE_EMBEDDED {
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 @@ class HeapSnapshot {
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 @@ class HeapObjectsMap {
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;
......
......@@ -2506,3 +2506,63 @@ TEST(BoxObject) {
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)));
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment