| Index: tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html
|
| diff --git a/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html b/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html
|
| index 18291eb4009d4c1689a976a5d80c658e69acea34..2d2c0b7d8326b72592f499a8722549603a1ffb40 100644
|
| --- a/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html
|
| +++ b/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html
|
| @@ -28,6 +28,13 @@ found in the LICENSE file.
|
| overflow: auto;
|
| }
|
| </style>
|
| + <div>
|
| + Organize by:
|
| + <select id="select">
|
| + <option value="none">None</option>
|
| + <option value="tree">Frame Tree</option>
|
| + </select>
|
| + </div>
|
| <table-container>
|
| <tr-ui-b-table id="table"></tr-ui-b-table>
|
| </table-container>
|
| @@ -49,12 +56,24 @@ tr.exportTo('tr.ui.e.s', function() {
|
|
|
| /**
|
| * @constructor
|
| + * If |context| is provided, creates a row for the given context.
|
| + * Otherwise, creates an empty Row template which can be used for aggregating
|
| + * data from a group of subrows.
|
| */
|
| function Row(context) {
|
| - this.type = context.objectInstance.blameContextType;
|
| + this.subRows = undefined;
|
| + this.contexts = [];
|
| + this.type = undefined;
|
| + this.renderer = 'N/A';
|
| + this.url = undefined;
|
| + this.time = 0;
|
| + this.eventsOfInterest = new tr.model.EventSet();
|
| +
|
| + if (context === undefined)
|
| + return;
|
|
|
| - this.contexts = [context];
|
| - this.renderer = undefined;
|
| + this.type = context.objectInstance.blameContextType;
|
| + this.contexts.push(context);
|
| if (context instanceof FrameTreeNodeSnapshot) {
|
| if (context.renderFrame) {
|
| this.contexts.push(context.renderFrame);
|
| @@ -69,17 +88,81 @@ tr.exportTo('tr.ui.e.s', function() {
|
| } else {
|
| throw new Error('Unknown context type');
|
| }
|
| + this.eventsOfInterest.addEventSet(this.contexts);
|
|
|
| // TODO(xiaochengh): Handle the case where a subframe has a trivial url
|
| // (e.g., about:blank), but inherits the origin of its parent. This is not
|
| // needed now, but will be required if we want to group rows by origin.
|
| this.url = context.url;
|
| -
|
| - // To be computed in batch later for efficiency.
|
| - this.eventsOfInterest = new tr.model.EventSet(this.contexts);
|
| - this.time = 0;
|
| }
|
|
|
| + var groupFunctions = {
|
| + none: rows => rows,
|
| +
|
| + // Group the rows according to the frame tree structure.
|
| + // Example: consider frame tree a(b, c(d)), where each frame has 1ms time
|
| + // attributed to it. The resulting table should look like:
|
| + // Type | Time | URL
|
| + // --------------+------+-----
|
| + // Frame Tree | 4 | a
|
| + // +- Frame | 1 | a
|
| + // +- Subframe | 1 | b
|
| + // +- Frame Tree | 2 | c
|
| + // +- Frame | 1 | c
|
| + // +- Subframe | 1 | d
|
| + tree: function(rows, rowMap) {
|
| + // Finds the parent of a specific row. When there is conflict between the
|
| + // browser's dump of the frame tree and the renderers', use the browser's.
|
| + var getParentRow = function(row) {
|
| + var pivot;
|
| + row.contexts.forEach(function(context) {
|
| + if (context instanceof tr.e.chrome.FrameTreeNodeSnapshot)
|
| + pivot = context;
|
| + });
|
| + if (pivot && pivot.parentContext)
|
| + return rowMap[pivot.parentContext.guid];
|
| + return undefined;
|
| + };
|
| +
|
| + var rootRows = [];
|
| + rows.forEach(function(row) {
|
| + var parentRow = getParentRow(row);
|
| + if (parentRow === undefined) {
|
| + rootRows.push(row);
|
| + return;
|
| + }
|
| + if (parentRow.subRows === undefined)
|
| + parentRow.subRows = [];
|
| + parentRow.subRows.push(row);
|
| + });
|
| +
|
| + var aggregateAllDescendants = function(row) {
|
| + if (!row.subRows) {
|
| + if (getParentRow(row))
|
| + row.type = 'Subframe';
|
| + return row;
|
| + }
|
| + var result = new Row();
|
| + result.type = 'Frame Tree';
|
| + result.renderer = row.renderer;
|
| + result.url = row.url;
|
| + result.subRows = [row];
|
| + row.subRows.forEach(
|
| + subRow => result.subRows.push(aggregateAllDescendants(subRow)));
|
| + result.subRows.forEach(function(subRow) {
|
| + result.time += subRow.time;
|
| + result.eventsOfInterest.addEventSet(subRow.eventsOfInterest);
|
| + });
|
| + row.subRows = undefined;
|
| + return result;
|
| + };
|
| +
|
| + return rootRows.map(rootRow => aggregateAllDescendants(rootRow));
|
| + }
|
| +
|
| + // TODO(xiaochengh): Add grouping by site and probably more...
|
| + };
|
| +
|
| Polymer({
|
| is: 'tr-ui-e-s-frame-data-side-panel',
|
| behaviors: [tr.ui.behaviors.SidePanel],
|
| @@ -88,8 +171,6 @@ tr.exportTo('tr.ui.e.s', function() {
|
| this.model_ = undefined;
|
| this.rangeOfInterest_ = new tr.b.Range();
|
|
|
| - // TODO(xiaochengh): Design proper grouping of the rows (by renderer
|
| - // pid, frame tree topology, site, ...) in a follow-up patch.
|
| this.$.table.showHeader = true;
|
| this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW;
|
| this.$.table.tableColumns = this.createFrameDataTableColumns_();
|
| @@ -97,6 +178,10 @@ tr.exportTo('tr.ui.e.s', function() {
|
| this.$.table.addEventListener('selection-changed', function(e) {
|
| this.selectEventSet_(this.$.table.selectedTableRow.eventsOfInterest);
|
| }.bind(this));
|
| +
|
| + this.$.select.addEventListener('change', function(e) {
|
| + this.updateContents_();
|
| + }.bind(this));
|
| },
|
|
|
| selectEventSet_: function(eventSet) {
|
| @@ -146,7 +231,7 @@ tr.exportTo('tr.ui.e.s', function() {
|
| var rowMap = {};
|
| tr.b.iterItems(this.model_.processes, function(pid, process) {
|
| process.objects.iterObjectInstances(function(objectInstance) {
|
| - if (!objectInstance instanceof BlameContextInstance)
|
| + if (!(objectInstance instanceof BlameContextInstance))
|
| return;
|
| objectInstance.snapshots.forEach(function(snapshot) {
|
| if (rowMap[snapshot.guid])
|
| @@ -176,7 +261,11 @@ tr.exportTo('tr.ui.e.s', function() {
|
| }, this);
|
| }, this);
|
|
|
| - return rows;
|
| + // Apply grouping to rows.
|
| + var select = this.$.select;
|
| + var groupOption = select.options[select.selectedIndex].value;
|
| + var groupFunction = groupFunctions[groupOption];
|
| + return groupFunction(rows, rowMap);
|
| },
|
|
|
| updateContents_: function() {
|
|
|