1 var initialize_HeapSnapshotTest = function() {
3 InspectorTest
.preloadPanel("profiles");
5 InspectorTest
.createHeapSnapshotMockFactories = function() {
7 InspectorTest
.createJSHeapSnapshotMockObject = function()
13 _nodeEdgeCountOffset
: 2,
19 _nodeTypes
: ["hidden", "object"],
20 _edgeTypes
: ["element", "property", "shortcut"],
21 _edgeShortcutType
: -1,
25 // Represents the following graph:
26 // (numbers in parentheses indicate node offset)
28 // -> A (3) --ac- C (9) -ce- E(15)
32 // -> B (6) -bd- D (12)
34 nodes
: new Uint32Array([
41 containmentEdges
: new Uint32Array([
42 2, 6, 3, // 0: shortcut 'a' to node 'A'
43 1, 7, 6, // 3: property 'b' to node 'B'
44 0, 1, 6, // 6: element '1' to node 'B'
45 1, 8, 9, // 9: property 'ac' to node 'C'
46 1, 9, 9, // 12: property 'bc' to node 'C'
47 1, 10, 12, // 15: property 'bd' to node 'D'
48 1, 11, 15]),// 18: property 'ce' to node 'E'
49 strings
: ["", "A", "B", "C", "D", "E", "a", "b", "ac", "bc", "bd", "ce"],
50 _firstEdgeIndexes
: new Uint32Array([0, 6, 12, 18, 21, 21, 21]),
51 createNode
: WebInspector
.JSHeapSnapshot
.prototype.createNode
,
52 createEdge
: WebInspector
.JSHeapSnapshot
.prototype.createEdge
,
53 createRetainingEdge
: WebInspector
.JSHeapSnapshot
.prototype.createRetainingEdge
57 InspectorTest
.createHeapSnapshotMockRaw = function()
59 // Effectively the same graph as in createJSHeapSnapshotMockObject,
60 // but having full set of fields.
62 // A triple in parentheses indicates node index, self size and
65 // --- A (7,2,2) --ac- C (21,4,10) -ce- E(35,6,6)
67 // "" (0,0,20) 1 --bc-----
69 // --- B (14,3,8) --bd- D (28,5,5)
74 node_fields
: ["type", "name", "id", "self_size", "retained_size", "dominator", "edge_count"],
75 node_types
: [["hidden", "object"], "", "", "", "", "", ""],
76 edge_fields
: ["type", "name_or_index", "to_node"],
77 edge_types
: [["element", "property", "shortcut"], "", ""]
82 0, 0, 1, 0, 20, 0, 2, // root (0)
83 1, 1, 2, 2, 2, 0, 2, // A (7)
84 1, 2, 3, 3, 8, 0, 2, // B (14)
85 1, 3, 4, 4, 10, 0, 1, // C (21)
86 1, 4, 5, 5, 5, 14, 0, // D (28)
87 1, 5, 6, 6, 6, 21, 0], // E (35)
90 1, 6, 7, // property 'a' to node 'A'
91 1, 7, 14, // property 'b' to node 'B'
94 0, 1, 14, // element 1 to node 'B'
95 1, 8, 21, // property 'ac' to node 'C'
98 1, 9, 21, // property 'bc' to node 'C'
99 1, 10, 28, // property 'bd' to node 'D'
102 1, 11, 35], // property 'ce' to node 'E'
103 strings
: ["", "A", "B", "C", "D", "E", "a", "b", "ac", "bc", "bd", "ce"]
107 InspectorTest
._postprocessHeapSnapshotMock = function(mock
)
109 mock
.nodes
= new Uint32Array(mock
.nodes
);
110 mock
.edges
= new Uint32Array(mock
.edges
);
114 InspectorTest
.createHeapSnapshotMock = function()
116 return InspectorTest
._postprocessHeapSnapshotMock(InspectorTest
.createHeapSnapshotMockRaw());
119 InspectorTest
.createHeapSnapshotMockWithDOM = function()
121 return InspectorTest
._postprocessHeapSnapshotMock({
124 node_fields
: ["type", "name", "id", "edge_count"],
125 node_types
: [["hidden", "object", "synthetic"], "", "", ""],
126 edge_fields
: ["type", "name_or_index", "to_node"],
127 edge_types
: [["element", "hidden", "internal"], "", ""]
133 // A tree with Window objects.
135 // |----->Window--->A
137 // |----->Window--->B--->C
139 // (root) hidden --->D--internal / "native"-->N
141 // |----->E H internal
145 /* (root) */ 2, 0, 1, 4,
146 /* Window */ 1, 11, 2, 2,
147 /* Window */ 1, 11, 3, 3,
156 /* N */ 1, 10, 12, 0,
160 /* from (root) */ 0, 1, 4, 0, 2, 8, 0, 3, 12, 0, 4, 16,
161 /* from Window */ 0, 1, 20, 0, 2, 24,
162 /* from Window */ 0, 1, 24, 0, 2, 28, 1, 3, 32,
163 /* from F */ 0, 1, 36,
164 /* from B */ 0, 1, 40,
165 /* from D */ 2, 12, 44, 2, 1, 48
167 strings
: ["", "A", "B", "C", "D", "E", "F", "G", "H", "M", "N", "Window", "native"]
171 InspectorTest
.HeapNode = function(name
, selfSize
, type
, id
)
173 this._type
= type
|| InspectorTest
.HeapNode
.Type
.object
;
175 this._selfSize
= selfSize
|| 0;
176 this._builder
= null;
178 this._edgesCount
= 0;
182 InspectorTest
.HeapNode
.Type
= {
188 "closure": "closure",
192 "synthetic": "synthetic"
195 InspectorTest
.HeapNode
.prototype = {
196 linkNode: function(node
, type
, nameOrIndex
)
199 throw new Error("parent node is not connected to a snapshot");
202 node
._setBuilder(this._builder
);
204 if (nameOrIndex
=== undefined)
205 nameOrIndex
= this._edgesCount
;
208 if (nameOrIndex
in this._edges
)
209 throw new Error("Can't add edge with the same nameOrIndex. nameOrIndex: " + nameOrIndex
+ " oldNodeName: " + this._edges
[nameOrIndex
]._name
+ " newNodeName: " + node
._name
);
210 this._edges
[nameOrIndex
] = new InspectorTest
.HeapEdge(node
, type
, nameOrIndex
);
213 _setBuilder: function(builder
)
216 throw new Error("node reusing is prohibited");
218 this._builder
= builder
;
219 this._ordinal
= this._builder
._registerNode(this);
222 _serialize: function(rawSnapshot
)
224 rawSnapshot
.nodes
.push(this._builder
.lookupNodeType(this._type
));
225 rawSnapshot
.nodes
.push(this._builder
.lookupOrAddString(this._name
));
226 // JS engine snapshot impementation generates monotonicaly increasing odd id for JS objects,
227 // and even ids based on a hash for native DOMObject groups.
228 rawSnapshot
.nodes
.push(this._id
|| this._ordinal
* 2 + 1);
229 rawSnapshot
.nodes
.push(this._selfSize
);
230 rawSnapshot
.nodes
.push(0); // retained_size
231 rawSnapshot
.nodes
.push(0); // dominator
232 rawSnapshot
.nodes
.push(Object
.keys(this._edges
).length
); // edge_count
234 for (var i
in this._edges
)
235 this._edges
[i
]._serialize(rawSnapshot
);
239 InspectorTest
.HeapEdge = function(targetNode
, type
, nameOrIndex
)
241 this._targetNode
= targetNode
;
243 this._nameOrIndex
= nameOrIndex
;
246 InspectorTest
.HeapEdge
.prototype = {
247 _serialize: function(rawSnapshot
)
249 if (!this._targetNode
._builder
)
250 throw new Error("Inconsistent state of node: " + this._name
+ " no builder assigned");
251 var builder
= this._targetNode
._builder
;
252 rawSnapshot
.edges
.push(builder
.lookupEdgeType(this._type
));
253 rawSnapshot
.edges
.push(typeof this._nameOrIndex
=== "string" ? builder
.lookupOrAddString(this._nameOrIndex
) : this._nameOrIndex
);
254 rawSnapshot
.edges
.push(this._targetNode
._ordinal
* builder
.nodeFieldsCount
); // index
258 InspectorTest
.HeapEdge
.Type
= {
259 "context": "context",
260 "element": "element",
261 "property": "property",
262 "internal": "internal",
264 "shortcut": "shortcut",
268 InspectorTest
.HeapSnapshotBuilder = function()
271 this._string2id
= {};
273 this.nodeFieldsCount
= 7;
275 this._nodeTypesMap
= {};
276 this._nodeTypesArray
= [];
277 for (var nodeType
in InspectorTest
.HeapNode
.Type
) {
278 this._nodeTypesMap
[nodeType
] = this._nodeTypesArray
.length
279 this._nodeTypesArray
.push(nodeType
);
282 this._edgeTypesMap
= {};
283 this._edgeTypesArray
= [];
284 for (var edgeType
in InspectorTest
.HeapEdge
.Type
) {
285 this._edgeTypesMap
[edgeType
] = this._edgeTypesArray
.length
286 this._edgeTypesArray
.push(edgeType
);
289 this.rootNode
= new InspectorTest
.HeapNode("root", 0, "object");
290 this.rootNode
._setBuilder(this);
293 InspectorTest
.HeapSnapshotBuilder
.prototype = {
294 generateSnapshot: function()
299 "node_fields": ["type","name","id","self_size","retained_size","dominator","edge_count"],
301 this._nodeTypesArray
,
309 "edge_fields": ["type","name_or_index","to_node"],
311 this._edgeTypesArray
,
322 for (var i
= 0; i
< this._nodes
.length
; ++i
)
323 this._nodes
[i
]._serialize(rawSnapshot
);
325 rawSnapshot
.strings
= this._strings
.slice();
327 var meta
= rawSnapshot
.snapshot
.meta
;
328 rawSnapshot
.snapshot
.edge_count
= rawSnapshot
.edges
.length
/ meta
.edge_fields
.length
;
329 rawSnapshot
.snapshot
.node_count
= rawSnapshot
.nodes
.length
/ meta
.node_fields
.length
;
334 createJSHeapSnapshot: function()
336 var parsedSnapshot
= InspectorTest
._postprocessHeapSnapshotMock(this.generateSnapshot());
337 return new WebInspector
.JSHeapSnapshot(parsedSnapshot
, new WebInspector
.HeapSnapshotProgress());
340 _registerNode: function(node
)
342 this._nodes
.push(node
);
343 return this._nodes
.length
- 1;
346 lookupNodeType: function(typeName
)
348 if (typeName
=== undefined)
349 throw new Error("wrong node type: " + typeName
);
350 if (!typeName
in this._nodeTypesMap
)
351 throw new Error("wrong node type name: " + typeName
);
352 return this._nodeTypesMap
[typeName
];
355 lookupEdgeType: function(typeName
)
357 if (!typeName
in this._edgeTypesMap
)
358 throw new Error("wrong edge type name: " + typeName
);
359 return this._edgeTypesMap
[typeName
];
362 lookupOrAddString: function(string
)
364 if (string
in this._string2id
)
365 return this._string2id
[string
];
366 this._string2id
[string
] = this._strings
.length
;
367 this._strings
.push(string
);
368 return this._strings
.length
- 1;
372 InspectorTest
.createHeapSnapshot = function(instanceCount
, firstId
)
374 // Mocking results of running the following code:
376 // function A() { this.a = this; }
377 // function B() { this.a = new A(); }
378 // for (var i = 0; i < instanceCount; ++i) window[i] = new B();
380 // Set A and B object sizes to pseudo random numbers. It is used in sorting tests.
383 function pseudoRandom(limit
) {
384 seed
= ((seed
* 355109 + 153763) >> 2) & 0xffff;
388 var builder
= new InspectorTest
.HeapSnapshotBuilder();
389 var rootNode
= builder
.rootNode
;
391 var gcRootsNode
= new InspectorTest
.HeapNode("(GC roots)", 0, InspectorTest
.HeapNode
.Type
.synthetic
);
392 rootNode
.linkNode(gcRootsNode
, InspectorTest
.HeapEdge
.Type
.element
);
394 var windowNode
= new InspectorTest
.HeapNode("Window", 20);
395 rootNode
.linkNode(windowNode
, InspectorTest
.HeapEdge
.Type
.shortcut
);
396 gcRootsNode
.linkNode(windowNode
, InspectorTest
.HeapEdge
.Type
.element
);
398 for (var i
= 0; i
< instanceCount
; ++i
) {
399 var sizeOfB
= pseudoRandom(20) + 1;
400 var nodeB
= new InspectorTest
.HeapNode("B", sizeOfB
, undefined, firstId
++);
401 windowNode
.linkNode(nodeB
, InspectorTest
.HeapEdge
.Type
.element
);
402 var sizeOfA
= pseudoRandom(50) + 1;
403 var nodeA
= new InspectorTest
.HeapNode("A", sizeOfA
, undefined, firstId
++);
404 nodeB
.linkNode(nodeA
, InspectorTest
.HeapEdge
.Type
.property
, "a");
405 nodeA
.linkNode(nodeA
, InspectorTest
.HeapEdge
.Type
.property
, "a");
407 return builder
.generateSnapshot();
412 InspectorTest
.createHeapSnapshotMockFactories();
415 InspectorTest
.startProfilerTest = function(callback
)
417 WebInspector
.settingForTest("showAdvancedHeapSnapshotProperties").set(true);
419 InspectorTest
.addResult("Profiler was enabled.");
420 // We mock out HeapProfilerAgent -- as DRT runs in single-process mode, Inspector
421 // and test share the same heap. Taking a snapshot takes too long for a test,
422 // so we provide synthetic snapshots.
423 InspectorTest
._panelReset
= InspectorTest
.override(WebInspector
.panels
.profiles
, "_reset", function(){}, true);
424 InspectorTest
.addSniffer(WebInspector
.HeapSnapshotView
.prototype, "show", InspectorTest
._snapshotViewShown
, true);
426 // Reduce the number of populated nodes to speed up testing.
427 WebInspector
.HeapSnapshotContainmentDataGrid
.prototype.defaultPopulateCount = function() { return 10; };
428 WebInspector
.HeapSnapshotConstructorsDataGrid
.prototype.defaultPopulateCount = function() { return 10; };
429 WebInspector
.HeapSnapshotDiffDataGrid
.prototype.defaultPopulateCount = function() { return 5; };
430 InspectorTest
.addResult("Detailed heap profiles were enabled.");
431 InspectorTest
.safeWrap(callback
)();
434 InspectorTest
.completeProfilerTest = function()
436 // There is no way to disable detailed heap profiles.
437 InspectorTest
.addResult("");
438 InspectorTest
.addResult("Profiler was disabled.");
439 InspectorTest
.completeTest();
442 InspectorTest
.runHeapSnapshotTestSuite = function(testSuite
)
444 var testSuiteTests
= testSuite
.slice();
445 var completeTestStack
;
449 if (!testSuiteTests
.length
) {
450 if (completeTestStack
)
451 InspectorTest
.addResult("FAIL: test already completed at " + completeTestStack
);
452 InspectorTest
.completeProfilerTest();
453 completeTestStack
= new Error().stack
;
457 var nextTest
= testSuiteTests
.shift();
458 InspectorTest
.addResult("");
459 InspectorTest
.addResult("Running: " + /function\s([^(]*)/.exec(nextTest
)[1]);
460 InspectorTest
._panelReset
.call(WebInspector
.panels
.profiles
);
461 InspectorTest
.safeWrap(nextTest
)(runner
, runner
);
464 InspectorTest
.startProfilerTest(runner
);
467 InspectorTest
.assertColumnContentsEqual = function(reference
, actual
)
469 var length
= Math
.min(reference
.length
, actual
.length
);
470 for (var i
= 0; i
< length
; ++i
)
471 InspectorTest
.assertEquals(reference
[i
], actual
[i
], "row " + i
);
472 if (reference
.length
> length
)
473 InspectorTest
.addResult("extra rows in reference array:\n" + reference
.slice(length
).join("\n"));
474 else if (actual
.length
> length
)
475 InspectorTest
.addResult("extra rows in actual array:\n" + actual
.slice(length
).join("\n"));
478 InspectorTest
.checkArrayIsSorted = function(contents
, sortType
, sortOrder
)
480 function simpleComparator(a
, b
)
482 return a
< b
? -1 : (a
> b
? 1 : 0);
484 function parseSize(size
)
486 // Remove thousands separator.
487 return parseInt(size
.replace(/[\u2009,]/g, ""), 10);
490 text: function (data
) { data
; },
491 number: function (data
) { return parseInt(data
, 10); },
493 name: function (data
) { return data
; },
494 id: function (data
) { return parseInt(data
, 10); }
498 InspectorTest
.addResult("Invalid sort type: " + sortType
);
502 var acceptableComparisonResult
;
503 if (sortOrder
=== WebInspector
.DataGrid
.Order
.Ascending
) {
504 acceptableComparisonResult
= -1;
505 } else if (sortOrder
=== WebInspector
.DataGrid
.Order
.Descending
) {
506 acceptableComparisonResult
= 1;
508 InspectorTest
.addResult("Invalid sort order: " + sortOrder
);
512 for (var i
= 0; i
< contents
.length
- 1; ++i
) {
513 var a
= extractor(contents
[i
]);
514 var b
= extractor(contents
[i
+ 1]);
515 var result
= simpleComparator(a
, b
);
516 if (result
!== 0 && result
!== acceptableComparisonResult
) {
517 InspectorTest
.addResult("Elements " + i
+ " and " + (i
+ 1) + " are out of order: " + a
+ " " + b
+ " (" + sortOrder
+ ")");
522 InspectorTest
.clickColumn = function(column
, callback
)
524 callback
= InspectorTest
.safeWrap(callback
);
525 var cell
= this._currentGrid()._headerTableHeaders
[column
.identifier
];
526 var event
= { target
: { enclosingNodeOrSelfWithNodeName: function() { return cell
; } } };
528 function sortingComplete()
530 InspectorTest
._currentGrid().removeEventListener(WebInspector
.HeapSnapshotSortableDataGrid
.Events
.SortingComplete
, sortingComplete
, this);
531 InspectorTest
.assertEquals(column
.identifier
, this._currentGrid().sortColumnIdentifier(), "unexpected sorting");
532 column
.sort
= this._currentGrid().sortOrder();
533 function callCallback()
537 setTimeout(callCallback
, 0);
539 InspectorTest
._currentGrid().addEventListener(WebInspector
.HeapSnapshotSortableDataGrid
.Events
.SortingComplete
, sortingComplete
, this);
540 this._currentGrid()._clickInHeaderCell(event
);
543 InspectorTest
.clickRowAndGetRetainers = function(row
, callback
)
545 callback
= InspectorTest
.safeWrap(callback
);
548 enclosingNodeOrSelfWithNodeName: function() { return row
._element
; },
552 this._currentGrid()._mouseDownInDataTable(event
);
553 var rootNode
= InspectorTest
.currentProfileView()._retainmentDataGrid
.rootNode();
554 function populateComplete()
556 rootNode
.removeEventListener(WebInspector
.HeapSnapshotGridNode
.Events
.PopulateComplete
, populateComplete
, this);
559 rootNode
.addEventListener(WebInspector
.HeapSnapshotGridNode
.Events
.PopulateComplete
, populateComplete
, this);
562 InspectorTest
.clickShowMoreButton = function(buttonName
, row
, callback
)
564 callback
= InspectorTest
.safeWrap(callback
);
565 var parent
= row
.parent
;
566 function populateComplete()
568 parent
.removeEventListener(WebInspector
.HeapSnapshotGridNode
.Events
.PopulateComplete
, populateComplete
, this);
569 function callCallback()
573 setTimeout(callCallback
, 0);
575 parent
.addEventListener(WebInspector
.HeapSnapshotGridNode
.Events
.PopulateComplete
, populateComplete
, this);
576 row
[buttonName
].click();
579 InspectorTest
.columnContents = function(column
, row
)
581 // Make sure invisible nodes are removed from the view port.
582 this._currentGrid().updateVisibleNodes();
583 var columnOrdinal
= InspectorTest
.viewColumns().indexOf(column
);
585 var parent
= row
|| this._currentGrid().rootNode();
586 for (var node
= parent
.children
[0]; node
; node
= node
.traverseNextNode(true, parent
, true)) {
587 if (!node
.selectable
)
589 var content
= node
.element().children
[columnOrdinal
];
590 // Do not inlcude percents
591 if (content
.firstElementChild
)
592 content
= content
.firstElementChild
;
593 result
.push(content
.textContent
);
598 InspectorTest
.countDataRows = function(row
, filter
)
601 filter
= filter
|| function(node
) { return node
.selectable
; };
602 for (var node
= row
.children
[0]; node
; node
= node
.traverseNextNode(true, row
, true)) {
609 InspectorTest
.expandRow = function(row
, callback
)
611 callback
= InspectorTest
.safeWrap(callback
);
612 function populateComplete()
614 row
.removeEventListener(WebInspector
.HeapSnapshotGridNode
.Events
.PopulateComplete
, populateComplete
, this);
615 function callCallback()
619 setTimeout(callCallback
, 0);
621 row
.addEventListener(WebInspector
.HeapSnapshotGridNode
.Events
.PopulateComplete
, populateComplete
, this);
627 setTimeout(expand
, 0);
631 InspectorTest
.findAndExpandGCRoots = function(callback
)
633 InspectorTest
.findAndExpandRow("(GC roots)", callback
);
636 InspectorTest
.findAndExpandWindow = function(callback
)
638 InspectorTest
.findAndExpandRow("Window", callback
);
641 InspectorTest
.findAndExpandRow = function(name
, callback
)
643 callback
= InspectorTest
.safeWrap(callback
);
644 var row
= InspectorTest
.findRow(name
);
645 InspectorTest
.assertEquals(true, !!row
, '"' + name
+ '" row');
646 InspectorTest
.expandRow(row
, callback
);
649 InspectorTest
.findButtonsNode = function(row
, startNode
)
652 for (var node
= startNode
|| row
.children
[0]; node
; node
= node
.traverseNextNode(true, row
, true)) {
653 if (!node
.selectable
&& node
.showNext
)
659 InspectorTest
.findRow = function(name
, parent
)
663 return x
._name
=== name
;
665 return InspectorTest
.findMatchingRow(matcher
, parent
);
668 InspectorTest
.findMatchingRow = function(matcher
, parent
)
670 parent
= parent
|| this._currentGrid().rootNode();
671 for (var node
= parent
.children
[0]; node
; node
= node
.traverseNextNode(true, parent
, true)) {
678 InspectorTest
.switchToView = function(title
, callback
)
680 callback
= InspectorTest
.safeWrap(callback
);
681 var view
= WebInspector
.panels
.profiles
.visibleView
;
682 view
._changePerspectiveAndWait(title
, callback
);
683 // Increase the grid container height so the viewport don't limit the number of nodes.
684 InspectorTest
._currentGrid().scrollContainer
.style
.height
= "10000px";
687 InspectorTest
.takeAndOpenSnapshot = function(generator
, callback
)
689 callback
= InspectorTest
.safeWrap(callback
);
690 var snapshot
= generator();
691 var profileType
= WebInspector
.ProfileTypeRegistry
.instance
.heapSnapshotProfileType
;
692 function pushGeneratedSnapshot(reportProgress
, callback2
)
694 var profile
= profileType
.profileBeingRecorded();
695 if (reportProgress
) {
696 profileType
._reportHeapSnapshotProgress({data
: {done
: 50, total
: 100, finished
: false}});
697 profileType
._reportHeapSnapshotProgress({data
: {done
: 100, total
: 100, finished
: true}});
699 snapshot
.snapshot
.typeId
= "HEAP";
700 profileType
._addHeapSnapshotChunk({data
: JSON
.stringify(snapshot
)});
701 setTimeout(callback2
, 0);
703 InspectorTest
.override(InspectorTest
.HeapProfilerAgent
, "takeHeapSnapshot", pushGeneratedSnapshot
);
704 InspectorTest
._takeAndOpenSnapshotCallback
= callback
;
705 profileType
._takeHeapSnapshot(function() { });
708 InspectorTest
.viewColumns = function()
710 return InspectorTest
._currentGrid()._columnsArray
;
713 InspectorTest
.currentProfileView = function()
715 return WebInspector
.panels
.profiles
.visibleView
;
718 InspectorTest
._currentGrid = function()
720 return this.currentProfileView()._dataGrid
;
723 InspectorTest
._snapshotViewShown = function()
725 if (InspectorTest
._takeAndOpenSnapshotCallback
) {
726 var callback
= InspectorTest
._takeAndOpenSnapshotCallback
;
727 InspectorTest
._takeAndOpenSnapshotCallback
= null;
728 var dataGrid
= this._dataGrid
;
729 function sortingComplete()
731 dataGrid
.removeEventListener(WebInspector
.HeapSnapshotSortableDataGrid
.Events
.SortingComplete
, sortingComplete
, null);
734 dataGrid
.addEventListener(WebInspector
.HeapSnapshotSortableDataGrid
.Events
.SortingComplete
, sortingComplete
, null);