Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Side by Side Diff: chrome/browser/resources/profiler.js

Issue 8590001: Cache the results of merging/filtering/grouping data in about:profiler. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: re-upload to make sure file hasn't changed... Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 var g_browserBridge; 5 var g_browserBridge;
6 var g_mainView; 6 var g_mainView;
7 7
8 // TODO(eroman): Don't repeat the work of grouping, sorting, merging on every
9 // redraw. Rather do it only once when one of its dependencies
10 // change and cache the result.
11
12 /** 8 /**
13 * Main entry point called once the page has loaded. 9 * Main entry point called once the page has loaded.
14 */ 10 */
15 function onLoad() { 11 function onLoad() {
16 g_browserBridge = new BrowserBridge(); 12 g_browserBridge = new BrowserBridge();
17 g_mainView = new MainView(); 13 g_mainView = new MainView();
18 14
19 // Ask the browser to send us the current data. 15 // Ask the browser to send us the current data.
20 g_browserBridge.sendGetData(); 16 g_browserBridge.sendGetData();
21 } 17 }
(...skipping 694 matching lines...) Expand 10 before | Expand all | Expand 10 after
716 return path; 712 return path;
717 713
718 return path.substr(lastSlash + 1); 714 return path.substr(lastSlash + 1);
719 } 715 }
720 716
721 // -------------------------------------------------------------------------- 717 // --------------------------------------------------------------------------
722 // Functions that augment, bucket, and compute aggregates for the input data. 718 // Functions that augment, bucket, and compute aggregates for the input data.
723 // -------------------------------------------------------------------------- 719 // --------------------------------------------------------------------------
724 720
725 /** 721 /**
726 * Selects all the data in |rows| which are matched by |filterFunc|, and
727 * buckets the results using |entryToGroupKeyFunc|. For each bucket aggregates
728 * are computed, and the results are sorted.
729 *
730 * Returns a dictionary whose keys are the group name, and the value is an
731 * objected containing two properties: |rows| and |aggregates|.
732 */
733 function prepareData(rows, entryToGroupKeyFunc, filterFunc, sortingFunc) {
734 var groupedData = {};
735
736 for (var i = 0; i < rows.length; ++i) {
737 var e = rows[i];
738
739 if (!filterFunc(e))
740 continue; // Not matched by our filter, discard the row.
741
742 var groupKey = entryToGroupKeyFunc(e);
743
744 var groupData = groupedData[groupKey];
745 if (!groupData) {
746 groupData = {
747 aggregates: initializeAggregates(ALL_KEYS),
748 rows: [],
749 };
750 groupedData[groupKey] = groupData;
751 }
752
753 // Add the row to our list.
754 groupData.rows.push(e);
755
756 // Update aggregates for each column.
757 consumeAggregates(groupData.aggregates, e);
758 }
759
760 // Sort all the data.
761 for (var groupKey in groupedData)
762 groupedData[groupKey].rows.sort(sortingFunc);
763
764 return groupedData;
765 }
766
767 /**
768 * Adds new derived properties to row. Mutates the provided dictionary |e|. 722 * Adds new derived properties to row. Mutates the provided dictionary |e|.
769 */ 723 */
770 function augmentDataRow(e) { 724 function augmentDataRow(e) {
771 e[KEY_AVG_QUEUE_TIME] = e[KEY_QUEUE_TIME] / e[KEY_COUNT]; 725 e[KEY_AVG_QUEUE_TIME] = e[KEY_QUEUE_TIME] / e[KEY_COUNT];
772 e[KEY_AVG_RUN_TIME] = e[KEY_RUN_TIME] / e[KEY_COUNT]; 726 e[KEY_AVG_RUN_TIME] = e[KEY_RUN_TIME] / e[KEY_COUNT];
773 e[KEY_SOURCE_LOCATION] = e[KEY_FILE_NAME] + ' [' + e[KEY_LINE_NUMBER] + ']'; 727 e[KEY_SOURCE_LOCATION] = e[KEY_FILE_NAME] + ' [' + e[KEY_LINE_NUMBER] + ']';
774 } 728 }
775 729
776 /** 730 /**
777 * Creates and initializes an aggregator object for each key in |columns|. 731 * Creates and initializes an aggregator object for each key in |columns|.
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
906 addNode(parent, 'i', ' and '); 860 addNode(parent, 'i', ' and ');
907 var e = groupKey[i]; 861 var e = groupKey[i];
908 addNode(parent, 'b', getNameForKey(e.key) + ' = '); 862 addNode(parent, 'b', getNameForKey(e.key) + ' = ');
909 addNode(parent, 'span', e.value); 863 addNode(parent, 'span', e.value);
910 } 864 }
911 } 865 }
912 866
913 /** 867 /**
914 * Renders the information for a particular group. 868 * Renders the information for a particular group.
915 */ 869 */
916 function drawGroup(parent, groupKey, groupData, columns, 870 function drawGroup(parent, groupData, columns,
917 columnOnClickHandler, currentSortKeys) { 871 columnOnClickHandler, currentSortKeys) {
918 var div = addNode(parent, 'div'); 872 var div = addNode(parent, 'div');
919 div.className = 'group-container'; 873 div.className = 'group-container';
920 874
921 drawGroupTitle(div, groupKey); 875 drawGroupTitle(div, groupData.key);
922 876
923 var table = addNode(div, 'table'); 877 var table = addNode(div, 'table');
924 878
925 drawDataTable(table, groupData, columns, columnOnClickHandler, 879 drawDataTable(table, groupData, columns, columnOnClickHandler,
926 currentSortKeys); 880 currentSortKeys);
927 } 881 }
928 882
929 /** 883 /**
930 * Renders a row that describes all the aggregate values for |columns|. 884 * Renders a row that describes all the aggregate values for |columns|.
931 */ 885 */
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
1204 // When resetting the data, it is possible for the backend to give us 1158 // When resetting the data, it is possible for the backend to give us
1205 // counts of "0". There is no point adding these rows (in fact they 1159 // counts of "0". There is no point adding these rows (in fact they
1206 // will cause us to do divide by zeros when calculating averages and 1160 // will cause us to do divide by zeros when calculating averages and
1207 // stuff), so we skip past them. 1161 // stuff), so we skip past them.
1208 continue; 1162 continue;
1209 } 1163 }
1210 1164
1211 // Add our computed properties. 1165 // Add our computed properties.
1212 augmentDataRow(newRow); 1166 augmentDataRow(newRow);
1213 1167
1214 this.allData_.push(newRow); 1168 this.flatData_.push(newRow);
1215 } 1169 }
1216 1170
1171 // Recompute the merged data based on flatData_.
1172 this.updateMergedData_();
1173 },
1174
1175 updateMergedData_: function() {
1176 // Recompute mergedData_.
1177 this.mergedData_ = mergeRows(this.flatData_,
1178 this.getMergeColumns_(),
1179 this.shouldMergeSimilarThreads_());
1180
1181 // Recompute filteredData_ (since it is derived from mergedData_)
1182 this.updateFilteredData_();
1183 },
1184
1185 updateFilteredData_: function() {
1186 // Recompute filteredData_.
1187 this.filteredData_ = [];
1188 var filterFunc = this.getFilterFunction_();
1189 for (var i = 0; i < this.mergedData_.length; ++i) {
1190 var r = this.mergedData_[i];
1191 if (!filterFunc(r)) {
1192 // Not matched by our filter, discard.
1193 continue;
1194 }
1195 this.filteredData_.push(r);
1196 }
1197
1198 // Recompute groupedData_ (since it is derived from filteredData_)
1199 this.updateGroupedData_();
1200 },
1201
1202 updateGroupedData_: function() {
1203 // Recompute groupedData_.
1204 var groupKeyToData = {};
1205 var entryToGroupKeyFunc = this.getGroupingFunction_();
1206 for (var i = 0; i < this.filteredData_.length; ++i) {
1207 var r = this.filteredData_[i];
1208
1209 var groupKey = entryToGroupKeyFunc(r);
1210
1211 var groupData = groupKeyToData[groupKey];
1212 if (!groupData) {
1213 groupData = {
1214 key: JSON.parse(groupKey),
1215 aggregates: initializeAggregates(ALL_KEYS),
1216 rows: [],
1217 };
1218 groupKeyToData[groupKey] = groupData;
1219 }
1220
1221 // Add the row to our list.
1222 groupData.rows.push(r);
1223
1224 // Update aggregates for each column.
1225 consumeAggregates(groupData.aggregates, r);
1226 }
1227 this.groupedData_ = groupKeyToData;
1228
1229 // Figure out a display order for the groups themselves.
1230 this.sortedGroupKeys_ = getDictionaryKeys(groupKeyToData);
1231 this.sortedGroupKeys_.sort(this.getGroupSortingFunction_());
1232
1233 // Sort the group data.
1234 this.sortGroupedData_();
1235 },
1236
1237 sortGroupedData_: function() {
1238 var sortingFunc = this.getSortingFunction_();
1239 for (var k in this.groupedData_)
1240 this.groupedData_[k].rows.sort(sortingFunc);
1241
1242 // Every cached data dependency is now up to date, all that is left is
1243 // to actually draw the result.
1217 this.redrawData_(); 1244 this.redrawData_();
1218 }, 1245 },
1219 1246
1220 redrawData_: function() { 1247 getVisibleColumnKeys_: function() {
1221 // Eliminate columns which we are merging on.
1222 var mergedKeys = this.getMergeColumns_();
1223 var data = mergeRows(
1224 this.allData_, mergedKeys, this.shouldMergeSimilarThreads_());
1225
1226 // Figure out what columns to include, based on the selected checkboxes. 1248 // Figure out what columns to include, based on the selected checkboxes.
1227 var columns = this.getSelectionColumns_(); 1249 var columns = this.getSelectionColumns_();
1228 deleteValuesFromArray(columns, mergedKeys);
1229 1250
1230 // Group, aggregate, filter, and sort the data. 1251 // Eliminate columns which we are merging on.
1231 var groupedData = prepareData( 1252 deleteValuesFromArray(columns, this.getMergeColumns_());
1232 data, this.getGroupingFunction_(), this.getFilterFunction_(),
1233 this.getSortingFunction_());
1234 1253
1235 // Figure out a display order for the groups. 1254 // Eliminate columns which we are grouped on.
1236 var groupKeys = getDictionaryKeys(groupedData); 1255 if (this.sortedGroupKeys_.length > 0) {
1237 groupKeys.sort(this.getGroupSortingFunction_());
1238
1239 // Clear the results div, sine we may be overwriting older data.
1240 var parent = $(RESULTS_DIV_ID);
1241 parent.innerHTML = '';
1242
1243 if (groupKeys.length > 0) {
1244 // The grouping will be the the same for each so just pick the first. 1256 // The grouping will be the the same for each so just pick the first.
1245 var randomGroupKey = JSON.parse(groupKeys[0]); 1257 var randomGroupKey = this.groupedData_[this.sortedGroupKeys_[0]].key;
1246 1258
1247 // The grouped properties are going to be the same for each row in our, 1259 // The grouped properties are going to be the same for each row in our,
1248 // table, so avoid drawing them in our table! 1260 // table, so avoid drawing them in our table!
1249 var keysToExclude = [] 1261 var keysToExclude = []
1250 1262
1251 for (var i = 0; i < randomGroupKey.length; ++i) 1263 for (var i = 0; i < randomGroupKey.length; ++i)
1252 keysToExclude.push(randomGroupKey[i].key); 1264 keysToExclude.push(randomGroupKey[i].key);
1253 columns = columns.slice(0); 1265 columns = columns.slice(0);
1254 deleteValuesFromArray(columns, keysToExclude); 1266 deleteValuesFromArray(columns, keysToExclude);
1255 } 1267 }
1256 1268
1269 return columns;
1270 },
1271
1272 redrawData_: function() {
1273 // Clear the results div, sine we may be overwriting older data.
1274 var parent = $(RESULTS_DIV_ID);
1275 parent.innerHTML = '';
1276
1277 var columns = this.getVisibleColumnKeys_();
1278
1257 var columnOnClickHandler = this.onClickColumn_.bind(this); 1279 var columnOnClickHandler = this.onClickColumn_.bind(this);
1258 1280
1259 // Draw each group. 1281 // Draw each group.
1260 for (var i = 0; i < groupKeys.length; ++i) { 1282 for (var i = 0; i < this.sortedGroupKeys_.length; ++i) {
1261 var groupKeyString = groupKeys[i]; 1283 var groupData = this.groupedData_[this.sortedGroupKeys_[i]];
1262 var groupData = groupedData[groupKeyString]; 1284 drawGroup(parent, groupData, columns,
1263 var groupKey = JSON.parse(groupKeyString);
1264
1265 drawGroup(parent, groupKey, groupData, columns,
1266 columnOnClickHandler, this.currentSortKeys_); 1285 columnOnClickHandler, this.currentSortKeys_);
1267 } 1286 }
1268 }, 1287 },
1269 1288
1270 init_: function() { 1289 init_: function() {
1271 this.allData_ = []; 1290 // Data goes through the following pipeline:
1291 // (1) Raw data received from browser, and transformed into our own
1292 // internal row format (where properties are indexed by KEY_*
1293 // constants.)
1294 // (2) We "augment" each row by adding some extra computed columns
1295 // (like averages).
1296 // (3) The rows are merged using current merge settings.
1297 // (4) The rows that don't match current search expression are
1298 // tossed out.
1299 // (5) The rows are organized into "groups" based on current settings,
1300 // and aggregate values are computed for each resulting group.
1301 // (6) The rows within each group are sorted using current settings.
1302 // (7) The grouped rows are drawn to the screen.
1303 this.flatData_ = [];
1304 this.mergedData_ = [];
1305 this.filteredData_ = [];
1306 this.groupedData_ = {};
1307 this.sortedGroupKeys_ = [];
1308
1272 this.fillSelectionCheckboxes_($(COLUMN_TOGGLES_CONTAINER_ID)); 1309 this.fillSelectionCheckboxes_($(COLUMN_TOGGLES_CONTAINER_ID));
1273 this.fillMergeCheckboxes_($(COLUMN_MERGE_TOGGLES_CONTAINER_ID)); 1310 this.fillMergeCheckboxes_($(COLUMN_MERGE_TOGGLES_CONTAINER_ID));
1274 1311
1275 $(FILTER_SEARCH_ID).onsearch = this.onChangedFilter_.bind(this); 1312 $(FILTER_SEARCH_ID).onsearch = this.onChangedFilter_.bind(this);
1276 1313
1277 this.currentSortKeys_ = INITIAL_SORT_KEYS.slice(0); 1314 this.currentSortKeys_ = INITIAL_SORT_KEYS.slice(0);
1278 this.currentGroupingKeys_ = INITIAL_GROUP_KEYS.slice(0); 1315 this.currentGroupingKeys_ = INITIAL_GROUP_KEYS.slice(0);
1279 1316
1280 this.fillGroupingDropdowns_(); 1317 this.fillGroupingDropdowns_();
1281 this.fillSortingDropdowns_(); 1318 this.fillSortingDropdowns_();
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
1378 if (i < this.currentSortKeys_.length) { 1415 if (i < this.currentSortKeys_.length) {
1379 var key = this.currentSortKeys_[i]; 1416 var key = this.currentSortKeys_[i];
1380 setSelectedOptionByValue(select, key); 1417 setSelectedOptionByValue(select, key);
1381 } 1418 }
1382 } 1419 }
1383 }, 1420 },
1384 1421
1385 onChangedGrouping_: function(select, i) { 1422 onChangedGrouping_: function(select, i) {
1386 updateKeyListFromDropdown(this.currentGroupingKeys_, i, select); 1423 updateKeyListFromDropdown(this.currentGroupingKeys_, i, select);
1387 this.fillGroupingDropdowns_(); 1424 this.fillGroupingDropdowns_();
1388 this.redrawData_(); 1425 this.updateGroupedData_();
1389 }, 1426 },
1390 1427
1391 onChangedSorting_: function(select, i) { 1428 onChangedSorting_: function(select, i) {
1392 updateKeyListFromDropdown(this.currentSortKeys_, i, select); 1429 updateKeyListFromDropdown(this.currentSortKeys_, i, select);
1393 this.fillSortingDropdowns_(); 1430 this.fillSortingDropdowns_();
1394 this.redrawData_(); 1431 this.sortGroupedData_();
1395 }, 1432 },
1396 1433
1397 onSelectCheckboxChanged_: function() { 1434 onSelectCheckboxChanged_: function() {
1398 this.redrawData_(); 1435 this.redrawData_();
1399 }, 1436 },
1400 1437
1401 onMergeCheckboxChanged_: function() { 1438 onMergeCheckboxChanged_: function() {
1402 this.redrawData_(); 1439 this.updateMergedData_();
1403 }, 1440 },
1404 1441
1405 onMergeSimilarThreadsCheckboxChanged_: function() { 1442 onMergeSimilarThreadsCheckboxChanged_: function() {
1406 this.redrawData_(); 1443 this.updateMergedData_();
1407 }, 1444 },
1408 1445
1409 onChangedFilter_: function() { 1446 onChangedFilter_: function() {
1410 this.redrawData_(); 1447 this.updateFilteredData_();
1411 }, 1448 },
1412 1449
1413 /** 1450 /**
1414 * When left-clicking a column, change the primary sort order to that 1451 * When left-clicking a column, change the primary sort order to that
1415 * column. If we were already sorted on that column then reverse the order. 1452 * column. If we were already sorted on that column then reverse the order.
1416 * 1453 *
1417 * When alt-clicking, add a secondary sort column. Similarly, if 1454 * When alt-clicking, add a secondary sort column. Similarly, if
1418 * alt-clicking a column which was already being sorted on, reverse its 1455 * alt-clicking a column which was already being sorted on, reverse its
1419 * order. 1456 * order.
1420 */ 1457 */
(...skipping 28 matching lines...) Expand all
1449 // make it so. 1486 // make it so.
1450 this.currentSortKeys_ = [key]; 1487 this.currentSortKeys_ = [key];
1451 } else { 1488 } else {
1452 // If the column we left-clicked was already our primary column (and 1489 // If the column we left-clicked was already our primary column (and
1453 // we just reversed it), remove any secondary sorts. 1490 // we just reversed it), remove any secondary sorts.
1454 this.currentSortKeys_.length = 1; 1491 this.currentSortKeys_.length = 1;
1455 } 1492 }
1456 } 1493 }
1457 1494
1458 this.fillSortingDropdowns_(); 1495 this.fillSortingDropdowns_();
1459 this.redrawData_(); 1496 this.sortGroupedData_();
1460 }, 1497 },
1461 1498
1462 getSortingFunction_: function() { 1499 getSortingFunction_: function() {
1463 var sortKeys = this.currentSortKeys_.slice(0); 1500 var sortKeys = this.currentSortKeys_.slice(0);
1464 1501
1465 // Eliminate the empty string keys (which means they were unspecified). 1502 // Eliminate the empty string keys (which means they were unspecified).
1466 deleteValuesFromArray(sortKeys, ['']); 1503 deleteValuesFromArray(sortKeys, ['']);
1467 1504
1468 // If no sort is specified, use our default sort. 1505 // If no sort is specified, use our default sort.
1469 if (sortKeys.length == 0) 1506 if (sortKeys.length == 0)
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
1552 groupKey.push(entry); 1589 groupKey.push(entry);
1553 } 1590 }
1554 1591
1555 return JSON.stringify(groupKey); 1592 return JSON.stringify(groupKey);
1556 }; 1593 };
1557 }, 1594 },
1558 }; 1595 };
1559 1596
1560 return MainView; 1597 return MainView;
1561 })(); 1598 })();
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698