| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 12 matching lines...) Expand all Loading... |
| 23 /** | 23 /** |
| 24 * This class provides a "bridge" for communicating between the javascript and | 24 * This class provides a "bridge" for communicating between the javascript and |
| 25 * the browser. Used as a singleton. | 25 * the browser. Used as a singleton. |
| 26 */ | 26 */ |
| 27 var BrowserBridge = (function() { | 27 var BrowserBridge = (function() { |
| 28 'use strict'; | 28 'use strict'; |
| 29 | 29 |
| 30 /** | 30 /** |
| 31 * @constructor | 31 * @constructor |
| 32 */ | 32 */ |
| 33 function BrowserBridge() { | 33 function BrowserBridge() {} |
| 34 } | |
| 35 | 34 |
| 36 BrowserBridge.prototype = { | 35 BrowserBridge.prototype = { |
| 37 //-------------------------------------------------------------------------- | 36 //-------------------------------------------------------------------------- |
| 38 // Messages sent to the browser | 37 // Messages sent to the browser |
| 39 //-------------------------------------------------------------------------- | 38 //-------------------------------------------------------------------------- |
| 40 | 39 |
| 41 sendGetData: function() { | 40 sendGetData: function() { |
| 42 chrome.send('getData'); | 41 chrome.send('getData'); |
| 43 }, | 42 }, |
| 44 | 43 |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 175 consume: function(e) { | 174 consume: function(e) { |
| 176 this.valuesSet_[e[this.key_]] = true; | 175 this.valuesSet_[e[this.key_]] = true; |
| 177 }, | 176 }, |
| 178 | 177 |
| 179 getValueAsText: function() { | 178 getValueAsText: function() { |
| 180 return getDictionaryKeys(this.valuesSet_).length + ' unique'; | 179 return getDictionaryKeys(this.valuesSet_).length + ' unique'; |
| 181 }, | 180 }, |
| 182 }; | 181 }; |
| 183 | 182 |
| 184 return { | 183 return { |
| 185 create: function(key) { return new Aggregator(key); } | 184 create: function(key) { |
| 185 return new Aggregator(key); |
| 186 } |
| 186 }; | 187 }; |
| 187 })(); | 188 })(); |
| 188 | 189 |
| 189 /** | 190 /** |
| 190 * This aggregator sums a numeric field. | 191 * This aggregator sums a numeric field. |
| 191 */ | 192 */ |
| 192 var SumAggregator = (function() { | 193 var SumAggregator = (function() { |
| 193 function Aggregator(key) { | 194 function Aggregator(key) { |
| 194 this.key_ = key; | 195 this.key_ = key; |
| 195 this.sum_ = 0; | 196 this.sum_ = 0; |
| 196 } | 197 } |
| 197 | 198 |
| 198 Aggregator.prototype = { | 199 Aggregator.prototype = { |
| 199 consume: function(e) { | 200 consume: function(e) { |
| 200 this.sum_ += e[this.key_]; | 201 this.sum_ += e[this.key_]; |
| 201 }, | 202 }, |
| 202 | 203 |
| 203 getValue: function() { | 204 getValue: function() { |
| 204 return this.sum_; | 205 return this.sum_; |
| 205 }, | 206 }, |
| 206 | 207 |
| 207 getValueAsText: function() { | 208 getValueAsText: function() { |
| 208 return formatNumberAsText(this.getValue()); | 209 return formatNumberAsText(this.getValue()); |
| 209 }, | 210 }, |
| 210 }; | 211 }; |
| 211 | 212 |
| 212 return { | 213 return { |
| 213 create: function(key) { return new Aggregator(key); } | 214 create: function(key) { |
| 215 return new Aggregator(key); |
| 216 } |
| 214 }; | 217 }; |
| 215 })(); | 218 })(); |
| 216 | 219 |
| 217 /** | 220 /** |
| 218 * This aggregator computes an average by summing two | 221 * This aggregator computes an average by summing two |
| 219 * numeric fields, and then dividing the totals. | 222 * numeric fields, and then dividing the totals. |
| 220 */ | 223 */ |
| 221 var AvgAggregator = (function() { | 224 var AvgAggregator = (function() { |
| 222 function Aggregator(numeratorKey, divisorKey) { | 225 function Aggregator(numeratorKey, divisorKey) { |
| 223 this.numeratorKey_ = numeratorKey; | 226 this.numeratorKey_ = numeratorKey; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 311 getValue: function() { | 314 getValue: function() { |
| 312 return this.max_; | 315 return this.max_; |
| 313 }, | 316 }, |
| 314 | 317 |
| 315 getValueAsText: function() { | 318 getValueAsText: function() { |
| 316 return formatNumberAsText(this.getValue()); | 319 return formatNumberAsText(this.getValue()); |
| 317 }, | 320 }, |
| 318 }; | 321 }; |
| 319 | 322 |
| 320 return { | 323 return { |
| 321 create: function(key) { return new Aggregator(key); } | 324 create: function(key) { |
| 325 return new Aggregator(key); |
| 326 } |
| 322 }; | 327 }; |
| 323 })(); | 328 })(); |
| 324 | 329 |
| 325 // -------------------------------------------------------------------------- | 330 // -------------------------------------------------------------------------- |
| 326 // Key properties | 331 // Key properties |
| 327 // -------------------------------------------------------------------------- | 332 // -------------------------------------------------------------------------- |
| 328 | 333 |
| 329 // Custom comparator for thread names (sorts main thread and IO thread | 334 // Custom comparator for thread names (sorts main thread and IO thread |
| 330 // higher than would happen lexicographically.) | 335 // higher than would happen lexicographically.) |
| 331 var threadNameComparator = | 336 var threadNameComparator = createLexicographicComparatorWithExceptions([ |
| 332 createLexicographicComparatorWithExceptions([ | 337 'CrBrowserMain', |
| 333 'CrBrowserMain', | 338 'Chrome_IOThread', |
| 334 'Chrome_IOThread', | 339 'Chrome_FileThread', |
| 335 'Chrome_FileThread', | 340 'Chrome_HistoryThread', |
| 336 'Chrome_HistoryThread', | 341 'Chrome_DBThread', |
| 337 'Chrome_DBThread', | 342 'Still_Alive', |
| 338 'Still_Alive', | 343 ]); |
| 339 ]); | |
| 340 | 344 |
| 341 function diffFuncForCount(a, b) { | 345 function diffFuncForCount(a, b) { |
| 342 return b - a; | 346 return b - a; |
| 343 } | 347 } |
| 344 | 348 |
| 345 function diffFuncForMax(a, b) { | 349 function diffFuncForMax(a, b) { |
| 346 return b; | 350 return b; |
| 347 } | 351 } |
| 348 | 352 |
| 349 /** | 353 /** |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 485 sortDescending: true, | 489 sortDescending: true, |
| 486 textPrinter: formatNumberAsText, | 490 textPrinter: formatNumberAsText, |
| 487 aggregator: AvgAggregator.create(KEY_MEMORY_FREE_OPS, KEY_COUNT), | 491 aggregator: AvgAggregator.create(KEY_MEMORY_FREE_OPS, KEY_COUNT), |
| 488 }; | 492 }; |
| 489 | 493 |
| 490 KEY_PROPERTIES[KEY_MEMORY_AVG_NET_BYTES] = { | 494 KEY_PROPERTIES[KEY_MEMORY_AVG_NET_BYTES] = { |
| 491 name: 'Avg Net Bytes', | 495 name: 'Avg Net Bytes', |
| 492 cellAlignment: 'right', | 496 cellAlignment: 'right', |
| 493 sortDescending: true, | 497 sortDescending: true, |
| 494 textPrinter: formatNumberAsText, | 498 textPrinter: formatNumberAsText, |
| 495 aggregator: AvgDiffAggregator.create(KEY_MEMORY_ALLOCATED_BYTES, | 499 aggregator: AvgDiffAggregator.create( |
| 496 KEY_MEMORY_FREED_BYTES, KEY_COUNT), | 500 KEY_MEMORY_ALLOCATED_BYTES, KEY_MEMORY_FREED_BYTES, KEY_COUNT), |
| 497 }; | 501 }; |
| 498 | 502 |
| 499 KEY_PROPERTIES[KEY_MEMORY_ALLOC_OPS] = { | 503 KEY_PROPERTIES[KEY_MEMORY_ALLOC_OPS] = { |
| 500 name: 'Allocation count', | 504 name: 'Allocation count', |
| 501 cellAlignment: 'right', | 505 cellAlignment: 'right', |
| 502 sortDescending: true, | 506 sortDescending: true, |
| 503 textPrinter: formatNumberAsText, | 507 textPrinter: formatNumberAsText, |
| 504 inputJsonKey: 'death_data.alloc_ops', | 508 inputJsonKey: 'death_data.alloc_ops', |
| 505 aggregator: SumAggregator, | 509 aggregator: SumAggregator, |
| 506 diff: diffFuncForCount, | 510 diff: diffFuncForCount, |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 751 } | 755 } |
| 752 | 756 |
| 753 /** | 757 /** |
| 754 * Formats the number |x| as a decimal integer. Strips off any decimal parts, | 758 * Formats the number |x| as a decimal integer. Strips off any decimal parts, |
| 755 * and comma separates the number every 3 characters. | 759 * and comma separates the number every 3 characters. |
| 756 */ | 760 */ |
| 757 function formatNumberAsText(x) { | 761 function formatNumberAsText(x) { |
| 758 var orig = x.toFixed(0); | 762 var orig = x.toFixed(0); |
| 759 | 763 |
| 760 var parts = []; | 764 var parts = []; |
| 761 for (var end = orig.length; end > 0; ) { | 765 for (var end = orig.length; end > 0;) { |
| 762 var chunk = Math.min(end, 3); | 766 var chunk = Math.min(end, 3); |
| 763 parts.push(orig.substr(end - chunk, chunk)); | 767 parts.push(orig.substr(end - chunk, chunk)); |
| 764 end -= chunk; | 768 end -= chunk; |
| 765 } | 769 } |
| 766 return parts.reverse().join(','); | 770 return parts.reverse().join(','); |
| 767 } | 771 } |
| 768 | 772 |
| 769 /** | 773 /** |
| 770 * Simple comparator function which works for both strings and numbers. | 774 * Simple comparator function which works for both strings and numbers. |
| 771 */ | 775 */ |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 843 var textNode = parent.ownerDocument.createTextNode(text); | 847 var textNode = parent.ownerDocument.createTextNode(text); |
| 844 parent.appendChild(textNode); | 848 parent.appendChild(textNode); |
| 845 return textNode; | 849 return textNode; |
| 846 } | 850 } |
| 847 | 851 |
| 848 /** | 852 /** |
| 849 * Deletes all the strings in |array| which appear in |valuesToDelete|. | 853 * Deletes all the strings in |array| which appear in |valuesToDelete|. |
| 850 */ | 854 */ |
| 851 function deleteValuesFromArray(array, valuesToDelete) { | 855 function deleteValuesFromArray(array, valuesToDelete) { |
| 852 var valueSet = arrayToSet(valuesToDelete); | 856 var valueSet = arrayToSet(valuesToDelete); |
| 853 for (var i = 0; i < array.length; ) { | 857 for (var i = 0; i < array.length;) { |
| 854 if (valueSet[array[i]]) { | 858 if (valueSet[array[i]]) { |
| 855 array.splice(i, 1); | 859 array.splice(i, 1); |
| 856 } else { | 860 } else { |
| 857 i++; | 861 i++; |
| 858 } | 862 } |
| 859 } | 863 } |
| 860 } | 864 } |
| 861 | 865 |
| 862 /** | 866 /** |
| 863 * Deletes all the repeated ocurrences of strings in |array|. | 867 * Deletes all the repeated ocurrences of strings in |array|. |
| 864 */ | 868 */ |
| 865 function deleteDuplicateStringsFromArray(array) { | 869 function deleteDuplicateStringsFromArray(array) { |
| 866 // Build up set of each entry in array. | 870 // Build up set of each entry in array. |
| 867 var seenSoFar = {}; | 871 var seenSoFar = {}; |
| 868 | 872 |
| 869 for (var i = 0; i < array.length; ) { | 873 for (var i = 0; i < array.length;) { |
| 870 var value = array[i]; | 874 var value = array[i]; |
| 871 if (seenSoFar[value]) { | 875 if (seenSoFar[value]) { |
| 872 array.splice(i, 1); | 876 array.splice(i, 1); |
| 873 } else { | 877 } else { |
| 874 seenSoFar[value] = true; | 878 seenSoFar[value] = true; |
| 875 i++; | 879 i++; |
| 876 } | 880 } |
| 877 } | 881 } |
| 878 } | 882 } |
| 879 | 883 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 915 checkbox.type = 'checkbox'; | 919 checkbox.type = 'checkbox'; |
| 916 addText(labelNode, label); | 920 addText(labelNode, label); |
| 917 return checkbox; | 921 return checkbox; |
| 918 } | 922 } |
| 919 | 923 |
| 920 /** | 924 /** |
| 921 * Return the last component in a path which is separated by either forward | 925 * Return the last component in a path which is separated by either forward |
| 922 * slashes or backslashes. | 926 * slashes or backslashes. |
| 923 */ | 927 */ |
| 924 function getFilenameFromPath(path) { | 928 function getFilenameFromPath(path) { |
| 925 var lastSlash = Math.max(path.lastIndexOf('/'), | 929 var lastSlash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\')); |
| 926 path.lastIndexOf('\\')); | |
| 927 if (lastSlash == -1) | 930 if (lastSlash == -1) |
| 928 return path; | 931 return path; |
| 929 | 932 |
| 930 return path.substr(lastSlash + 1); | 933 return path.substr(lastSlash + 1); |
| 931 } | 934 } |
| 932 | 935 |
| 933 /** | 936 /** |
| 934 * Returns the current time in milliseconds since unix epoch. | 937 * Returns the current time in milliseconds since unix epoch. |
| 935 */ | 938 */ |
| 936 function getTimeMillis() { | 939 function getTimeMillis() { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 973 | 976 |
| 974 function computeDataRowAverages(e) { | 977 function computeDataRowAverages(e) { |
| 975 e[KEY_AVG_QUEUE_TIME] = e[KEY_QUEUE_TIME] / e[KEY_COUNT]; | 978 e[KEY_AVG_QUEUE_TIME] = e[KEY_QUEUE_TIME] / e[KEY_COUNT]; |
| 976 e[KEY_AVG_RUN_TIME] = e[KEY_RUN_TIME] / e[KEY_COUNT]; | 979 e[KEY_AVG_RUN_TIME] = e[KEY_RUN_TIME] / e[KEY_COUNT]; |
| 977 | 980 |
| 978 if (loadTimeData.getBoolean('enableMemoryTaskProfiler')) { | 981 if (loadTimeData.getBoolean('enableMemoryTaskProfiler')) { |
| 979 e[KEY_MEMORY_AVG_ALLOC_OPS] = e[KEY_MEMORY_ALLOC_OPS] / e[KEY_COUNT]; | 982 e[KEY_MEMORY_AVG_ALLOC_OPS] = e[KEY_MEMORY_ALLOC_OPS] / e[KEY_COUNT]; |
| 980 e[KEY_MEMORY_AVG_FREE_OPS] = e[KEY_MEMORY_FREE_OPS] / e[KEY_COUNT]; | 983 e[KEY_MEMORY_AVG_FREE_OPS] = e[KEY_MEMORY_FREE_OPS] / e[KEY_COUNT]; |
| 981 e[KEY_MEMORY_AVG_NET_BYTES] = | 984 e[KEY_MEMORY_AVG_NET_BYTES] = |
| 982 (e[KEY_MEMORY_ALLOCATED_BYTES] - e[KEY_MEMORY_FREED_BYTES]) / | 985 (e[KEY_MEMORY_ALLOCATED_BYTES] - e[KEY_MEMORY_FREED_BYTES]) / |
| 983 e[KEY_COUNT]; | 986 e[KEY_COUNT]; |
| 984 } | 987 } |
| 985 } | 988 } |
| 986 | 989 |
| 987 /** | 990 /** |
| 988 * Creates and initializes an aggregator object for each key in |columns|. | 991 * Creates and initializes an aggregator object for each key in |columns|. |
| 989 * Returns an array whose keys are values from |columns|, and whose | 992 * Returns an array whose keys are values from |columns|, and whose |
| 990 * values are Aggregator instances. | 993 * values are Aggregator instances. |
| 991 */ | 994 */ |
| 992 function initializeAggregates(columns) { | 995 function initializeAggregates(columns) { |
| 993 var aggregates = []; | 996 var aggregates = []; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1032 * order). | 1035 * order). |
| 1033 * | 1036 * |
| 1034 * If |mergeSimilarThreads| is true, then threads with a similar name will be | 1037 * If |mergeSimilarThreads| is true, then threads with a similar name will be |
| 1035 * considered equivalent. For instance, "WorkerThread-1" and "WorkerThread-2" | 1038 * considered equivalent. For instance, "WorkerThread-1" and "WorkerThread-2" |
| 1036 * will be remapped to "WorkerThread-*". | 1039 * will be remapped to "WorkerThread-*". |
| 1037 * | 1040 * |
| 1038 * If |outputAsDictionary| is false then the merged rows will be returned as a | 1041 * If |outputAsDictionary| is false then the merged rows will be returned as a |
| 1039 * flat list. Otherwise the result will be a dictionary, where each row | 1042 * flat list. Otherwise the result will be a dictionary, where each row |
| 1040 * has a unique key. | 1043 * has a unique key. |
| 1041 */ | 1044 */ |
| 1042 function mergeRows(origRows, mergeKeys, mergeSimilarThreads, | 1045 function mergeRows( |
| 1043 outputAsDictionary) { | 1046 origRows, mergeKeys, mergeSimilarThreads, outputAsDictionary) { |
| 1044 // Define a translation function for each property. Normally we copy over | 1047 // Define a translation function for each property. Normally we copy over |
| 1045 // properties as-is, but if we have been asked to "merge similar threads" we | 1048 // properties as-is, but if we have been asked to "merge similar threads" we |
| 1046 // we will remap the thread names that end in a numeric suffix. | 1049 // we will remap the thread names that end in a numeric suffix. |
| 1047 var propertyGetterFunc; | 1050 var propertyGetterFunc; |
| 1048 | 1051 |
| 1049 if (mergeSimilarThreads) { | 1052 if (mergeSimilarThreads) { |
| 1050 propertyGetterFunc = function(row, key) { | 1053 propertyGetterFunc = function(row, key) { |
| 1051 var value = row[key]; | 1054 var value = row[key]; |
| 1052 // If the property is a thread name, try to remap it. | 1055 // If the property is a thread name, try to remap it. |
| 1053 if (key == KEY_BIRTH_THREAD || key == KEY_DEATH_THREAD) { | 1056 if (key == KEY_BIRTH_THREAD || key == KEY_DEATH_THREAD) { |
| 1054 var m = /^(.*[^\d])(\d+)$/.exec(value); | 1057 var m = /^(.*[^\d])(\d+)$/.exec(value); |
| 1055 if (m) | 1058 if (m) |
| 1056 value = m[1] + '*'; | 1059 value = m[1] + '*'; |
| 1057 } | 1060 } |
| 1058 return value; | 1061 return value; |
| 1059 }; | 1062 }; |
| 1060 } else { | 1063 } else { |
| 1061 propertyGetterFunc = function(row, key) { return row[key]; }; | 1064 propertyGetterFunc = function(row, key) { |
| 1065 return row[key]; |
| 1066 }; |
| 1062 } | 1067 } |
| 1063 | 1068 |
| 1064 // Determine which sets of properties a row needs to match on to be | 1069 // Determine which sets of properties a row needs to match on to be |
| 1065 // considered identical to another row. | 1070 // considered identical to another row. |
| 1066 var identityKeys = IDENTITY_KEYS.slice(0); | 1071 var identityKeys = IDENTITY_KEYS.slice(0); |
| 1067 deleteValuesFromArray(identityKeys, mergeKeys); | 1072 deleteValuesFromArray(identityKeys, mergeKeys); |
| 1068 | 1073 |
| 1069 // Set |aggregateKeys| to everything else, since we will be aggregating | 1074 // Set |aggregateKeys| to everything else, since we will be aggregating |
| 1070 // their value as part of the merge. | 1075 // their value as part of the merge. |
| 1071 var aggregateKeys = ALL_KEYS.slice(0); | 1076 var aggregateKeys = ALL_KEYS.slice(0); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1119 * | 1124 * |
| 1120 * Rows in data1 and data2 are expected to use the same scheme for the keys. | 1125 * Rows in data1 and data2 are expected to use the same scheme for the keys. |
| 1121 * In other words, data1[k] is considered the analagous row to data2[k]. | 1126 * In other words, data1[k] is considered the analagous row to data2[k]. |
| 1122 */ | 1127 */ |
| 1123 function subtractSnapshots(data1, data2, columnsToExclude) { | 1128 function subtractSnapshots(data1, data2, columnsToExclude) { |
| 1124 // These columns are computed from the other columns. We won't bother | 1129 // These columns are computed from the other columns. We won't bother |
| 1125 // diffing/aggregating these, but rather will derive them again from the | 1130 // diffing/aggregating these, but rather will derive them again from the |
| 1126 // final row. | 1131 // final row. |
| 1127 var COMPUTED_AGGREGATE_KEYS = [KEY_AVG_QUEUE_TIME, KEY_AVG_RUN_TIME]; | 1132 var COMPUTED_AGGREGATE_KEYS = [KEY_AVG_QUEUE_TIME, KEY_AVG_RUN_TIME]; |
| 1128 if (loadTimeData.getBoolean('enableMemoryTaskProfiler')) { | 1133 if (loadTimeData.getBoolean('enableMemoryTaskProfiler')) { |
| 1129 COMPUTED_AGGREGATE_KEYS = COMPUTED_AGGREGATE_KEYS.concat([ | 1134 COMPUTED_AGGREGATE_KEYS = COMPUTED_AGGREGATE_KEYS.concat([ |
| 1130 KEY_MEMORY_AVG_ALLOC_OPS, | 1135 KEY_MEMORY_AVG_ALLOC_OPS, KEY_MEMORY_AVG_FREE_OPS, |
| 1131 KEY_MEMORY_AVG_FREE_OPS, | 1136 KEY_MEMORY_AVG_NET_BYTES |
| 1132 KEY_MEMORY_AVG_NET_BYTES]); | 1137 ]); |
| 1133 } | 1138 } |
| 1134 | 1139 |
| 1135 // These are the keys which determine row equality. Since we are not doing | 1140 // These are the keys which determine row equality. Since we are not doing |
| 1136 // any merging yet at this point, it is simply the list of all identity | 1141 // any merging yet at this point, it is simply the list of all identity |
| 1137 // columns. | 1142 // columns. |
| 1138 var identityKeys = IDENTITY_KEYS.slice(0); | 1143 var identityKeys = IDENTITY_KEYS.slice(0); |
| 1139 deleteValuesFromArray(identityKeys, columnsToExclude); | 1144 deleteValuesFromArray(identityKeys, columnsToExclude); |
| 1140 | 1145 |
| 1141 // The columns to compute via aggregation is everything else. | 1146 // The columns to compute via aggregation is everything else. |
| 1142 var aggregateKeys = ALL_KEYS.slice(0); | 1147 var aggregateKeys = ALL_KEYS.slice(0); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1228 // builds. | 1233 // builds. |
| 1229 var m = /^(.*) \[(\d+)\]$/.exec(text); | 1234 var m = /^(.*) \[(\d+)\]$/.exec(text); |
| 1230 if (m) { | 1235 if (m) { |
| 1231 var filepath = m[1]; | 1236 var filepath = m[1]; |
| 1232 var filename = getFilenameFromPath(filepath); | 1237 var filename = getFilenameFromPath(filepath); |
| 1233 var linenumber = m[2]; | 1238 var linenumber = m[2]; |
| 1234 | 1239 |
| 1235 var link = addNode(td, 'a', filename + ' [' + linenumber + ']'); | 1240 var link = addNode(td, 'a', filename + ' [' + linenumber + ']'); |
| 1236 | 1241 |
| 1237 link.href = 'https://code.google.com/p/chromium/codesearch#search/&q=' + | 1242 link.href = 'https://code.google.com/p/chromium/codesearch#search/&q=' + |
| 1238 encodeURIComponent(filename) + ':' + linenumber + | 1243 encodeURIComponent(filename) + ':' + linenumber + |
| 1239 '&sq=package:chromium&type=cs'; | 1244 '&sq=package:chromium&type=cs'; |
| 1240 link.target = '_blank'; | 1245 link.target = '_blank'; |
| 1241 return; | 1246 return; |
| 1242 } | 1247 } |
| 1243 } | 1248 } |
| 1244 | 1249 |
| 1245 // String values can get pretty long. If the string contains no spaces, then | 1250 // String values can get pretty long. If the string contains no spaces, then |
| 1246 // CSS fails to wrap it, and it overflows the cell causing the table to get | 1251 // CSS fails to wrap it, and it overflows the cell causing the table to get |
| 1247 // really big. We solve this using a hack: insert a <wbr> element after | 1252 // really big. We solve this using a hack: insert a <wbr> element after |
| 1248 // every single character. This will allow the rendering engine to wrap the | 1253 // every single character. This will allow the rendering engine to wrap the |
| 1249 // value, and hence avoid it overflowing! | 1254 // value, and hence avoid it overflowing! |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1502 // Otherwise if two snapshots were chosen, show the difference between | 1507 // Otherwise if two snapshots were chosen, show the difference between |
| 1503 // them. | 1508 // them. |
| 1504 var snapshot1 = this.snapshots_[selectedSnapshots[0]]; | 1509 var snapshot1 = this.snapshots_[selectedSnapshots[0]]; |
| 1505 var snapshot2 = this.snapshots_[selectedSnapshots[1]]; | 1510 var snapshot2 = this.snapshots_[selectedSnapshots[1]]; |
| 1506 | 1511 |
| 1507 var timeDeltaInSeconds = | 1512 var timeDeltaInSeconds = |
| 1508 ((snapshot2.time - snapshot1.time) / 1000).toFixed(0); | 1513 ((snapshot2.time - snapshot1.time) / 1000).toFixed(0); |
| 1509 | 1514 |
| 1510 // Explain that what is being shown is the difference between two | 1515 // Explain that what is being shown is the difference between two |
| 1511 // snapshots. | 1516 // snapshots. |
| 1512 summaryDiv.innerText = | 1517 summaryDiv.innerText = 'Showing the difference between snapshots #' + |
| 1513 'Showing the difference between snapshots #' + | 1518 selectedSnapshots[0] + ' and #' + selectedSnapshots[1] + ' (' + |
| 1514 selectedSnapshots[0] + ' and #' + | 1519 timeDeltaInSeconds + ' seconds worth of data)'; |
| 1515 selectedSnapshots[1] + ' (' + timeDeltaInSeconds + | |
| 1516 ' seconds worth of data)'; | |
| 1517 } else { | 1520 } else { |
| 1518 // This shouldn't be possible... | 1521 // This shouldn't be possible... |
| 1519 throw 'Unexpected number of selected snapshots'; | 1522 throw 'Unexpected number of selected snapshots'; |
| 1520 } | 1523 } |
| 1521 }, | 1524 }, |
| 1522 | 1525 |
| 1523 updateMergedData_: function() { | 1526 updateMergedData_: function() { |
| 1524 // Retrieve the merge options. | 1527 // Retrieve the merge options. |
| 1525 var mergeColumns = this.getMergeColumns_(); | 1528 var mergeColumns = this.getMergeColumns_(); |
| 1526 var shouldMergeSimilarThreads = this.shouldMergeSimilarThreads_(); | 1529 var shouldMergeSimilarThreads = this.shouldMergeSimilarThreads_(); |
| 1527 | 1530 |
| 1528 var selectedSnapshots = this.getSelectedSnapshotIndexes_(); | 1531 var selectedSnapshots = this.getSelectedSnapshotIndexes_(); |
| 1529 | 1532 |
| 1530 // We do merges a bit differently depending if we are displaying the diffs | 1533 // We do merges a bit differently depending if we are displaying the diffs |
| 1531 // between two snapshots, or just displaying a single snapshot. | 1534 // between two snapshots, or just displaying a single snapshot. |
| 1532 if (selectedSnapshots.length == 1) { | 1535 if (selectedSnapshots.length == 1) { |
| 1533 var snapshot = this.snapshots_[selectedSnapshots[0]]; | 1536 var snapshot = this.snapshots_[selectedSnapshots[0]]; |
| 1534 this.mergedData_ = mergeRows(snapshot.flatData, | 1537 this.mergedData_ = mergeRows( |
| 1535 mergeColumns, | 1538 snapshot.flatData, mergeColumns, shouldMergeSimilarThreads, false); |
| 1536 shouldMergeSimilarThreads, | |
| 1537 false); | |
| 1538 | 1539 |
| 1539 } else if (selectedSnapshots.length == 2) { | 1540 } else if (selectedSnapshots.length == 2) { |
| 1540 var snapshot1 = this.snapshots_[selectedSnapshots[0]]; | 1541 var snapshot1 = this.snapshots_[selectedSnapshots[0]]; |
| 1541 var snapshot2 = this.snapshots_[selectedSnapshots[1]]; | 1542 var snapshot2 = this.snapshots_[selectedSnapshots[1]]; |
| 1542 | 1543 |
| 1543 // Merge the data for snapshot1. | 1544 // Merge the data for snapshot1. |
| 1544 var mergedRows1 = mergeRows(snapshot1.flatData, | 1545 var mergedRows1 = mergeRows( |
| 1545 mergeColumns, | 1546 snapshot1.flatData, mergeColumns, shouldMergeSimilarThreads, true); |
| 1546 shouldMergeSimilarThreads, | |
| 1547 true); | |
| 1548 | 1547 |
| 1549 // Merge the data for snapshot2. | 1548 // Merge the data for snapshot2. |
| 1550 var mergedRows2 = mergeRows(snapshot2.flatData, | 1549 var mergedRows2 = mergeRows( |
| 1551 mergeColumns, | 1550 snapshot2.flatData, mergeColumns, shouldMergeSimilarThreads, true); |
| 1552 shouldMergeSimilarThreads, | |
| 1553 true); | |
| 1554 | 1551 |
| 1555 // Do a diff between the two snapshots. | 1552 // Do a diff between the two snapshots. |
| 1556 this.mergedData_ = subtractSnapshots(mergedRows1, | 1553 this.mergedData_ = |
| 1557 mergedRows2, | 1554 subtractSnapshots(mergedRows1, mergedRows2, mergeColumns); |
| 1558 mergeColumns); | |
| 1559 } else { | 1555 } else { |
| 1560 throw 'Unexpected number of selected snapshots'; | 1556 throw 'Unexpected number of selected snapshots'; |
| 1561 } | 1557 } |
| 1562 | 1558 |
| 1563 // Recompute filteredData_ (since it is derived from mergedData_) | 1559 // Recompute filteredData_ (since it is derived from mergedData_) |
| 1564 this.updateFilteredData_(); | 1560 this.updateFilteredData_(); |
| 1565 }, | 1561 }, |
| 1566 | 1562 |
| 1567 updateFilteredData_: function() { | 1563 updateFilteredData_: function() { |
| 1568 // Recompute filteredData_. | 1564 // Recompute filteredData_. |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1716 table.className = 'results-table'; | 1712 table.className = 'results-table'; |
| 1717 var thead = addNode(table, 'thead'); | 1713 var thead = addNode(table, 'thead'); |
| 1718 var tbody = addNode(table, 'tbody'); | 1714 var tbody = addNode(table, 'tbody'); |
| 1719 | 1715 |
| 1720 var displaySettings = this.getGroupDisplaySettings_(groupKey); | 1716 var displaySettings = this.getGroupDisplaySettings_(groupKey); |
| 1721 var limit = displaySettings.limit; | 1717 var limit = displaySettings.limit; |
| 1722 | 1718 |
| 1723 this.drawAggregateRow_(thead, data.aggregates, columns); | 1719 this.drawAggregateRow_(thead, data.aggregates, columns); |
| 1724 this.drawTableHeader_(thead, columns); | 1720 this.drawTableHeader_(thead, columns); |
| 1725 this.drawTableBody_(tbody, data.rows, columns, limit); | 1721 this.drawTableBody_(tbody, data.rows, columns, limit); |
| 1726 this.drawTruncationRow_(tbody, data.rows.length, limit, columns.length, | 1722 this.drawTruncationRow_( |
| 1727 groupKey); | 1723 tbody, data.rows.length, limit, columns.length, groupKey); |
| 1728 }, | 1724 }, |
| 1729 | 1725 |
| 1730 drawTableHeader_: function(thead, columns) { | 1726 drawTableHeader_: function(thead, columns) { |
| 1731 var tr = addNode(thead, 'tr'); | 1727 var tr = addNode(thead, 'tr'); |
| 1732 for (var i = 0; i < columns.length; ++i) { | 1728 for (var i = 0; i < columns.length; ++i) { |
| 1733 var key = columns[i]; | 1729 var key = columns[i]; |
| 1734 var th = addNode(tr, 'th', getNameForKey(key)); | 1730 var th = addNode(tr, 'th', getNameForKey(key)); |
| 1735 th.onclick = this.onClickColumn_.bind(this, key); | 1731 th.onclick = this.onClickColumn_.bind(this, key); |
| 1736 | 1732 |
| 1737 // Draw an indicator if we are currently sorted on this column. | 1733 // Draw an indicator if we are currently sorted on this column. |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1932 this.addSnapshotToList_(this.snapshots_.length - 1); | 1928 this.addSnapshotToList_(this.snapshots_.length - 1); |
| 1933 | 1929 |
| 1934 // Ask the browser for the profiling data. We will receive the data | 1930 // Ask the browser for the profiling data. We will receive the data |
| 1935 // later through a callback to addDataToSnapshot_(). | 1931 // later through a callback to addDataToSnapshot_(). |
| 1936 g_browserBridge.sendGetData(); | 1932 g_browserBridge.sendGetData(); |
| 1937 }, | 1933 }, |
| 1938 | 1934 |
| 1939 saveSnapshots_: function() { | 1935 saveSnapshots_: function() { |
| 1940 var snapshots = []; | 1936 var snapshots = []; |
| 1941 for (var i = 0; i < this.snapshots_.length; ++i) { | 1937 for (var i = 0; i < this.snapshots_.length; ++i) { |
| 1942 snapshots.push({ data: this.snapshots_[i].origData, | 1938 snapshots.push({ |
| 1943 timestamp: Math.floor( | 1939 data: this.snapshots_[i].origData, |
| 1944 this.snapshots_[i].time / 1000) }); | 1940 timestamp: Math.floor(this.snapshots_[i].time / 1000) |
| 1941 }); |
| 1945 } | 1942 } |
| 1946 | 1943 |
| 1947 var dump = { | 1944 var dump = { |
| 1948 'userAgent': navigator.userAgent, | 1945 'userAgent': navigator.userAgent, |
| 1949 'version': 1, | 1946 'version': 1, |
| 1950 'snapshots': snapshots | 1947 'snapshots': snapshots |
| 1951 }; | 1948 }; |
| 1952 | 1949 |
| 1953 var dumpText = JSON.stringify(dump, null, ' '); | 1950 var dumpText = JSON.stringify(dump, null, ' '); |
| 1954 var textBlob = new Blob([dumpText], | 1951 var textBlob = |
| 1955 { type: 'octet/stream', endings: 'native' }); | 1952 new Blob([dumpText], {type: 'octet/stream', endings: 'native'}); |
| 1956 var blobUrl = window.URL.createObjectURL(textBlob); | 1953 var blobUrl = window.URL.createObjectURL(textBlob); |
| 1957 $(DOWNLOAD_ANCHOR_ID).href = blobUrl; | 1954 $(DOWNLOAD_ANCHOR_ID).href = blobUrl; |
| 1958 $(DOWNLOAD_ANCHOR_ID).click(); | 1955 $(DOWNLOAD_ANCHOR_ID).click(); |
| 1959 }, | 1956 }, |
| 1960 | 1957 |
| 1961 loadFileChanged_: function() { | 1958 loadFileChanged_: function() { |
| 1962 this.loadSnapshots_($(SNAPSHOT_FILE_LOADER_ID).files[0]); | 1959 this.loadSnapshots_($(SNAPSHOT_FILE_LOADER_ID).files[0]); |
| 1963 }, | 1960 }, |
| 1964 | 1961 |
| 1965 loadSnapshots_: function(file) { | 1962 loadSnapshots_: function(file) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2004 this.clearExistingSnapshots_(); | 2001 this.clearExistingSnapshots_(); |
| 2005 $(TAKE_SNAPSHOT_BUTTON_ID).disabled = true; | 2002 $(TAKE_SNAPSHOT_BUTTON_ID).disabled = true; |
| 2006 $(SAVE_SNAPSHOTS_BUTTON_ID).disabled = true; | 2003 $(SAVE_SNAPSHOTS_BUTTON_ID).disabled = true; |
| 2007 | 2004 |
| 2008 if (content.snapshots.length > 1) { | 2005 if (content.snapshots.length > 1) { |
| 2009 setNodeDisplay($(SNAPSHOTS_ROW), true); | 2006 setNodeDisplay($(SNAPSHOTS_ROW), true); |
| 2010 } | 2007 } |
| 2011 | 2008 |
| 2012 for (var i = 0; i < content.snapshots.length; ++i) { | 2009 for (var i = 0; i < content.snapshots.length; ++i) { |
| 2013 var snapshot = content.snapshots[i]; | 2010 var snapshot = content.snapshots[i]; |
| 2014 this.snapshots_.push({flatData: [], origData: [], | 2011 this.snapshots_.push( |
| 2015 time: snapshot.timestamp * 1000}); | 2012 {flatData: [], origData: [], time: snapshot.timestamp * 1000}); |
| 2016 this.addSnapshotToList_(this.snapshots_.length - 1); | 2013 this.addSnapshotToList_(this.snapshots_.length - 1); |
| 2017 var snapshotData = snapshot.data; | 2014 var snapshotData = snapshot.data; |
| 2018 for (var j = 0; j < snapshotData.length; ++j) { | 2015 for (var j = 0; j < snapshotData.length; ++j) { |
| 2019 this.addDataToSnapshot(snapshotData[j]); | 2016 this.addDataToSnapshot(snapshotData[j]); |
| 2020 } | 2017 } |
| 2021 } | 2018 } |
| 2022 this.redrawData_(); | 2019 this.redrawData_(); |
| 2023 }, | 2020 }, |
| 2024 | 2021 |
| 2025 onLoadSnapshotsFileError_: function(file, filedata) { | 2022 onLoadSnapshotsFileError_: function(file, filedata) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2085 | 2082 |
| 2086 onSnapshotCheckboxChanged_: function(event) { | 2083 onSnapshotCheckboxChanged_: function(event) { |
| 2087 // Keep track of when we clicked this box (for when we need to uncheck | 2084 // Keep track of when we clicked this box (for when we need to uncheck |
| 2088 // older boxes). | 2085 // older boxes). |
| 2089 event.target.__time = getTimeMillis(); | 2086 event.target.__time = getTimeMillis(); |
| 2090 | 2087 |
| 2091 // Find all the checked boxes. Either 1 or 2 can be checked. If a third | 2088 // Find all the checked boxes. Either 1 or 2 can be checked. If a third |
| 2092 // was just checked, then uncheck one of the earlier ones so we only have | 2089 // was just checked, then uncheck one of the earlier ones so we only have |
| 2093 // 2. | 2090 // 2. |
| 2094 var checked = this.getSelectedSnapshotBoxes_(); | 2091 var checked = this.getSelectedSnapshotBoxes_(); |
| 2095 checked.sort(function(a, b) { return b.__time - a.__time; }); | 2092 checked.sort(function(a, b) { |
| 2093 return b.__time - a.__time; |
| 2094 }); |
| 2096 if (checked.length > 2) { | 2095 if (checked.length > 2) { |
| 2097 for (var i = 2; i < checked.length; ++i) | 2096 for (var i = 2; i < checked.length; ++i) |
| 2098 checked[i].checked = false; | 2097 checked[i].checked = false; |
| 2099 checked.length = 2; | 2098 checked.length = 2; |
| 2100 } | 2099 } |
| 2101 | 2100 |
| 2102 // We should always have at least 1 selection. Prevent the user from | 2101 // We should always have at least 1 selection. Prevent the user from |
| 2103 // unselecting the final box. | 2102 // unselecting the final box. |
| 2104 if (checked.length == 0) | 2103 if (checked.length == 0) |
| 2105 event.target.checked = true; | 2104 event.target.checked = true; |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2303 }; | 2302 }; |
| 2304 }, | 2303 }, |
| 2305 | 2304 |
| 2306 getGroupSortingFunction_: function() { | 2305 getGroupSortingFunction_: function() { |
| 2307 return function(a, b) { | 2306 return function(a, b) { |
| 2308 var groupKey1 = JSON.parse(a); | 2307 var groupKey1 = JSON.parse(a); |
| 2309 var groupKey2 = JSON.parse(b); | 2308 var groupKey2 = JSON.parse(b); |
| 2310 | 2309 |
| 2311 for (var i = 0; i < groupKey1.length; ++i) { | 2310 for (var i = 0; i < groupKey1.length; ++i) { |
| 2312 var comparison = compareValuesForKey( | 2311 var comparison = compareValuesForKey( |
| 2313 groupKey1[i].key, | 2312 groupKey1[i].key, groupKey1[i].value, groupKey2[i].value); |
| 2314 groupKey1[i].value, | |
| 2315 groupKey2[i].value); | |
| 2316 | 2313 |
| 2317 if (comparison != 0) | 2314 if (comparison != 0) |
| 2318 return comparison; | 2315 return comparison; |
| 2319 } | 2316 } |
| 2320 | 2317 |
| 2321 // Tie breaker. | 2318 // Tie breaker. |
| 2322 return simpleCompare(a, b); | 2319 return simpleCompare(a, b); |
| 2323 }; | 2320 }; |
| 2324 }, | 2321 }, |
| 2325 | 2322 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2354 deleteValuesFromArray(groupings, ['']); | 2351 deleteValuesFromArray(groupings, ['']); |
| 2355 | 2352 |
| 2356 // Eliminate duplicate primary/secondary group by directives, since they | 2353 // Eliminate duplicate primary/secondary group by directives, since they |
| 2357 // are redundant. | 2354 // are redundant. |
| 2358 deleteDuplicateStringsFromArray(groupings); | 2355 deleteDuplicateStringsFromArray(groupings); |
| 2359 | 2356 |
| 2360 return function(e) { | 2357 return function(e) { |
| 2361 var groupKey = []; | 2358 var groupKey = []; |
| 2362 | 2359 |
| 2363 for (var i = 0; i < groupings.length; ++i) { | 2360 for (var i = 0; i < groupings.length; ++i) { |
| 2364 var entry = {key: groupings[i], | 2361 var entry = {key: groupings[i], value: e[groupings[i]]}; |
| 2365 value: e[groupings[i]]}; | |
| 2366 groupKey.push(entry); | 2362 groupKey.push(entry); |
| 2367 } | 2363 } |
| 2368 | 2364 |
| 2369 return JSON.stringify(groupKey); | 2365 return JSON.stringify(groupKey); |
| 2370 }; | 2366 }; |
| 2371 }, | 2367 }, |
| 2372 }; | 2368 }; |
| 2373 | 2369 |
| 2374 return MainView; | 2370 return MainView; |
| 2375 })(); | 2371 })(); |
| OLD | NEW |