Chromium Code Reviews| Index: chrome/browser/resources/profiler.js |
| =================================================================== |
| --- chrome/browser/resources/profiler.js (revision 110261) |
| +++ chrome/browser/resources/profiler.js (working copy) |
| @@ -5,10 +5,6 @@ |
| var g_browserBridge; |
| var g_mainView; |
| -// TODO(eroman): Don't repeat the work of grouping, sorting, merging on every |
| -// redraw. Rather do it only once when one of its dependencies |
| -// change and cache the result. |
| - |
| /** |
| * Main entry point called once the page has loaded. |
| */ |
| @@ -723,48 +719,6 @@ |
| // -------------------------------------------------------------------------- |
| /** |
| - * Selects all the data in |rows| which are matched by |filterFunc|, and |
| - * buckets the results using |entryToGroupKeyFunc|. For each bucket aggregates |
| - * are computed, and the results are sorted. |
| - * |
| - * Returns a dictionary whose keys are the group name, and the value is an |
| - * objected containing two properties: |rows| and |aggregates|. |
| - */ |
| - function prepareData(rows, entryToGroupKeyFunc, filterFunc, sortingFunc) { |
| - var groupedData = {}; |
| - |
| - for (var i = 0; i < rows.length; ++i) { |
| - var e = rows[i]; |
| - |
| - if (!filterFunc(e)) |
| - continue; // Not matched by our filter, discard the row. |
| - |
| - var groupKey = entryToGroupKeyFunc(e); |
| - |
| - var groupData = groupedData[groupKey]; |
| - if (!groupData) { |
| - groupData = { |
| - aggregates: initializeAggregates(ALL_KEYS), |
| - rows: [], |
| - }; |
| - groupedData[groupKey] = groupData; |
| - } |
| - |
| - // Add the row to our list. |
| - groupData.rows.push(e); |
| - |
| - // Update aggregates for each column. |
| - consumeAggregates(groupData.aggregates, e); |
| - } |
| - |
| - // Sort all the data. |
| - for (var groupKey in groupedData) |
| - groupedData[groupKey].rows.sort(sortingFunc); |
| - |
| - return groupedData; |
| - } |
| - |
| - /** |
| * Adds new derived properties to row. Mutates the provided dictionary |e|. |
| */ |
| function augmentDataRow(e) { |
| @@ -913,12 +867,12 @@ |
| /** |
| * Renders the information for a particular group. |
| */ |
| - function drawGroup(parent, groupKey, groupData, columns, |
| + function drawGroup(parent, groupData, columns, |
| columnOnClickHandler, currentSortKeys) { |
| var div = addNode(parent, 'div'); |
| div.className = 'group-container'; |
| - drawGroupTitle(div, groupKey); |
| + drawGroupTitle(div, groupData.key); |
| var table = addNode(div, 'table'); |
| @@ -1211,38 +1165,96 @@ |
| // Add our computed properties. |
| augmentDataRow(newRow); |
| - this.allData_.push(newRow); |
| + this.flatData_.push(newRow); |
| } |
| + // Recompute the merged data based on flatData_. |
| + this.updateMergedData_(); |
| + }, |
| + |
| + updateMergedData_: function() { |
| + // Recompute mergedData_. |
| + this.mergedData_ = mergeRows(this.flatData_, |
| + this.getMergeColumns_(), |
| + this.shouldMergeSimilarThreads_()); |
| + |
| + // Recompute filteredData_ (since it is derived from mergedData_) |
| + this.updateFilteredData_(); |
| + }, |
| + |
| + updateFilteredData_: function() { |
| + // Recompute filteredData_. |
| + this.filteredData_ = []; |
| + var filterFunc = this.getFilterFunction_(); |
| + for (var i = 0; i < this.mergedData_.length; ++i) { |
| + var r = this.mergedData_[i]; |
| + if (!filterFunc(r)) { |
| + // Not matched by our filter, discard. |
| + continue; |
| + } |
| + this.filteredData_.push(r); |
| + } |
| + |
| + // Recompute groupedData_ (since it is derived from filteredData_) |
| + this.updateGroupedData_(); |
| + }, |
| + |
| + updateGroupedData_: function() { |
| + // Recompute groupedData_. |
| + var groupKeyToData = {}; |
| + var entryToGroupKeyFunc = this.getGroupingFunction_(); |
| + for (var i = 0; i < this.filteredData_.length; ++i) { |
| + var r = this.filteredData_[i]; |
| + |
| + var groupKey = entryToGroupKeyFunc(r); |
| + |
| + var groupData = groupKeyToData[groupKey]; |
| + if (!groupData) { |
| + groupData = { |
| + key: JSON.parse(groupKey), |
| + aggregates: initializeAggregates(ALL_KEYS), |
| + rows: [], |
| + }; |
| + groupKeyToData[groupKey] = groupData; |
| + } |
| + |
| + // Add the row to our list. |
| + groupData.rows.push(r); |
| + |
| + // Update aggregates for each column. |
| + consumeAggregates(groupData.aggregates, r); |
| + } |
| + this.groupedData_ = groupKeyToData; |
| + |
| + // Figure out a display order for the groups themselves. |
| + this.sortedGroupKeys_ = getDictionaryKeys(groupKeyToData); |
| + this.sortedGroupKeys_.sort(this.getGroupSortingFunction_()); |
| + |
| + // Sort the group data. |
| + this.sortGroupedData_(); |
| + }, |
| + |
| + sortGroupedData_: function() { |
| + var sortingFunc = this.getSortingFunction_(); |
| + for (var k in this.groupedData_) |
| + this.groupedData_[k].rows.sort(sortingFunc); |
| + |
| + // Every cached data dependency is now up to date, all that is left is |
| + // to actually draw the result. |
| this.redrawData_(); |
| }, |
| - redrawData_: function() { |
| - // Eliminate columns which we are merging on. |
| - var mergedKeys = this.getMergeColumns_(); |
| - var data = mergeRows( |
| - this.allData_, mergedKeys, this.shouldMergeSimilarThreads_()); |
| - |
| + getVisibleColumnKeys_: function() { |
| // Figure out what columns to include, based on the selected checkboxes. |
| var columns = this.getSelectionColumns_(); |
| - deleteValuesFromArray(columns, mergedKeys); |
| - // Group, aggregate, filter, and sort the data. |
| - var groupedData = prepareData( |
| - data, this.getGroupingFunction_(), this.getFilterFunction_(), |
| - this.getSortingFunction_()); |
| + // Eliminate columns which we are merging on. |
| + deleteValuesFromArray(columns, this.getMergeColumns_()); |
| - // Figure out a display order for the groups. |
| - var groupKeys = getDictionaryKeys(groupedData); |
| - groupKeys.sort(this.getGroupSortingFunction_()); |
| - |
| - // Clear the results div, sine we may be overwriting older data. |
| - var parent = $(RESULTS_DIV_ID); |
| - parent.innerHTML = ''; |
| - |
| - if (groupKeys.length > 0) { |
| + // Eliminate columns which we are grouped on. |
| + if (this.sortedGroupKeys_.length > 0) { |
| // The grouping will be the the same for each so just pick the first. |
| - var randomGroupKey = JSON.parse(groupKeys[0]); |
| + var randomGroupKey = this.groupedData_[this.sortedGroupKeys_[0]].key; |
| // The grouped properties are going to be the same for each row in our, |
| // table, so avoid drawing them in our table! |
| @@ -1254,21 +1266,46 @@ |
| deleteValuesFromArray(columns, keysToExclude); |
| } |
| + return columns; |
| + }, |
| + |
| + redrawData_: function() { |
| + // Clear the results div, sine we may be overwriting older data. |
| + var parent = $(RESULTS_DIV_ID); |
| + parent.innerHTML = ''; |
| + |
| + var columns = this.getVisibleColumnKeys_(); |
| + |
| var columnOnClickHandler = this.onClickColumn_.bind(this); |
| // Draw each group. |
| - for (var i = 0; i < groupKeys.length; ++i) { |
| - var groupKeyString = groupKeys[i]; |
| - var groupData = groupedData[groupKeyString]; |
| - var groupKey = JSON.parse(groupKeyString); |
| - |
| - drawGroup(parent, groupKey, groupData, columns, |
| + for (var i = 0; i < this.sortedGroupKeys_.length; ++i) { |
| + var groupData = this.groupedData_[this.sortedGroupKeys_[i]]; |
| + drawGroup(parent, groupData, columns, |
| columnOnClickHandler, this.currentSortKeys_); |
| } |
| }, |
| init_: function() { |
| - this.allData_ = []; |
| + // Data goes through the following pipeline: |
|
jar (doing other things)
2011/11/17 02:40:31
This sort of comment is quite helpful.
|
| + // (1) Raw data received from browser, and transformed into our own |
| + // internal row format (where properties are indexed by KEY_* |
| + // constants.) |
| + // (2) We "augment" each row by adding some extra computed columns |
| + // (like averages). |
| + // (3) The rows are merged using current merge settings. |
| + // (4) The rows that don't match current search expression are |
| + // tossed out. |
| + // (5) The rows are organized into "groups" based on current settings, |
| + // and aggregate values are computed for each resulting group. |
| + // (6) The rows within each group are sorted using current settings. |
| + // (7) The grouped rows are drawn to the screen. |
| + this.flatData_ = []; |
| + this.mergedData_ = []; |
| + this.filteredData_ = []; |
| + this.groupedData_ = {}; |
| + this.sortedGroupKeys_ = []; |
| + |
| this.fillSelectionCheckboxes_($(COLUMN_TOGGLES_CONTAINER_ID)); |
| this.fillMergeCheckboxes_($(COLUMN_MERGE_TOGGLES_CONTAINER_ID)); |
| @@ -1385,13 +1422,13 @@ |
| onChangedGrouping_: function(select, i) { |
| updateKeyListFromDropdown(this.currentGroupingKeys_, i, select); |
| this.fillGroupingDropdowns_(); |
| - this.redrawData_(); |
| + this.updateGroupedData_(); |
| }, |
| onChangedSorting_: function(select, i) { |
| updateKeyListFromDropdown(this.currentSortKeys_, i, select); |
| this.fillSortingDropdowns_(); |
| - this.redrawData_(); |
| + this.sortGroupedData_(); |
| }, |
| onSelectCheckboxChanged_: function() { |
| @@ -1399,15 +1436,15 @@ |
| }, |
| onMergeCheckboxChanged_: function() { |
| - this.redrawData_(); |
| + this.updateMergedData_(); |
| }, |
| onMergeSimilarThreadsCheckboxChanged_: function() { |
| - this.redrawData_(); |
| + this.updateMergedData_(); |
| }, |
| onChangedFilter_: function() { |
| - this.redrawData_(); |
| + this.updateFilteredData_(); |
| }, |
| /** |
| @@ -1456,7 +1493,7 @@ |
| } |
| this.fillSortingDropdowns_(); |
| - this.redrawData_(); |
| + this.sortGroupedData_(); |
| }, |
| getSortingFunction_: function() { |