OLD | NEW |
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): The handling of "max" across snapshots is not correct. | 8 // TODO(eroman): The handling of "max" across snapshots is not correct. |
9 // For starters the browser needs to be aware to generate new maximums. | 9 // For starters the browser needs to be aware to generate new maximums. |
10 // Secondly, we need to take into account the "max" of intermediary snapshots, | 10 // Secondly, we need to take into account the "max" of intermediary snapshots, |
(...skipping 848 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
859 } | 859 } |
860 | 860 |
861 /** | 861 /** |
862 * Merges the rows in |origRows|, by collapsing the columns listed in | 862 * Merges the rows in |origRows|, by collapsing the columns listed in |
863 * |mergeKeys|. Returns an array with the merged rows (in no particular | 863 * |mergeKeys|. Returns an array with the merged rows (in no particular |
864 * order). | 864 * order). |
865 * | 865 * |
866 * If |mergeSimilarThreads| is true, then threads with a similar name will be | 866 * If |mergeSimilarThreads| is true, then threads with a similar name will be |
867 * considered equivalent. For instance, "WorkerThread-1" and "WorkerThread-2" | 867 * considered equivalent. For instance, "WorkerThread-1" and "WorkerThread-2" |
868 * will be remapped to "WorkerThread-*". | 868 * will be remapped to "WorkerThread-*". |
| 869 * |
| 870 * If |outputAsDictionary| is false then the merged rows will be returned as a |
| 871 * flat list. Otherwise the result will be a dictionary, where each row |
| 872 * has a unique key. |
869 */ | 873 */ |
870 function mergeRows(origRows, mergeKeys, mergeSimilarThreads) { | 874 function mergeRows(origRows, mergeKeys, mergeSimilarThreads, |
| 875 outputAsDictionary) { |
871 // Define a translation function for each property. Normally we copy over | 876 // Define a translation function for each property. Normally we copy over |
872 // properties as-is, but if we have been asked to "merge similar threads" we | 877 // properties as-is, but if we have been asked to "merge similar threads" we |
873 // we will remap the thread names that end in a numeric suffix. | 878 // we will remap the thread names that end in a numeric suffix. |
874 var propertyGetterFunc; | 879 var propertyGetterFunc; |
875 | 880 |
876 if (mergeSimilarThreads) { | 881 if (mergeSimilarThreads) { |
877 propertyGetterFunc = function(row, key) { | 882 propertyGetterFunc = function(row, key) { |
878 var value = row[key]; | 883 var value = row[key]; |
879 // If the property is a thread name, try to remap it. | 884 // If the property is a thread name, try to remap it. |
880 if (key == KEY_BIRTH_THREAD || key == KEY_DEATH_THREAD) { | 885 if (key == KEY_BIRTH_THREAD || key == KEY_DEATH_THREAD) { |
881 var m = /^(.*[^\d])(\d+)$/.exec(value); | 886 var m = /^(.*[^\d])(\d+)$/.exec(value); |
882 if (m) | 887 if (m) |
883 value = m[1] + '*'; | 888 value = m[1] + '*'; |
884 } | 889 } |
885 return value; | 890 return value; |
886 } | 891 } |
887 } else { | 892 } else { |
888 propertyGetterFunc = function(row, key) { return row[key]; }; | 893 propertyGetterFunc = function(row, key) { return row[key]; }; |
889 } | 894 } |
890 | 895 |
891 // Determine which sets of properties a row needs to match on to be | 896 // Determine which sets of properties a row needs to match on to be |
892 // considered identical to another row. | 897 // considered identical to another row. |
893 var identityKeys = IDENTITY_KEYS.slice(0); | 898 var identityKeys = IDENTITY_KEYS.slice(0); |
894 deleteValuesFromArray(identityKeys, mergeKeys); | 899 deleteValuesFromArray(identityKeys, mergeKeys); |
895 | 900 |
896 // Set |aggregateKeys| to everything else, since we will be aggregating | 901 // Set |aggregateKeys| to everything else, since we will be aggregating |
897 // their value as part of the merge. | 902 // their value as part of the merge. |
898 var aggregateKeys = ALL_KEYS.slice(0); | 903 var aggregateKeys = ALL_KEYS.slice(0); |
899 deleteValuesFromArray(aggregateKeys, IDENTITY_KEYS); | 904 deleteValuesFromArray(aggregateKeys, IDENTITY_KEYS); |
| 905 deleteValuesFromArray(aggregateKeys, mergeKeys); |
900 | 906 |
901 // Group all the identical rows together, bucketed into |identicalRows|. | 907 // Group all the identical rows together, bucketed into |identicalRows|. |
902 var identicalRows = | 908 var identicalRows = |
903 bucketIdenticalRows(origRows, identityKeys, propertyGetterFunc); | 909 bucketIdenticalRows(origRows, identityKeys, propertyGetterFunc); |
904 | 910 |
905 var mergedRows = []; | 911 var mergedRows = outputAsDictionary ? {} : []; |
906 | 912 |
907 // Merge the rows and save the results to |mergedRows|. | 913 // Merge the rows and save the results to |mergedRows|. |
908 for (var k in identicalRows) { | 914 for (var k in identicalRows) { |
909 // We need to smash the list |l| down to a single row... | 915 // We need to smash the list |l| down to a single row... |
910 var l = identicalRows[k]; | 916 var l = identicalRows[k]; |
911 | 917 |
912 var newRow = []; | 918 var newRow = []; |
913 mergedRows.push(newRow); | 919 |
| 920 if (outputAsDictionary) { |
| 921 mergedRows[k] = newRow; |
| 922 } else { |
| 923 mergedRows.push(newRow); |
| 924 } |
914 | 925 |
915 // Copy over all the identity columns to the new row (since they | 926 // Copy over all the identity columns to the new row (since they |
916 // were the same for each row matched). | 927 // were the same for each row matched). |
917 for (var i = 0; i < identityKeys.length; ++i) | 928 for (var i = 0; i < identityKeys.length; ++i) |
918 newRow[identityKeys[i]] = propertyGetterFunc(l[0], identityKeys[i]); | 929 newRow[identityKeys[i]] = propertyGetterFunc(l[0], identityKeys[i]); |
919 | 930 |
920 // Compute aggregates for the other columns. | 931 // Compute aggregates for the other columns. |
921 var aggregates = initializeAggregates(aggregateKeys); | 932 var aggregates = initializeAggregates(aggregateKeys); |
922 | 933 |
923 // Feed the rows to the aggregators. | 934 // Feed the rows to the aggregators. |
924 for (var i = 0; i < l.length; ++i) | 935 for (var i = 0; i < l.length; ++i) |
925 consumeAggregates(aggregates, l[i]); | 936 consumeAggregates(aggregates, l[i]); |
926 | 937 |
927 // Suck out the data generated by the aggregators. | 938 // Suck out the data generated by the aggregators. |
928 for (var aggregateKey in aggregates) | 939 for (var aggregateKey in aggregates) |
929 newRow[aggregateKey] = aggregates[aggregateKey].getValue(); | 940 newRow[aggregateKey] = aggregates[aggregateKey].getValue(); |
930 } | 941 } |
931 | 942 |
932 return mergedRows; | 943 return mergedRows; |
933 } | 944 } |
934 | 945 |
935 /** | 946 /** |
936 * Takes two flat lists data1 and data2, and returns a new flat list which | 947 * Takes two dictionaries data1 and data2, and returns a new flat list which |
937 * represents the difference between them. The exact meaning of "difference" | 948 * represents the difference between them. The exact meaning of "difference" |
938 * is column specific, but for most numeric fields (like the count, or total | 949 * is column specific, but for most numeric fields (like the count, or total |
939 * time), it is found by subtracting. | 950 * time), it is found by subtracting. |
940 * | 951 * |
941 * TODO(eroman): Some of this code is duplicated from mergeRows(). | 952 * Rows in data1 and data2 are expected to use the same scheme for the keys. |
| 953 * In other words, data1[k] is considered the analagous row to data2[k]. |
942 */ | 954 */ |
943 function subtractSnapshots(data1, data2) { | 955 function subtractSnapshots(data1, data2, columnsToExclude) { |
944 // These columns are computed from the other columns. We won't bother | 956 // These columns are computed from the other columns. We won't bother |
945 // diffing/aggregating these, but rather will derive them again from the | 957 // diffing/aggregating these, but rather will derive them again from the |
946 // final row. | 958 // final row. |
947 var COMPUTED_AGGREGATE_KEYS = [KEY_AVG_QUEUE_TIME, KEY_AVG_RUN_TIME]; | 959 var COMPUTED_AGGREGATE_KEYS = [KEY_AVG_QUEUE_TIME, KEY_AVG_RUN_TIME]; |
948 | 960 |
949 // These are the keys which determine row equality. Since we are not doing | 961 // These are the keys which determine row equality. Since we are not doing |
950 // any merging yet at this point, it is simply the list of all identity | 962 // any merging yet at this point, it is simply the list of all identity |
951 // columns. | 963 // columns. |
952 var identityKeys = IDENTITY_KEYS; | 964 var identityKeys = IDENTITY_KEYS.slice(0); |
| 965 deleteValuesFromArray(identityKeys, columnsToExclude); |
953 | 966 |
954 // The columns to compute via aggregation is everything else. | 967 // The columns to compute via aggregation is everything else. |
955 var aggregateKeys = ALL_KEYS.slice(0); | 968 var aggregateKeys = ALL_KEYS.slice(0); |
956 deleteValuesFromArray(aggregateKeys, IDENTITY_KEYS); | 969 deleteValuesFromArray(aggregateKeys, IDENTITY_KEYS); |
957 deleteValuesFromArray(aggregateKeys, COMPUTED_AGGREGATE_KEYS); | 970 deleteValuesFromArray(aggregateKeys, COMPUTED_AGGREGATE_KEYS); |
958 | 971 deleteValuesFromArray(aggregateKeys, columnsToExclude); |
959 // Group all the identical rows for each list together. | |
960 var propertyGetterFunc = function(row, key) { return row[key]; }; | |
961 var identicalRows1 = | |
962 bucketIdenticalRows(data1, identityKeys, propertyGetterFunc); | |
963 var identicalRows2 = | |
964 bucketIdenticalRows(data2, identityKeys, propertyGetterFunc); | |
965 | 972 |
966 var diffedRows = []; | 973 var diffedRows = []; |
967 | 974 |
968 for (var k in identicalRows2) { | 975 for (var rowId in data2) { |
969 var rows2 = identicalRows2[k]; | 976 var row1 = data1[rowId]; |
970 var rows1 = identicalRows1[k]; | 977 var row2 = data2[rowId]; |
971 if (rows1 == undefined) | |
972 rows1 = []; | |
973 | 978 |
974 var newRow = []; | 979 var newRow = []; |
975 | 980 |
976 // Copy over all the identity columns to the new row (since they | 981 // Copy over all the identity columns to the new row (since they |
977 // were the same for each row matched). | 982 // were the same for each row matched). |
978 for (var i = 0; i < identityKeys.length; ++i) | 983 for (var i = 0; i < identityKeys.length; ++i) |
979 newRow[identityKeys[i]] = propertyGetterFunc(rows2[0], identityKeys[i]); | 984 newRow[identityKeys[i]] = row2[identityKeys[i]]; |
980 | 985 |
981 // The raw data for each snapshot *may* have contained duplicate rows, so | 986 // Diff the two rows. |
982 // smash them down into a single row using our aggregation functions. | 987 if (row1) { |
983 var aggregates1 = initializeAggregates(aggregateKeys); | 988 for (var i = 0; i < aggregateKeys.length; ++i) { |
984 var aggregates2 = initializeAggregates(aggregateKeys); | 989 var aggregateKey = aggregateKeys[i]; |
985 for (var i = 0; i < rows1.length; ++i) | 990 var a = row1[aggregateKey]; |
986 consumeAggregates(aggregates1, rows1[i]); | 991 var b = row2[aggregateKey]; |
987 for (var i = 0; i < rows2.length; ++i) | |
988 consumeAggregates(aggregates2, rows2[i]); | |
989 | 992 |
990 // Finally, diff the two merged rows. | 993 var diffFunc = KEY_PROPERTIES[aggregateKey].diff; |
991 for (var aggregateKey in aggregates2) { | 994 newRow[aggregateKey] = diffFunc(a, b); |
992 var a = aggregates1[aggregateKey].getValue(); | 995 } |
993 var b = aggregates2[aggregateKey].getValue(); | 996 } else { |
994 | 997 // If the the row doesn't appear in snapshot1, then there is nothing to |
995 var diffFunc = KEY_PROPERTIES[aggregateKey].diff; | 998 // diff, so just copy row2 as is. |
996 newRow[aggregateKey] = diffFunc(a, b); | 999 for (var i = 0; i < aggregateKeys.length; ++i) { |
| 1000 var aggregateKey = aggregateKeys[i]; |
| 1001 newRow[aggregateKey] = row2[aggregateKey]; |
| 1002 } |
997 } | 1003 } |
998 | 1004 |
999 if (newRow[KEY_COUNT] == 0) { | 1005 if (newRow[KEY_COUNT] == 0) { |
1000 // If a row's count has gone to zero, it means there were no new | 1006 // If a row's count has gone to zero, it means there were no new |
1001 // occurrences of it in the second snapshot, so remove it. | 1007 // occurrences of it in the second snapshot, so remove it. |
1002 continue; | 1008 continue; |
1003 } | 1009 } |
1004 | 1010 |
1005 // Since we excluded the averages during diffing phase, re-compute them | 1011 // Since we excluded the averages during the diffing phase, re-compute |
1006 // using the diffed totals. | 1012 // them using the diffed totals. |
1007 computeDataRowAverages(newRow); | 1013 computeDataRowAverages(newRow); |
1008 diffedRows.push(newRow); | 1014 diffedRows.push(newRow); |
1009 } | 1015 } |
1010 | 1016 |
1011 return diffedRows; | 1017 return diffedRows; |
1012 } | 1018 } |
1013 | 1019 |
1014 // -------------------------------------------------------------------------- | 1020 // -------------------------------------------------------------------------- |
1015 // HTML drawing code | 1021 // HTML drawing code |
1016 // -------------------------------------------------------------------------- | 1022 // -------------------------------------------------------------------------- |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1232 | 1238 |
1233 if (!arrayToSet(this.getSelectedSnapshotIndexes_())[snapshotIndex]) { | 1239 if (!arrayToSet(this.getSelectedSnapshotIndexes_())[snapshotIndex]) { |
1234 // Optimization: If this snapshot is not a data dependency for the | 1240 // Optimization: If this snapshot is not a data dependency for the |
1235 // current display, then don't bother updating anything. | 1241 // current display, then don't bother updating anything. |
1236 return; | 1242 return; |
1237 } | 1243 } |
1238 | 1244 |
1239 // We may end up calling addDataToSnapshot_() repeatedly (once for each | 1245 // We may end up calling addDataToSnapshot_() repeatedly (once for each |
1240 // process). To avoid this from slowing us down we do bulk updates on a | 1246 // process). To avoid this from slowing us down we do bulk updates on a |
1241 // timer. | 1247 // timer. |
1242 this.updateFlatDataSoon_(); | 1248 this.updateMergedDataSoon_(); |
1243 }, | 1249 }, |
1244 | 1250 |
1245 updateFlatDataSoon_: function() { | 1251 updateMergedDataSoon_: function() { |
1246 if (this.updateFlatDataPending_) { | 1252 if (this.updateMergedDataPending_) { |
1247 // If a delayed task has already been posted to re-merge the data, | 1253 // If a delayed task has already been posted to re-merge the data, |
1248 // then we don't need to do anything extra. | 1254 // then we don't need to do anything extra. |
1249 return; | 1255 return; |
1250 } | 1256 } |
1251 | 1257 |
1252 // Otherwise schedule updateFlatData_() to be called later. We want it to | 1258 // Otherwise schedule updateMergedData_() to be called later. We want it |
1253 // be called no more than once every PROCESS_DATA_DELAY_MS milliseconds. | 1259 // to be called no more than once every PROCESS_DATA_DELAY_MS |
| 1260 // milliseconds. |
1254 | 1261 |
1255 if (this.lastUpdateFlatDataTime_ == undefined) | 1262 if (this.lastUpdateMergedDataTime_ == undefined) |
1256 this.lastUpdateFlatDataTime_ = 0; | 1263 this.lastUpdateMergedDataTime_ = 0; |
1257 | 1264 |
1258 var timeSinceLastMerge = getTimeMillis() - this.lastUpdateFlatDataTime_; | 1265 var timeSinceLastMerge = getTimeMillis() - this.lastUpdateMergedDataTime_; |
1259 var timeToWait = Math.max(0, PROCESS_DATA_DELAY_MS - timeSinceLastMerge); | 1266 var timeToWait = Math.max(0, PROCESS_DATA_DELAY_MS - timeSinceLastMerge); |
1260 | 1267 |
1261 var functionToRun = function() { | 1268 var functionToRun = function() { |
1262 // Do the actual update. | 1269 // Do the actual update. |
1263 this.updateFlatData_(); | 1270 this.updateMergedData_(); |
1264 // Keep track of when we last ran. | 1271 // Keep track of when we last ran. |
1265 this.lastUpdateFlatDataTime_ = getTimeMillis(); | 1272 this.lastUpdateMergedDataTime_ = getTimeMillis(); |
1266 this.updateFlatDataPending_ = false; | 1273 this.updateMergedDataPending_ = false; |
1267 }.bind(this); | 1274 }.bind(this); |
1268 | 1275 |
1269 this.updateFlatDataPending_ = true; | 1276 this.updateMergedDataPending_ = true; |
1270 window.setTimeout(functionToRun, timeToWait); | 1277 window.setTimeout(functionToRun, timeToWait); |
1271 }, | 1278 }, |
1272 | 1279 |
1273 /** | 1280 /** |
1274 * Returns a list of the currently selected snapshots. This list is | 1281 * Returns a list of the currently selected snapshots. This list is |
1275 * guaranteed to be of length 1 or 2. | 1282 * guaranteed to be of length 1 or 2. |
1276 */ | 1283 */ |
1277 getSelectedSnapshotIndexes_: function() { | 1284 getSelectedSnapshotIndexes_: function() { |
1278 var indexes = this.getSelectedSnapshotBoxes_(); | 1285 var indexes = this.getSelectedSnapshotBoxes_(); |
1279 for (var i = 0; i < indexes.length; ++i) | 1286 for (var i = 0; i < indexes.length; ++i) |
(...skipping 10 matching lines...) Expand all Loading... |
1290 var boxes = []; | 1297 var boxes = []; |
1291 for (var i = 0; i < this.snapshots_.length; ++i) { | 1298 for (var i = 0; i < this.snapshots_.length; ++i) { |
1292 var box = this.getSnapshotCheckbox_(i); | 1299 var box = this.getSnapshotCheckbox_(i); |
1293 if (box.checked) | 1300 if (box.checked) |
1294 boxes.push(box); | 1301 boxes.push(box); |
1295 } | 1302 } |
1296 return boxes; | 1303 return boxes; |
1297 }, | 1304 }, |
1298 | 1305 |
1299 /** | 1306 /** |
1300 * This function should be called any time a snapshot dependency for what is | 1307 * Re-draw the description which explains which snapshots are currently |
1301 * being displayed on the screen has changed. It will re-calculate the | 1308 * selected (if two snapshots were selected we explain that the *difference* |
1302 * difference between the two snapshots and update flatData_. | 1309 * between them is being displayed). |
1303 */ | 1310 */ |
1304 updateFlatData_: function() { | 1311 updateSnapshotSelectionSummaryDiv_: function() { |
1305 var summaryDiv = $(SNAPSHOT_SELECTION_SUMMARY_ID); | 1312 var summaryDiv = $(SNAPSHOT_SELECTION_SUMMARY_ID); |
1306 | 1313 |
1307 var selectedSnapshots = this.getSelectedSnapshotIndexes_(); | 1314 var selectedSnapshots = this.getSelectedSnapshotIndexes_(); |
1308 if (selectedSnapshots.length == 1) { | 1315 if (selectedSnapshots.length == 1) { |
1309 // If only one snapshot is chosen then we will display that snapshot's | |
1310 // data in its entirety. | |
1311 this.flatData_ = this.snapshots_[selectedSnapshots[0]].flatData; | |
1312 | |
1313 // Don't bother displaying any text when just 1 snapshot is selected, | 1316 // Don't bother displaying any text when just 1 snapshot is selected, |
1314 // since it is obvious what this should do. | 1317 // since it is obvious what this should do. |
1315 summaryDiv.innerText = ''; | 1318 summaryDiv.innerText = ''; |
1316 } else if (selectedSnapshots.length == 2) { | 1319 } else if (selectedSnapshots.length == 2) { |
1317 // Otherwise if two snapshots were chosen, show the difference between | 1320 // Otherwise if two snapshots were chosen, show the difference between |
1318 // them. | 1321 // them. |
1319 var snapshot1 = this.snapshots_[selectedSnapshots[0]]; | 1322 var snapshot1 = this.snapshots_[selectedSnapshots[0]]; |
1320 var snapshot2 = this.snapshots_[selectedSnapshots[1]]; | 1323 var snapshot2 = this.snapshots_[selectedSnapshots[1]]; |
1321 | 1324 |
1322 this.flatData_ = | |
1323 subtractSnapshots(snapshot1.flatData, snapshot2.flatData); | |
1324 | |
1325 var timeDeltaInSeconds = | 1325 var timeDeltaInSeconds = |
1326 ((snapshot2.time - snapshot1.time) / 1000).toFixed(0); | 1326 ((snapshot2.time - snapshot1.time) / 1000).toFixed(0); |
1327 | 1327 |
1328 // Explain that what is being shown is the difference between two | 1328 // Explain that what is being shown is the difference between two |
1329 // snapshots. | 1329 // snapshots. |
1330 summaryDiv.innerText = | 1330 summaryDiv.innerText = |
1331 'Showing the difference between snapshots #' + | 1331 'Showing the difference between snapshots #' + |
1332 selectedSnapshots[0] + ' and #' + | 1332 selectedSnapshots[0] + ' and #' + |
1333 selectedSnapshots[1] + ' (' + timeDeltaInSeconds + | 1333 selectedSnapshots[1] + ' (' + timeDeltaInSeconds + |
1334 ' seconds worth of data)'; | 1334 ' seconds worth of data)'; |
1335 } else { | 1335 } else { |
1336 // This shouldn't be possible... | 1336 // This shouldn't be possible... |
1337 throw 'Unexpected number of selected snapshots'; | 1337 throw 'Unexpected number of selected snapshots'; |
1338 } | 1338 } |
1339 | |
1340 // Recompute mergedData_ (since it is derived from flatData_) | |
1341 this.updateMergedData_(); | |
1342 }, | 1339 }, |
1343 | 1340 |
1344 updateMergedData_: function() { | 1341 updateMergedData_: function() { |
1345 // Recompute mergedData_. | 1342 // Retrieve the merge options. |
1346 this.mergedData_ = mergeRows(this.flatData_, | 1343 var mergeColumns = this.getMergeColumns_(); |
1347 this.getMergeColumns_(), | 1344 var shouldMergeSimilarThreads = this.shouldMergeSimilarThreads_(); |
1348 this.shouldMergeSimilarThreads_()); | 1345 |
| 1346 var selectedSnapshots = this.getSelectedSnapshotIndexes_(); |
| 1347 |
| 1348 // We do merges a bit differently depending if we are displaying the diffs |
| 1349 // between two snapshots, or just displaying a single snapshot. |
| 1350 if (selectedSnapshots.length == 1) { |
| 1351 var snapshot = this.snapshots_[selectedSnapshots[0]]; |
| 1352 this.mergedData_ = mergeRows(snapshot.flatData, |
| 1353 mergeColumns, |
| 1354 shouldMergeSimilarThreads, |
| 1355 false); |
| 1356 |
| 1357 } else if (selectedSnapshots.length == 2) { |
| 1358 var snapshot1 = this.snapshots_[selectedSnapshots[0]]; |
| 1359 var snapshot2 = this.snapshots_[selectedSnapshots[1]]; |
| 1360 |
| 1361 // Merge the data for snapshot1. |
| 1362 var mergedRows1 = mergeRows(snapshot1.flatData, |
| 1363 mergeColumns, |
| 1364 shouldMergeSimilarThreads, |
| 1365 true); |
| 1366 |
| 1367 // Merge the data for snapshot2. |
| 1368 var mergedRows2 = mergeRows(snapshot2.flatData, |
| 1369 mergeColumns, |
| 1370 shouldMergeSimilarThreads, |
| 1371 true); |
| 1372 |
| 1373 // Do a diff between the two snapshots. |
| 1374 this.mergedData_ = subtractSnapshots(mergedRows1, |
| 1375 mergedRows2, |
| 1376 mergeColumns); |
| 1377 } else { |
| 1378 throw 'Unexpected number of selected snapshots'; |
| 1379 } |
1349 | 1380 |
1350 // Recompute filteredData_ (since it is derived from mergedData_) | 1381 // Recompute filteredData_ (since it is derived from mergedData_) |
1351 this.updateFilteredData_(); | 1382 this.updateFilteredData_(); |
1352 }, | 1383 }, |
1353 | 1384 |
1354 updateFilteredData_: function() { | 1385 updateFilteredData_: function() { |
1355 // Recompute filteredData_. | 1386 // Recompute filteredData_. |
1356 this.filteredData_ = []; | 1387 this.filteredData_ = []; |
1357 var filterFunc = this.getFilterFunction_(); | 1388 var filterFunc = this.getFilterFunction_(); |
1358 for (var i = 0; i < this.mergedData_.length; ++i) { | 1389 for (var i = 0; i < this.mergedData_.length; ++i) { |
(...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1670 // constants.) | 1701 // constants.) |
1671 // (2) We "augment" each row by adding some extra computed columns | 1702 // (2) We "augment" each row by adding some extra computed columns |
1672 // (like averages). | 1703 // (like averages). |
1673 // (3) The rows are merged using current merge settings. | 1704 // (3) The rows are merged using current merge settings. |
1674 // (4) The rows that don't match current search expression are | 1705 // (4) The rows that don't match current search expression are |
1675 // tossed out. | 1706 // tossed out. |
1676 // (5) The rows are organized into "groups" based on current settings, | 1707 // (5) The rows are organized into "groups" based on current settings, |
1677 // and aggregate values are computed for each resulting group. | 1708 // and aggregate values are computed for each resulting group. |
1678 // (6) The rows within each group are sorted using current settings. | 1709 // (6) The rows within each group are sorted using current settings. |
1679 // (7) The grouped rows are drawn to the screen. | 1710 // (7) The grouped rows are drawn to the screen. |
1680 this.flatData_ = []; | |
1681 this.mergedData_ = []; | 1711 this.mergedData_ = []; |
1682 this.filteredData_ = []; | 1712 this.filteredData_ = []; |
1683 this.groupedData_ = {}; | 1713 this.groupedData_ = {}; |
1684 this.sortedGroupKeys_ = []; | 1714 this.sortedGroupKeys_ = []; |
1685 | 1715 |
1686 this.groupDisplaySettings_ = {}; | 1716 this.groupDisplaySettings_ = {}; |
1687 | 1717 |
1688 this.fillSelectionCheckboxes_($(COLUMN_TOGGLES_CONTAINER_ID)); | 1718 this.fillSelectionCheckboxes_($(COLUMN_TOGGLES_CONTAINER_ID)); |
1689 this.fillMergeCheckboxes_($(COLUMN_MERGE_TOGGLES_CONTAINER_ID)); | 1719 this.fillMergeCheckboxes_($(COLUMN_MERGE_TOGGLES_CONTAINER_ID)); |
1690 | 1720 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1786 checked[i].checked = false; | 1816 checked[i].checked = false; |
1787 checked.length = 2; | 1817 checked.length = 2; |
1788 } | 1818 } |
1789 | 1819 |
1790 // We should always have at least 1 selection. Prevent the user from | 1820 // We should always have at least 1 selection. Prevent the user from |
1791 // unselecting the final box. | 1821 // unselecting the final box. |
1792 if (checked.length == 0) | 1822 if (checked.length == 0) |
1793 event.target.checked = true; | 1823 event.target.checked = true; |
1794 | 1824 |
1795 this.updateSnapshotCheckboxStyling_(); | 1825 this.updateSnapshotCheckboxStyling_(); |
| 1826 this.updateSnapshotSelectionSummaryDiv_(); |
1796 | 1827 |
1797 // Recompute flatData_ (since it is derived from selected snapshots). | 1828 // Recompute mergedData_ (since it is derived from selected snapshots). |
1798 this.updateFlatData_(); | 1829 this.updateMergedData_(); |
1799 }, | 1830 }, |
1800 | 1831 |
1801 fillSelectionCheckboxes_: function(parent) { | 1832 fillSelectionCheckboxes_: function(parent) { |
1802 this.selectionCheckboxes_ = {}; | 1833 this.selectionCheckboxes_ = {}; |
1803 | 1834 |
1804 var onChangeFunc = this.onSelectCheckboxChanged_.bind(this); | 1835 var onChangeFunc = this.onSelectCheckboxChanged_.bind(this); |
1805 | 1836 |
1806 for (var i = 0; i < ALL_TABLE_COLUMNS.length; ++i) { | 1837 for (var i = 0; i < ALL_TABLE_COLUMNS.length; ++i) { |
1807 var key = ALL_TABLE_COLUMNS[i]; | 1838 var key = ALL_TABLE_COLUMNS[i]; |
1808 var checkbox = addLabeledCheckbox(parent, getNameForKey(key)); | 1839 var checkbox = addLabeledCheckbox(parent, getNameForKey(key)); |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2053 groupKey.push(entry); | 2084 groupKey.push(entry); |
2054 } | 2085 } |
2055 | 2086 |
2056 return JSON.stringify(groupKey); | 2087 return JSON.stringify(groupKey); |
2057 }; | 2088 }; |
2058 }, | 2089 }, |
2059 }; | 2090 }; |
2060 | 2091 |
2061 return MainView; | 2092 return MainView; |
2062 })(); | 2093 })(); |
OLD | NEW |