Class view: list all/sample instances on request.

The returned list can be filtered, etc., using its eval box.

Change VM code to only get reachable instances, using ObjectGraph.

BUG=dart:
R=johnmccutchan@google.com

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

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@37661 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
koda@google.com
2014-06-24 16:14:37 +00:00
parent a95448448f
commit bdab04234a
9 changed files with 1120 additions and 894 deletions
@@ -3850,11 +3850,30 @@ hr {
</template>
<template if="{{ !cls.hasNoAllocations }}">
current instances ({{ cls.newSpace.current.instances + cls.oldSpace.current.instances }})
instances
<div class="memberItem">
<div class="memberName">shallow size</div>
<div class="memberName">currently allocated</div>
<div class="memberValue">
{{ cls.newSpace.current.bytes + cls.oldSpace.current.bytes | formatSize }}
count {{ cls.newSpace.current.instances + cls.oldSpace.current.instances }}
(shallow size {{ cls.newSpace.current.bytes + cls.oldSpace.current.bytes | formatSize }})
</div>
</div>
<div class="memberItem">
<div class="memberName">strongly reachable</div>
<div class="memberValue">
<template if="{{ instances == null }}">
<eval-link callback="{{ reachable }}" label="[find]" expr="100">
</eval-link>
</template>
<template if="{{ instances != null }}">
sample
<instance-ref ref="{{ instances['sample'] }}"></instance-ref>
<template if="{{ instances['totalCount'] > instances['sampleCount'] }}">
<eval-link callback="{{ reachable }}" label="[more]" expr="{{ instances['sampleCount'] * 2 }}">
</eval-link>
</template>
of total {{ instances['totalCount'] }}
</template>
</div>
</div>
<div class="memberItem">
File diff suppressed because one or more lines are too long
@@ -3850,11 +3850,30 @@ hr {
</template>
<template if="{{ !cls.hasNoAllocations }}">
current instances ({{ cls.newSpace.current.instances + cls.oldSpace.current.instances }})
instances
<div class="memberItem">
<div class="memberName">shallow size</div>
<div class="memberName">currently allocated</div>
<div class="memberValue">
{{ cls.newSpace.current.bytes + cls.oldSpace.current.bytes | formatSize }}
count {{ cls.newSpace.current.instances + cls.oldSpace.current.instances }}
(shallow size {{ cls.newSpace.current.bytes + cls.oldSpace.current.bytes | formatSize }})
</div>
</div>
<div class="memberItem">
<div class="memberName">strongly reachable</div>
<div class="memberValue">
<template if="{{ instances == null }}">
<eval-link callback="{{ reachable }}" label="[find]" expr="100">
</eval-link>
</template>
<template if="{{ instances != null }}">
sample
<instance-ref ref="{{ instances['sample'] }}"></instance-ref>
<template if="{{ instances['totalCount'] > instances['sampleCount'] }}">
<eval-link callback="{{ reachable }}" label="[more]" expr="{{ instances['sampleCount'] * 2 }}">
</eval-link>
</template>
of total {{ instances['totalCount'] }}
</template>
</div>
</div>
<div class="memberItem">
File diff suppressed because one or more lines are too long
@@ -134,11 +134,34 @@
</template>
<template if="{{ !cls.hasNoAllocations }}">
current instances ({{ cls.newSpace.current.instances + cls.oldSpace.current.instances }})
instances
<div class="memberItem">
<div class="memberName">shallow size</div>
<div class="memberName">currently allocated</div>
<div class="memberValue">
{{ cls.newSpace.current.bytes + cls.oldSpace.current.bytes | formatSize }}
count {{ cls.newSpace.current.instances + cls.oldSpace.current.instances }}
(shallow size {{ cls.newSpace.current.bytes + cls.oldSpace.current.bytes | formatSize }})
</div>
</div>
<div class="memberItem">
<div class="memberName">strongly reachable</div>
<div class="memberValue">
<template if="{{ instances == null }}">
<eval-link callback="{{ reachable }}"
label="[find]"
expr="100">
</eval-link>
</template>
<template if="{{ instances != null }}">
sample
<instance-ref ref="{{ instances['sample'] }}"></instance-ref>
<template if="{{ instances['totalCount'] > instances['sampleCount'] }}">
<eval-link callback="{{ reachable }}"
label="[more]"
expr="{{ instances['sampleCount'] * 2 }}">
</eval-link>
</template>
of total {{ instances['totalCount'] }}
</template>
</div>
</div>
<div class="memberItem">
@@ -12,6 +12,7 @@ import 'package:polymer/polymer.dart';
@CustomTag('class-view')
class ClassViewElement extends ObservatoryElement {
@published Class cls;
@observable ServiceMap instances;
@observable int retainedBytes;
ClassViewElement.created() : super.created();
@@ -19,6 +20,13 @@ class ClassViewElement extends ObservatoryElement {
return cls.get("eval?expr=${Uri.encodeComponent(text)}");
}
Future<ServiceObject> reachable(var limit) {
return cls.get("instances?limit=$limit")
.then((ServiceMap obj) {
instances = obj;
});
}
// TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link".
Future<ServiceObject> retainedSize(var dummy) {
return cls.get("retained")
@@ -28,6 +36,8 @@ class ClassViewElement extends ObservatoryElement {
}
void refresh(var done) {
instances = null;
retainedBytes = null;
cls.reload().whenComplete(done);
}
}
@@ -134,11 +134,34 @@
</template>
<template if="{{ !cls.hasNoAllocations }}">
current instances ({{ cls.newSpace.current.instances + cls.oldSpace.current.instances }})
instances
<div class="memberItem">
<div class="memberName">shallow size</div>
<div class="memberName">currently allocated</div>
<div class="memberValue">
{{ cls.newSpace.current.bytes + cls.oldSpace.current.bytes | formatSize }}
count {{ cls.newSpace.current.instances + cls.oldSpace.current.instances }}
(shallow size {{ cls.newSpace.current.bytes + cls.oldSpace.current.bytes | formatSize }})
</div>
</div>
<div class="memberItem">
<div class="memberName">strongly reachable</div>
<div class="memberValue">
<template if="{{ instances == null }}">
<eval-link callback="{{ reachable }}"
label="[find]"
expr="100">
</eval-link>
</template>
<template if="{{ instances != null }}">
sample
<instance-ref ref="{{ instances['sample'] }}"></instance-ref>
<template if="{{ instances['totalCount'] > instances['sampleCount'] }}">
<eval-link callback="{{ reachable }}"
label="[more]"
expr="{{ instances['sampleCount'] * 2 }}">
</eval-link>
</template>
of total {{ instances['totalCount'] }}
</template>
</div>
</div>
<div class="memberItem">
+19 -10
View File
@@ -1138,17 +1138,19 @@ static bool HandleClassesRetained(Isolate* isolate, const Class& cls,
}
class GetInstancesVisitor : public ObjectVisitor {
class GetInstancesVisitor : public ObjectGraph::Visitor {
public:
GetInstancesVisitor(Isolate* isolate, const Class& cls, const Array& storage)
: ObjectVisitor(isolate), cls_(cls), storage_(storage), count_(0) {}
GetInstancesVisitor(const Class& cls, const Array& storage)
: cls_(cls), storage_(storage), count_(0) {}
virtual void VisitObject(RawObject* raw_obj) {
virtual Direction VisitObject(ObjectGraph::StackIterator* it) {
RawObject* raw_obj = it->Get();
if (raw_obj->IsFreeListElement()) {
return;
return kProceed;
}
REUSABLE_OBJECT_HANDLESCOPE(isolate());
Object& obj = isolate()->ObjectHandle();
Isolate* isolate = Isolate::Current();
REUSABLE_OBJECT_HANDLESCOPE(isolate);
Object& obj = isolate->ObjectHandle();
obj = raw_obj;
if (obj.GetClassId() == cls_.id()) {
if (!storage_.IsNull() && count_ < storage_.Length()) {
@@ -1156,6 +1158,7 @@ class GetInstancesVisitor : public ObjectVisitor {
}
++count_;
}
return kProceed;
}
intptr_t count() const { return count_; }
@@ -1180,8 +1183,9 @@ static bool HandleClassesInstances(Isolate* isolate, const Class& cls,
return true;
}
Array& storage = Array::Handle(Array::New(limit));
GetInstancesVisitor visitor(isolate, cls, storage);
isolate->heap()->IterateObjects(&visitor);
GetInstancesVisitor visitor(cls, storage);
ObjectGraph graph(isolate);
graph.IterateObjects(&visitor);
intptr_t count = visitor.count();
if (count < limit) {
// Truncate the list using utility method for GrowableObjectArray.
@@ -1190,7 +1194,12 @@ static bool HandleClassesInstances(Isolate* isolate, const Class& cls,
wrapper.SetLength(count);
storage = Array::MakeArray(wrapper);
}
storage.PrintJSON(js, true);
JSONObject jsobj(js);
jsobj.AddProperty("type", "InstanceSet");
jsobj.AddProperty("id", "instance_set");
jsobj.AddProperty("totalCount", count);
jsobj.AddProperty("sampleCount", storage.Length());
jsobj.AddProperty("sample", storage);
return true;
}
+5 -2
View File
@@ -838,7 +838,9 @@ TEST_CASE(Service_Classes) {
"['limit'], ['3']]", class_b.id());
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
ExpectSubstringF(handler.msg(), "\"type\":\"@Array\"");
ExpectSubstringF(handler.msg(), "\"type\":\"InstanceSet\"");
ExpectSubstringF(handler.msg(), "\"totalCount\":2");
ExpectSubstringF(handler.msg(), "\"sampleCount\":2");
// TODO(koda): Actually parse the response.
static const intptr_t kInstanceListId = 0;
ExpectSubstringF(handler.msg(), "\"id\":\"objects\\/%" Pd "\",\"length\":2",
@@ -854,7 +856,8 @@ TEST_CASE(Service_Classes) {
"['limit'], ['1']]", class_b.id());
Service::HandleIsolateMessage(isolate, service_msg);
handler.HandleNextMessage();
ExpectSubstringF(handler.msg(), "\"length\":1");
ExpectSubstringF(handler.msg(), "\"totalCount\":2");
ExpectSubstringF(handler.msg(), "\"sampleCount\":1");
}