Add values to JSC heap capture visualizaion
Reviewed By: bnham Differential Revision: D3757492 fbshipit-source-id: 2e311878ca773b7d1ec680a2dc6422633f98a3a7
This commit is contained in:
Родитель
a0f55c9bca
Коммит
c06c1e1786
|
@ -10,6 +10,110 @@
|
||||||
/*eslint no-console-disallow: "off"*/
|
/*eslint no-console-disallow: "off"*/
|
||||||
/*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/
|
/*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/
|
||||||
|
|
||||||
|
function RefVisitor(refs,id){
|
||||||
|
this.refs=refs;
|
||||||
|
this.id=id;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefVisitor.prototype={
|
||||||
|
moveToEdge:function moveToEdge(name){
|
||||||
|
var ref=this.refs[this.id];
|
||||||
|
if(ref&&ref.edges){
|
||||||
|
var edges=ref.edges;
|
||||||
|
for(var edgeId in edges){
|
||||||
|
if(edges[edgeId]===name){
|
||||||
|
this.id=edgeId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.id=undefined;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
moveToFirst:function moveToFirst(callback){
|
||||||
|
var ref=this.refs[this.id];
|
||||||
|
if(ref&&ref.edges){
|
||||||
|
var edges=ref.edges;
|
||||||
|
for(var edgeId in edges){
|
||||||
|
this.id=edgeId;
|
||||||
|
if(callback(edges[edgeId],this)){
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.id=undefined;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
forEachEdge:function forEachEdge(callback){
|
||||||
|
var ref=this.refs[this.id];
|
||||||
|
if(ref&&ref.edges){
|
||||||
|
var edges=ref.edges;
|
||||||
|
var visitor=new RefVisitor(this.refs,undefined);
|
||||||
|
for(var edgeId in edges){
|
||||||
|
visitor.id=edgeId;
|
||||||
|
callback(edges[edgeId],visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getType:function getType(){
|
||||||
|
var ref=this.refs[this.id];
|
||||||
|
if(ref){
|
||||||
|
return ref.type;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
getRef:function getRef(){
|
||||||
|
return this.refs[this.id];
|
||||||
|
},
|
||||||
|
clone:function clone(){
|
||||||
|
return new RefVisitor(this.refs,this.id);
|
||||||
|
},
|
||||||
|
isDefined:function isDefined(){
|
||||||
|
return!!this.id;
|
||||||
|
},
|
||||||
|
getValue:function getValue(){var _this=this;
|
||||||
|
var ref=this.refs[this.id];
|
||||||
|
if(ref){
|
||||||
|
if(ref.type==='string'){
|
||||||
|
if(ref.value){
|
||||||
|
return ref.value;
|
||||||
|
}else{var _ret=function(){
|
||||||
|
var rope=[];
|
||||||
|
_this.forEachEdge(function(name,visitor){
|
||||||
|
if(name&&name.startsWith('[')&&name.endsWith(']')){
|
||||||
|
var index=parseInt(name.substring(1,name.length-1),10);
|
||||||
|
rope[index]=visitor.getValue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return{v:rope.join('')};}();if(typeof _ret==="object")return _ret.v;
|
||||||
|
}
|
||||||
|
}else if(ref.type==='ScriptExecutable'||
|
||||||
|
ref.type==='EvalExecutable'||
|
||||||
|
ref.type==='ProgramExecutable'){
|
||||||
|
return ref.value.url+':'+ref.value.line+':'+ref.value.col;
|
||||||
|
}else if(ref.type==='FunctionExecutable'){
|
||||||
|
return ref.value.name+'@'+ref.value.url+':'+ref.value.line+':'+ref.value.col;
|
||||||
|
}else if(ref.type==='NativeExecutable'){
|
||||||
|
return ref.value.function+' '+ref.value.constructor+' '+ref.value.name;
|
||||||
|
}else if(ref.type==='Function'){
|
||||||
|
var executable=this.clone().moveToEdge('@Executable');
|
||||||
|
if(executable.id){
|
||||||
|
return executable.getRef().type+' '+executable.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return'#none';
|
||||||
|
}};
|
||||||
|
|
||||||
|
|
||||||
|
function forEachRef(refs,callback){
|
||||||
|
var visitor=new RefVisitor(refs,undefined);
|
||||||
|
for(var id in refs){
|
||||||
|
visitor.id=id;
|
||||||
|
callback(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getTypeName(ref){
|
function getTypeName(ref){
|
||||||
if(ref.type==='Function'&&!!ref.value){
|
if(ref.type==='Function'&&!!ref.value){
|
||||||
return'Function '+ref.value.name;
|
return'Function '+ref.value.name;
|
||||||
|
@ -212,13 +316,14 @@ var sizeField=2;
|
||||||
var traceField=3;
|
var traceField=3;
|
||||||
var pathField=4;
|
var pathField=4;
|
||||||
var reactField=5;
|
var reactField=5;
|
||||||
var numFields=6;
|
var valueField=6;
|
||||||
|
var numFields=7;
|
||||||
|
|
||||||
return{
|
return{
|
||||||
strings:strings,
|
strings:strings,
|
||||||
stacks:stacks,
|
stacks:stacks,
|
||||||
data:data,
|
data:data,
|
||||||
register:function registerCapture(captureId,capture){
|
register:function registerCapture(captureId,capture){var _this2=this;
|
||||||
// NB: capture.refs is potentially VERY large, so we try to avoid making
|
// NB: capture.refs is potentially VERY large, so we try to avoid making
|
||||||
// copies, even of iteration is a bit more annoying.
|
// copies, even of iteration is a bit more annoying.
|
||||||
var rowCount=0;
|
var rowCount=0;
|
||||||
|
@ -245,34 +350,41 @@ this.stacks,
|
||||||
reactComponentTreeMap);
|
reactComponentTreeMap);
|
||||||
|
|
||||||
var internedCaptureId=this.strings.intern(captureId);
|
var internedCaptureId=this.strings.intern(captureId);
|
||||||
for(var _id4 in capture.refs){
|
var noneStack=this.stacks.insert(this.stacks.root,'#none');
|
||||||
var ref=capture.refs[_id4];
|
forEachRef(capture.refs,function(visitor){
|
||||||
newData[dataOffset+idField]=parseInt(_id4,16);
|
var ref=visitor.getRef();
|
||||||
newData[dataOffset+typeField]=this.strings.intern(getTypeName(ref));
|
var id=visitor.id;
|
||||||
|
newData[dataOffset+idField]=parseInt(id,16);
|
||||||
|
newData[dataOffset+typeField]=_this2.strings.intern(ref.type);
|
||||||
newData[dataOffset+sizeField]=ref.size;
|
newData[dataOffset+sizeField]=ref.size;
|
||||||
newData[dataOffset+traceField]=internedCaptureId;
|
newData[dataOffset+traceField]=internedCaptureId;
|
||||||
var pathNode=rootPathMap[_id4];
|
var pathNode=rootPathMap[id];
|
||||||
if(pathNode===undefined){
|
if(pathNode===undefined){
|
||||||
throw'did not find path for ref!';
|
throw'did not find path for ref!';
|
||||||
}
|
}
|
||||||
newData[dataOffset+pathField]=pathNode.id;
|
newData[dataOffset+pathField]=pathNode.id;
|
||||||
var reactTree=reactComponentTreeMap[_id4];
|
var reactTree=reactComponentTreeMap[id];
|
||||||
if(reactTree===undefined){
|
if(reactTree===undefined){
|
||||||
newData[dataOffset+reactField]=
|
newData[dataOffset+reactField]=noneStack.id;
|
||||||
this.stacks.insert(this.stacks.root,'<not-under-tree>').id;
|
|
||||||
}else{
|
}else{
|
||||||
newData[dataOffset+reactField]=reactTree.id;
|
newData[dataOffset+reactField]=reactTree.id;
|
||||||
}
|
}
|
||||||
|
newData[dataOffset+valueField]=_this2.strings.intern(visitor.getValue());
|
||||||
dataOffset+=numFields;
|
dataOffset+=numFields;
|
||||||
}
|
});
|
||||||
for(var _id5 in capture.markedBlocks){
|
for(var _id4 in capture.markedBlocks){
|
||||||
var block=capture.markedBlocks[_id5];
|
var block=capture.markedBlocks[_id4];
|
||||||
newData[dataOffset+idField]=parseInt(_id5,16);
|
newData[dataOffset+idField]=parseInt(_id4,16);
|
||||||
newData[dataOffset+typeField]=this.strings.intern('Marked Block Overhead');
|
newData[dataOffset+typeField]=this.strings.intern('Marked Block Overhead');
|
||||||
newData[dataOffset+sizeField]=block.capacity-block.size;
|
newData[dataOffset+sizeField]=block.capacity-block.size;
|
||||||
newData[dataOffset+traceField]=internedCaptureId;
|
newData[dataOffset+traceField]=internedCaptureId;
|
||||||
newData[dataOffset+pathField]=this.stacks.root;
|
newData[dataOffset+pathField]=noneStack.id;
|
||||||
newData[dataOffset+reactField]=this.stacks.root;
|
newData[dataOffset+reactField]=noneStack.id;
|
||||||
|
newData[dataOffset+valueField]=this.strings.intern(
|
||||||
|
'capacity: '+block.capacity+
|
||||||
|
', size: '+block.size+
|
||||||
|
', granularity: '+block.cellSize);
|
||||||
|
|
||||||
dataOffset+=numFields;
|
dataOffset+=numFields;
|
||||||
}
|
}
|
||||||
this.data=newData;
|
this.data=newData;
|
||||||
|
@ -297,12 +409,12 @@ return agData[rowA*numFields+idField]-agData[rowB*numFields+idField];
|
||||||
});
|
});
|
||||||
|
|
||||||
var typeExpander=ag.addFieldExpander('Type',
|
var typeExpander=ag.addFieldExpander('Type',
|
||||||
function getSize(row){return agStrings.get(agData[row*numFields+typeField]);},
|
function getType(row){return agStrings.get(agData[row*numFields+typeField]);},
|
||||||
function compareSize(rowA,rowB){
|
function compareType(rowA,rowB){
|
||||||
return agData[rowA*numFields+typeField]-agData[rowB*numFields+typeField];
|
return agData[rowA*numFields+typeField]-agData[rowB*numFields+typeField];
|
||||||
});
|
});
|
||||||
|
|
||||||
ag.addFieldExpander('Size',
|
var sizeExpander=ag.addFieldExpander('Size',
|
||||||
function getSize(row){return agData[row*numFields+sizeField].toString();},
|
function getSize(row){return agData[row*numFields+sizeField].toString();},
|
||||||
function compareSize(rowA,rowB){
|
function compareSize(rowA,rowB){
|
||||||
return agData[rowA*numFields+sizeField]-agData[rowB*numFields+sizeField];
|
return agData[rowA*numFields+sizeField]-agData[rowB*numFields+sizeField];
|
||||||
|
@ -320,6 +432,12 @@ function getStack(row){return agStacks.get(agData[row*numFields+pathField]);});
|
||||||
var reactExpander=ag.addCalleeStackExpander('React Tree',
|
var reactExpander=ag.addCalleeStackExpander('React Tree',
|
||||||
function getStack(row){return agStacks.get(agData[row*numFields+reactField]);});
|
function getStack(row){return agStacks.get(agData[row*numFields+reactField]);});
|
||||||
|
|
||||||
|
var valueExpander=ag.addFieldExpander('Value',
|
||||||
|
function getValue(row){return agStrings.get(agData[row*numFields+valueField]);},
|
||||||
|
function compareValue(rowA,rowB){
|
||||||
|
return agData[rowA*numFields+valueField]-agData[rowB*numFields+valueField];
|
||||||
|
});
|
||||||
|
|
||||||
var sizeAggregator=ag.addAggregator('Size',
|
var sizeAggregator=ag.addAggregator('Size',
|
||||||
function aggregateSize(indices){
|
function aggregateSize(indices){
|
||||||
var size=0;
|
var size=0;
|
||||||
|
@ -339,7 +457,15 @@ return indices.length;
|
||||||
function formatCount(value){return value.toString();},
|
function formatCount(value){return value.toString();},
|
||||||
function sortCount(a,b){return b-a;});
|
function sortCount(a,b){return b-a;});
|
||||||
|
|
||||||
ag.setActiveExpanders([pathExpander,reactExpander,typeExpander,idExpander,traceExpander]);
|
ag.setActiveExpanders([
|
||||||
|
pathExpander,
|
||||||
|
reactExpander,
|
||||||
|
typeExpander,
|
||||||
|
idExpander,
|
||||||
|
traceExpander,
|
||||||
|
valueExpander,
|
||||||
|
sizeExpander]);
|
||||||
|
|
||||||
ag.setActiveAggregators([sizeAggregator,countAggregator]);
|
ag.setActiveAggregators([sizeAggregator,countAggregator]);
|
||||||
return ag;
|
return ag;
|
||||||
}};
|
}};
|
||||||
|
|
|
@ -10,6 +10,110 @@
|
||||||
/*eslint no-console-disallow: "off"*/
|
/*eslint no-console-disallow: "off"*/
|
||||||
/*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/
|
/*global React ReactDOM Table stringInterner stackRegistry aggrow preLoadedCapture:true*/
|
||||||
|
|
||||||
|
function RefVisitor(refs, id) {
|
||||||
|
this.refs = refs;
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefVisitor.prototype = {
|
||||||
|
moveToEdge: function moveToEdge(name) {
|
||||||
|
const ref = this.refs[this.id];
|
||||||
|
if (ref && ref.edges) {
|
||||||
|
const edges = ref.edges;
|
||||||
|
for (const edgeId in edges) {
|
||||||
|
if (edges[edgeId] === name) {
|
||||||
|
this.id = edgeId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.id = undefined;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
moveToFirst: function moveToFirst(callback) {
|
||||||
|
const ref = this.refs[this.id];
|
||||||
|
if (ref && ref.edges) {
|
||||||
|
const edges = ref.edges;
|
||||||
|
for (const edgeId in edges) {
|
||||||
|
this.id = edgeId;
|
||||||
|
if (callback(edges[edgeId], this)) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.id = undefined;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
forEachEdge: function forEachEdge(callback) {
|
||||||
|
const ref = this.refs[this.id];
|
||||||
|
if (ref && ref.edges) {
|
||||||
|
const edges = ref.edges;
|
||||||
|
const visitor = new RefVisitor(this.refs, undefined);
|
||||||
|
for (const edgeId in edges) {
|
||||||
|
visitor.id = edgeId;
|
||||||
|
callback(edges[edgeId], visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getType: function getType() {
|
||||||
|
const ref = this.refs[this.id];
|
||||||
|
if (ref) {
|
||||||
|
return ref.type;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
},
|
||||||
|
getRef: function getRef() {
|
||||||
|
return this.refs[this.id];
|
||||||
|
},
|
||||||
|
clone: function clone() {
|
||||||
|
return new RefVisitor(this.refs, this.id);
|
||||||
|
},
|
||||||
|
isDefined: function isDefined() {
|
||||||
|
return !!this.id;
|
||||||
|
},
|
||||||
|
getValue: function getValue() {
|
||||||
|
const ref = this.refs[this.id];
|
||||||
|
if (ref) {
|
||||||
|
if (ref.type === 'string') {
|
||||||
|
if (ref.value) {
|
||||||
|
return ref.value;
|
||||||
|
} else {
|
||||||
|
const rope = [];
|
||||||
|
this.forEachEdge((name, visitor) => {
|
||||||
|
if (name && name.startsWith('[') && name.endsWith(']')) {
|
||||||
|
const index = parseInt(name.substring(1, name.length - 1), 10);
|
||||||
|
rope[index] = visitor.getValue();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return rope.join('');
|
||||||
|
}
|
||||||
|
} else if (ref.type === 'ScriptExecutable'
|
||||||
|
|| ref.type === 'EvalExecutable'
|
||||||
|
|| ref.type === 'ProgramExecutable') {
|
||||||
|
return ref.value.url + ':' + ref.value.line + ':' + ref.value.col;
|
||||||
|
} else if (ref.type === 'FunctionExecutable') {
|
||||||
|
return ref.value.name + '@' + ref.value.url + ':' + ref.value.line + ':' + ref.value.col;
|
||||||
|
} else if (ref.type === 'NativeExecutable') {
|
||||||
|
return ref.value.function + ' ' + ref.value.constructor + ' ' + ref.value.name;
|
||||||
|
} else if (ref.type === 'Function') {
|
||||||
|
const executable = this.clone().moveToEdge('@Executable');
|
||||||
|
if (executable.id) {
|
||||||
|
return executable.getRef().type + ' ' + executable.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '#none';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function forEachRef(refs, callback) {
|
||||||
|
const visitor = new RefVisitor(refs, undefined);
|
||||||
|
for (const id in refs) {
|
||||||
|
visitor.id = id;
|
||||||
|
callback(visitor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getTypeName(ref) {
|
function getTypeName(ref) {
|
||||||
if (ref.type === 'Function' && !!ref.value) {
|
if (ref.type === 'Function' && !!ref.value) {
|
||||||
return 'Function ' + ref.value.name;
|
return 'Function ' + ref.value.name;
|
||||||
|
@ -212,7 +316,8 @@ function captureRegistry() {
|
||||||
const traceField = 3;
|
const traceField = 3;
|
||||||
const pathField = 4;
|
const pathField = 4;
|
||||||
const reactField = 5;
|
const reactField = 5;
|
||||||
const numFields = 6;
|
const valueField = 6;
|
||||||
|
const numFields = 7;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
strings: strings,
|
strings: strings,
|
||||||
|
@ -245,10 +350,12 @@ function captureRegistry() {
|
||||||
reactComponentTreeMap
|
reactComponentTreeMap
|
||||||
);
|
);
|
||||||
const internedCaptureId = this.strings.intern(captureId);
|
const internedCaptureId = this.strings.intern(captureId);
|
||||||
for (const id in capture.refs) {
|
const noneStack = this.stacks.insert(this.stacks.root, '#none');
|
||||||
const ref = capture.refs[id];
|
forEachRef(capture.refs, (visitor) => {
|
||||||
|
const ref = visitor.getRef();
|
||||||
|
const id = visitor.id;
|
||||||
newData[dataOffset + idField] = parseInt(id, 16);
|
newData[dataOffset + idField] = parseInt(id, 16);
|
||||||
newData[dataOffset + typeField] = this.strings.intern(getTypeName(ref));
|
newData[dataOffset + typeField] = this.strings.intern(ref.type);
|
||||||
newData[dataOffset + sizeField] = ref.size;
|
newData[dataOffset + sizeField] = ref.size;
|
||||||
newData[dataOffset + traceField] = internedCaptureId;
|
newData[dataOffset + traceField] = internedCaptureId;
|
||||||
const pathNode = rootPathMap[id];
|
const pathNode = rootPathMap[id];
|
||||||
|
@ -258,21 +365,26 @@ function captureRegistry() {
|
||||||
newData[dataOffset + pathField] = pathNode.id;
|
newData[dataOffset + pathField] = pathNode.id;
|
||||||
const reactTree = reactComponentTreeMap[id];
|
const reactTree = reactComponentTreeMap[id];
|
||||||
if (reactTree === undefined) {
|
if (reactTree === undefined) {
|
||||||
newData[dataOffset + reactField] =
|
newData[dataOffset + reactField] = noneStack.id;
|
||||||
this.stacks.insert(this.stacks.root, '<not-under-tree>').id;
|
|
||||||
} else {
|
} else {
|
||||||
newData[dataOffset + reactField] = reactTree.id;
|
newData[dataOffset + reactField] = reactTree.id;
|
||||||
}
|
}
|
||||||
|
newData[dataOffset + valueField] = this.strings.intern(visitor.getValue());
|
||||||
dataOffset += numFields;
|
dataOffset += numFields;
|
||||||
}
|
});
|
||||||
for (const id in capture.markedBlocks) {
|
for (const id in capture.markedBlocks) {
|
||||||
const block = capture.markedBlocks[id];
|
const block = capture.markedBlocks[id];
|
||||||
newData[dataOffset + idField] = parseInt(id, 16);
|
newData[dataOffset + idField] = parseInt(id, 16);
|
||||||
newData[dataOffset + typeField] = this.strings.intern('Marked Block Overhead');
|
newData[dataOffset + typeField] = this.strings.intern('Marked Block Overhead');
|
||||||
newData[dataOffset + sizeField] = block.capacity - block.size;
|
newData[dataOffset + sizeField] = block.capacity - block.size;
|
||||||
newData[dataOffset + traceField] = internedCaptureId;
|
newData[dataOffset + traceField] = internedCaptureId;
|
||||||
newData[dataOffset + pathField] = this.stacks.root;
|
newData[dataOffset + pathField] = noneStack.id;
|
||||||
newData[dataOffset + reactField] = this.stacks.root;
|
newData[dataOffset + reactField] = noneStack.id;
|
||||||
|
newData[dataOffset + valueField] = this.strings.intern(
|
||||||
|
'capacity: ' + block.capacity +
|
||||||
|
', size: ' + block.size +
|
||||||
|
', granularity: ' + block.cellSize
|
||||||
|
);
|
||||||
dataOffset += numFields;
|
dataOffset += numFields;
|
||||||
}
|
}
|
||||||
this.data = newData;
|
this.data = newData;
|
||||||
|
@ -297,12 +409,12 @@ function captureRegistry() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const typeExpander = ag.addFieldExpander('Type',
|
const typeExpander = ag.addFieldExpander('Type',
|
||||||
function getSize(row) { return agStrings.get(agData[row * numFields + typeField]); },
|
function getType(row) { return agStrings.get(agData[row * numFields + typeField]); },
|
||||||
function compareSize(rowA, rowB) {
|
function compareType(rowA, rowB) {
|
||||||
return agData[rowA * numFields + typeField] - agData[rowB * numFields + typeField];
|
return agData[rowA * numFields + typeField] - agData[rowB * numFields + typeField];
|
||||||
});
|
});
|
||||||
|
|
||||||
ag.addFieldExpander('Size',
|
const sizeExpander = ag.addFieldExpander('Size',
|
||||||
function getSize(row) { return agData[row * numFields + sizeField].toString(); },
|
function getSize(row) { return agData[row * numFields + sizeField].toString(); },
|
||||||
function compareSize(rowA, rowB) {
|
function compareSize(rowA, rowB) {
|
||||||
return agData[rowA * numFields + sizeField] - agData[rowB * numFields + sizeField];
|
return agData[rowA * numFields + sizeField] - agData[rowB * numFields + sizeField];
|
||||||
|
@ -320,6 +432,12 @@ function captureRegistry() {
|
||||||
const reactExpander = ag.addCalleeStackExpander('React Tree',
|
const reactExpander = ag.addCalleeStackExpander('React Tree',
|
||||||
function getStack(row) { return agStacks.get(agData[row * numFields + reactField]); });
|
function getStack(row) { return agStacks.get(agData[row * numFields + reactField]); });
|
||||||
|
|
||||||
|
const valueExpander = ag.addFieldExpander('Value',
|
||||||
|
function getValue(row) { return agStrings.get(agData[row * numFields + valueField]); },
|
||||||
|
function compareValue(rowA, rowB) {
|
||||||
|
return agData[rowA * numFields + valueField] - agData[rowB * numFields + valueField];
|
||||||
|
});
|
||||||
|
|
||||||
const sizeAggregator = ag.addAggregator('Size',
|
const sizeAggregator = ag.addAggregator('Size',
|
||||||
function aggregateSize(indices) {
|
function aggregateSize(indices) {
|
||||||
let size = 0;
|
let size = 0;
|
||||||
|
@ -339,7 +457,15 @@ function captureRegistry() {
|
||||||
function formatCount(value) { return value.toString(); },
|
function formatCount(value) { return value.toString(); },
|
||||||
function sortCount(a, b) { return b - a; } );
|
function sortCount(a, b) { return b - a; } );
|
||||||
|
|
||||||
ag.setActiveExpanders([pathExpander, reactExpander, typeExpander, idExpander, traceExpander]);
|
ag.setActiveExpanders([
|
||||||
|
pathExpander,
|
||||||
|
reactExpander,
|
||||||
|
typeExpander,
|
||||||
|
idExpander,
|
||||||
|
traceExpander,
|
||||||
|
valueExpander,
|
||||||
|
sizeExpander
|
||||||
|
]);
|
||||||
ag.setActiveAggregators([sizeAggregator, countAggregator]);
|
ag.setActiveAggregators([sizeAggregator, countAggregator]);
|
||||||
return ag;
|
return ag;
|
||||||
},
|
},
|
||||||
|
|
Загрузка…
Ссылка в новой задаче