Chromium Code Reviews| 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 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 97 | 97 |
| 98 // The checkbox which controls whether things like "Worker Threads" and | 98 // The checkbox which controls whether things like "Worker Threads" and |
| 99 // "PAC threads" will be merged together. | 99 // "PAC threads" will be merged together. |
| 100 var MERGE_SIMILAR_THREADS_CHECKBOX_ID = 'merge-similar-threads-checkbox'; | 100 var MERGE_SIMILAR_THREADS_CHECKBOX_ID = 'merge-similar-threads-checkbox'; |
| 101 | 101 |
| 102 var RESET_DATA_LINK_ID = 'reset-data-link'; | 102 var RESET_DATA_LINK_ID = 'reset-data-link'; |
| 103 | 103 |
| 104 var TOGGLE_SNAPSHOTS_LINK_ID = 'snapshots-link'; | 104 var TOGGLE_SNAPSHOTS_LINK_ID = 'snapshots-link'; |
| 105 var SNAPSHOTS_ROW = 'snapshots-row'; | 105 var SNAPSHOTS_ROW = 'snapshots-row'; |
| 106 var SNAPSHOT_SELECTION_SUMMARY_ID = 'snapshot-selection-summary'; | 106 var SNAPSHOT_SELECTION_SUMMARY_ID = 'snapshot-selection-summary'; |
| 107 var TAKE_SNAPSHOT_BUTTON_ID = 'snapshot-button'; | 107 var TAKE_SNAPSHOT_BUTTON_ID = 'take-snapshot-button'; |
| 108 | |
| 109 var SAVE_SNAPSHOTS_BUTTON_ID = 'save-snapshots-button'; | |
| 110 var SNAPSHOT_FILE_LOADER_ID = 'snapshot-file-loader'; | |
| 111 var LOAD_ERROR_ID = 'file-load-error'; | |
| 112 | |
| 113 var DOWNLOAD_IFRAME_ID = 'download-iframe'; | |
| 108 | 114 |
| 109 // -------------------------------------------------------------------------- | 115 // -------------------------------------------------------------------------- |
| 110 // Row keys | 116 // Row keys |
| 111 // -------------------------------------------------------------------------- | 117 // -------------------------------------------------------------------------- |
| 112 | 118 |
| 113 // Each row of our data is an array of values rather than a dictionary. This | 119 // Each row of our data is an array of values rather than a dictionary. This |
| 114 // avoids some overhead from repeating the key string multiple times, and | 120 // avoids some overhead from repeating the key string multiple times, and |
| 115 // speeds up the property accesses a bit. The following keys are well-known | 121 // speeds up the property accesses a bit. The following keys are well-known |
| 116 // indexes into the array for various properties. | 122 // indexes into the array for various properties. |
| 117 // | 123 // |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 792 * Toggle a node between hidden/invisible. | 798 * Toggle a node between hidden/invisible. |
| 793 */ | 799 */ |
| 794 function toggleNodeDisplay(n) { | 800 function toggleNodeDisplay(n) { |
| 795 if (n.style.display == '') { | 801 if (n.style.display == '') { |
| 796 n.style.display = 'none'; | 802 n.style.display = 'none'; |
| 797 } else { | 803 } else { |
| 798 n.style.display = ''; | 804 n.style.display = ''; |
| 799 } | 805 } |
| 800 } | 806 } |
| 801 | 807 |
| 808 /** | |
| 809 * Set the visibility state of a node. | |
| 810 */ | |
| 811 function setNodeDisplay(n, visible) { | |
| 812 if (visible) { | |
| 813 n.style.display = ''; | |
| 814 } else { | |
| 815 n.style.display = 'none'; | |
| 816 } | |
| 817 } | |
| 818 | |
| 802 // -------------------------------------------------------------------------- | 819 // -------------------------------------------------------------------------- |
| 803 // Functions that augment, bucket, and compute aggregates for the input data. | 820 // Functions that augment, bucket, and compute aggregates for the input data. |
| 804 // -------------------------------------------------------------------------- | 821 // -------------------------------------------------------------------------- |
| 805 | 822 |
| 806 /** | 823 /** |
| 807 * Adds new derived properties to row. Mutates the provided dictionary |e|. | 824 * Adds new derived properties to row. Mutates the provided dictionary |e|. |
| 808 */ | 825 */ |
| 809 function augmentDataRow(e) { | 826 function augmentDataRow(e) { |
| 810 computeDataRowAverages(e); | 827 computeDataRowAverages(e); |
| 811 e[KEY_SOURCE_LOCATION] = e[KEY_FILE_NAME] + ' [' + e[KEY_LINE_NUMBER] + ']'; | 828 e[KEY_SOURCE_LOCATION] = e[KEY_FILE_NAME] + ' [' + e[KEY_LINE_NUMBER] + ']'; |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1190 addDataToSnapshot: function(data) { | 1207 addDataToSnapshot: function(data) { |
| 1191 // TODO(eroman): We need to know which snapshot this data belongs to! | 1208 // TODO(eroman): We need to know which snapshot this data belongs to! |
| 1192 // For now we assume it is the most recent snapshot. | 1209 // For now we assume it is the most recent snapshot. |
| 1193 var snapshotIndex = this.snapshots_.length - 1; | 1210 var snapshotIndex = this.snapshots_.length - 1; |
| 1194 | 1211 |
| 1195 var snapshot = this.snapshots_[snapshotIndex]; | 1212 var snapshot = this.snapshots_[snapshotIndex]; |
| 1196 | 1213 |
| 1197 var pid = data.process_id; | 1214 var pid = data.process_id; |
| 1198 var ptype = data.process_type; | 1215 var ptype = data.process_type; |
| 1199 | 1216 |
| 1217 // Save the browser's representation of the data | |
| 1218 snapshot.origData.push(data); | |
| 1219 | |
| 1200 // Augment each data row with the process information. | 1220 // Augment each data row with the process information. |
| 1201 var rows = data.list; | 1221 var rows = data.list; |
| 1202 for (var i = 0; i < rows.length; ++i) { | 1222 for (var i = 0; i < rows.length; ++i) { |
| 1203 // Transform the data from a dictionary to an array. This internal | 1223 // Transform the data from a dictionary to an array. This internal |
| 1204 // representation is more compact and faster to access. | 1224 // representation is more compact and faster to access. |
| 1205 var origRow = rows[i]; | 1225 var origRow = rows[i]; |
| 1206 var newRow = []; | 1226 var newRow = []; |
| 1207 | 1227 |
| 1208 newRow[KEY_PROCESS_ID] = pid; | 1228 newRow[KEY_PROCESS_ID] = pid; |
| 1209 newRow[KEY_PROCESS_TYPE] = ptype; | 1229 newRow[KEY_PROCESS_TYPE] = ptype; |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1298 | 1318 |
| 1299 /** | 1319 /** |
| 1300 * This function should be called any time a snapshot dependency for what is | 1320 * This function should be called any time a snapshot dependency for what is |
| 1301 * being displayed on the screen has changed. It will re-calculate the | 1321 * being displayed on the screen has changed. It will re-calculate the |
| 1302 * difference between the two snapshots and update flatData_. | 1322 * difference between the two snapshots and update flatData_. |
| 1303 */ | 1323 */ |
| 1304 updateFlatData_: function() { | 1324 updateFlatData_: function() { |
| 1305 var summaryDiv = $(SNAPSHOT_SELECTION_SUMMARY_ID); | 1325 var summaryDiv = $(SNAPSHOT_SELECTION_SUMMARY_ID); |
| 1306 | 1326 |
| 1307 var selectedSnapshots = this.getSelectedSnapshotIndexes_(); | 1327 var selectedSnapshots = this.getSelectedSnapshotIndexes_(); |
| 1308 if (selectedSnapshots.length == 1) { | 1328 if (selectedSnapshots.length == 0) { |
| 1329 // This can occur during an attempt to load a file or following file | |
| 1330 // load failure. We just ignore it and move on. | |
| 1331 } else if (selectedSnapshots.length == 1) { | |
| 1309 // If only one snapshot is chosen then we will display that snapshot's | 1332 // If only one snapshot is chosen then we will display that snapshot's |
| 1310 // data in its entirety. | 1333 // data in its entirety. |
| 1311 this.flatData_ = this.snapshots_[selectedSnapshots[0]].flatData; | 1334 this.flatData_ = this.snapshots_[selectedSnapshots[0]].flatData; |
| 1312 | 1335 |
| 1313 // Don't bother displaying any text when just 1 snapshot is selected, | 1336 // Don't bother displaying any text when just 1 snapshot is selected, |
| 1314 // since it is obvious what this should do. | 1337 // since it is obvious what this should do. |
| 1315 summaryDiv.innerText = ''; | 1338 summaryDiv.innerText = ''; |
| 1316 } else if (selectedSnapshots.length == 2) { | 1339 } else if (selectedSnapshots.length == 2) { |
| 1317 // Otherwise if two snapshots were chosen, show the difference between | 1340 // Otherwise if two snapshots were chosen, show the difference between |
| 1318 // them. | 1341 // them. |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1702 $(TOGGLE_SNAPSHOTS_LINK_ID).onclick = | 1725 $(TOGGLE_SNAPSHOTS_LINK_ID).onclick = |
| 1703 toggleNodeDisplay.bind(null, $(SNAPSHOTS_ROW)); | 1726 toggleNodeDisplay.bind(null, $(SNAPSHOTS_ROW)); |
| 1704 | 1727 |
| 1705 $(MERGE_SIMILAR_THREADS_CHECKBOX_ID).onchange = | 1728 $(MERGE_SIMILAR_THREADS_CHECKBOX_ID).onchange = |
| 1706 this.onMergeSimilarThreadsCheckboxChanged_.bind(this); | 1729 this.onMergeSimilarThreadsCheckboxChanged_.bind(this); |
| 1707 | 1730 |
| 1708 $(RESET_DATA_LINK_ID).onclick = | 1731 $(RESET_DATA_LINK_ID).onclick = |
| 1709 g_browserBridge.sendResetData.bind(g_browserBridge); | 1732 g_browserBridge.sendResetData.bind(g_browserBridge); |
| 1710 | 1733 |
| 1711 $(TAKE_SNAPSHOT_BUTTON_ID).onclick = this.takeSnapshot_.bind(this); | 1734 $(TAKE_SNAPSHOT_BUTTON_ID).onclick = this.takeSnapshot_.bind(this); |
| 1735 | |
| 1736 $(SAVE_SNAPSHOTS_BUTTON_ID).onclick = this.saveSnapshots_.bind(this); | |
| 1737 $(SNAPSHOT_FILE_LOADER_ID).onchange = this.loadFileChanged_.bind(this); | |
| 1712 }, | 1738 }, |
| 1713 | 1739 |
| 1714 takeSnapshot_: function() { | 1740 takeSnapshot_: function() { |
| 1715 // Start a new empty snapshot. Make note of the current time, so we know | 1741 // Start a new empty snapshot. Make note of the current time, so we know |
| 1716 // when the snaphot was taken. | 1742 // when the snaphot was taken. |
| 1717 this.snapshots_.push({flatData: [], time: getTimeMillis()}); | 1743 this.snapshots_.push({flatData: [], origData: [], time: getTimeMillis()}); |
| 1718 | 1744 |
| 1719 // Update the UI to reflect the new snapshot. | 1745 // Update the UI to reflect the new snapshot. |
| 1720 this.addSnapshotToList_(this.snapshots_.length - 1); | 1746 this.addSnapshotToList_(this.snapshots_.length - 1); |
| 1721 | 1747 |
| 1722 // Ask the browser for the profiling data. We will receive the data | 1748 // Ask the browser for the profiling data. We will receive the data |
| 1723 // later through a callback to addDataToSnapshot_(). | 1749 // later through a callback to addDataToSnapshot_(). |
| 1724 g_browserBridge.sendGetData(); | 1750 g_browserBridge.sendGetData(); |
| 1725 }, | 1751 }, |
| 1726 | 1752 |
| 1753 saveSnapshots_: function() { | |
| 1754 var snapshots = []; | |
| 1755 for (var i = 0; i < this.snapshots_.length; ++i) { | |
| 1756 snapshots.push({ data: this.snapshots_[i].origData, | |
| 1757 timestamp: this.snapshots_[i].time }); | |
| 1758 } | |
| 1759 | |
| 1760 var dump = { | |
| 1761 // 'browser_version': '' // FIXME fetch this somehow | |
|
eroman
2011/12/12 23:14:28
you could include the user agent (navigator.userAg
| |
| 1762 'snapshots': snapshots | |
|
eroman
2011/12/12 23:14:28
I suggest putting a version field in the format to
| |
| 1763 } | |
| 1764 | |
| 1765 var dumpText = JSON.stringify(dump, null, ' ') | |
| 1766 var blobBuilder = new WebKitBlobBuilder(); | |
| 1767 blobBuilder.append(dumpText, 'native'); | |
| 1768 var textBlob = blobBuilder.getBlob('octet/stream'); | |
| 1769 var blobUrl = window.webkitURL.createObjectURL(textBlob); | |
| 1770 $(DOWNLOAD_IFRAME_ID).src = blobUrl; | |
| 1771 }, | |
| 1772 | |
| 1773 loadFileChanged_: function() { | |
| 1774 this.loadSnapshots_($(SNAPSHOT_FILE_LOADER_ID).files[0]) | |
| 1775 }, | |
| 1776 | |
| 1777 loadSnapshots_: function(file) { | |
| 1778 if (file) { | |
| 1779 var fileReader = new FileReader(); | |
| 1780 | |
| 1781 fileReader.onload = this.onLoadSnapshotsFile_.bind(this, file); | |
| 1782 fileReader.onerror = this.onLoadSnapshotsFileError_.bind(this, file); | |
| 1783 | |
| 1784 fileReader.readAsText(file); | |
| 1785 } | |
| 1786 }, | |
| 1787 | |
| 1788 onLoadSnapshotsFile_: function(file, event) { | |
| 1789 try { | |
| 1790 var parsed = null; | |
| 1791 parsed = JSON.parse(event.target.result) | |
| 1792 | |
| 1793 this.displayLoadedFile_(file, parsed); | |
| 1794 this.hideFileLoadError_(); | |
| 1795 } catch (error) { | |
| 1796 this.displayFileLoadError_('File load failure: ' + error.message); | |
| 1797 } | |
| 1798 }, | |
| 1799 | |
| 1800 clearExistingSnapshots_: function() { | |
| 1801 var tbody = $('snapshots-tbody'); | |
| 1802 this.snapshots_ = []; | |
| 1803 while (tbody.hasChildNodes()) { | |
|
eroman
2011/12/12 23:14:28
A more typical way to empty a node is:
tbody.inne
| |
| 1804 tbody.removeChild(tbody.lastChild); | |
| 1805 } | |
| 1806 this.updateFlatDataSoon_(); | |
| 1807 }, | |
| 1808 | |
| 1809 displayLoadedFile_: function (file, content) { | |
| 1810 this.clearExistingSnapshots_(); | |
| 1811 $(TAKE_SNAPSHOT_BUTTON_ID).disabled = true; | |
| 1812 $(SAVE_SNAPSHOTS_BUTTON_ID).disabled = true; | |
| 1813 | |
| 1814 if (content.snapshots.length > 1) { | |
| 1815 setNodeDisplay($(SNAPSHOTS_ROW), true); | |
| 1816 } | |
| 1817 | |
| 1818 for (var i = 0; i < content.snapshots.length; ++i) { | |
| 1819 var snapshot = content.snapshots[i]; | |
| 1820 this.snapshots_.push({flatData: [], origData: [], | |
| 1821 time: snapshot.timestamp}); | |
| 1822 this.addSnapshotToList_(this.snapshots_.length - 1); | |
| 1823 var snapshotData = snapshot.data; | |
| 1824 for (var j = 0; j < snapshotData.length; ++j){ | |
| 1825 this.addDataToSnapshot(snapshotData[j]); | |
| 1826 } | |
| 1827 } | |
| 1828 this.redrawData_(); | |
| 1829 }, | |
| 1830 | |
| 1831 onLoadSnapshotsFileError_: function(file, filedata) { | |
| 1832 this.displayFileLoadError_('Error loading ' + file.name); | |
| 1833 }, | |
| 1834 | |
| 1835 displayFileLoadError_: function(message) { | |
| 1836 $(LOAD_ERROR_ID).textContent = message; | |
| 1837 $(LOAD_ERROR_ID).hidden = false; | |
| 1838 }, | |
| 1839 | |
| 1840 hideFileLoadError_: function() { | |
| 1841 $(LOAD_ERROR_ID).textContent = ''; | |
| 1842 $(LOAD_ERROR_ID).hidden = true; | |
| 1843 }, | |
| 1844 | |
| 1727 getSnapshotCheckbox_: function(i) { | 1845 getSnapshotCheckbox_: function(i) { |
| 1728 return $(this.getSnapshotCheckboxId_(i)); | 1846 return $(this.getSnapshotCheckboxId_(i)); |
| 1729 }, | 1847 }, |
| 1730 | 1848 |
| 1731 getSnapshotCheckboxId_: function(i) { | 1849 getSnapshotCheckboxId_: function(i) { |
| 1732 return 'snapshotCheckbox-' + i; | 1850 return 'snapshotCheckbox-' + i; |
| 1733 }, | 1851 }, |
| 1734 | 1852 |
| 1735 addSnapshotToList_: function(i) { | 1853 addSnapshotToList_: function(i) { |
| 1736 var tbody = $('snapshots-tbody'); | 1854 var tbody = $('snapshots-tbody'); |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2053 groupKey.push(entry); | 2171 groupKey.push(entry); |
| 2054 } | 2172 } |
| 2055 | 2173 |
| 2056 return JSON.stringify(groupKey); | 2174 return JSON.stringify(groupKey); |
| 2057 }; | 2175 }; |
| 2058 }, | 2176 }, |
| 2059 }; | 2177 }; |
| 2060 | 2178 |
| 2061 return MainView; | 2179 return MainView; |
| 2062 })(); | 2180 })(); |
| OLD | NEW |