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:
@@ -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
+26
-3
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user