| 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 |