processes.js revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5processes = new (function() { 6 7this.PS_INTERVAL_SEC_ = 2; 8this.DEV_STATS_INTERVAL_SEC_ = 2; 9this.PROC_STATS_INTERVAL_SEC_ = 1; 10this.TRACER_POLL_INTERVAL_SEC_ = 2; 11 12this.selProcUri_ = null; 13this.selProcName_ = null; 14this.psTable_ = null; 15this.psTableData_ = null; 16this.memChart_ = null; 17this.memChartData_ = null; 18this.cpuChart_ = null; 19this.cpuChartData_ = null; 20this.procCpuChart_ = null; 21this.procCpuChartData_ = null; 22this.procMemChart_ = null; 23this.procMemChartData_ = null; 24this.tracerTaskId_ = null; 25 26this.onDomReady_ = function() { 27 $('#device_tabs').tabs(); 28 $('#device_tabs').on('tabsactivate', this.redrawPsStats_.bind(this)); 29 $('#device_tabs').on('tabsactivate', this.redrawDevStats_.bind(this)); 30 31 // Initialize the toolbar. 32 $('#ps-quick_snapshot').button({icons:{primary: 'ui-icon-image'}}) 33 .click(this.snapshotSelectedProcess_.bind(this)); 34 $('#ps-dump_mmaps').button({icons:{primary: 'ui-icon-calculator'}}) 35 .click(this.dumpSelectedProcessMmaps_.bind(this)); 36 $('#ps-full_profile').button({icons:{primary: 'ui-icon-clock'}}) 37 .click(this.showTracingDialog_.bind(this)); 38 39 // Set-up the tracer dialog. 40 $('#ps-tracer-dialog').dialog({autoOpen: false, modal: true, width: 400, 41 buttons: {'Start': this.startTracingSelectedProcess_.bind(this)}}); 42 $('#ps-tracer-period').spinner({min: 0, step: 20}); 43 $('#ps-tracer-snapshots').spinner({min: 1, max: 100}); 44 45 // Create the process table. 46 this.psTable_ = new google.visualization.Table($('#ps-table')[0]); 47 google.visualization.events.addListener( 48 this.psTable_, 'select', this.onPsTableRowSelect_.bind(this)); 49 $('#ps-table').on('dblclick', this.snapshotSelectedProcess_.bind(this)); 50 51 // Create the device stats charts. 52 this.memChart_ = new google.visualization.PieChart($('#os-mem_chart')[0]); 53 this.cpuChart_ = new google.visualization.BarChart($('#os-cpu_chart')[0]); 54 55 // Create the selected process stats charts. 56 this.procCpuChart_ = 57 new google.visualization.ComboChart($('#proc-cpu_chart')[0]); 58 this.procMemChart_ = 59 new google.visualization.ComboChart($('#proc-mem_chart')[0]); 60}; 61 62this.getSelectedProcessURI = function() { 63 return this.selProcUri_; 64}; 65 66this.snapshotSelectedProcess_ = function() { 67 if (!this.selProcUri_) 68 return alert('Must select a process!'); 69 mmap.dumpMmaps(this.selProcUri_, true); 70 rootUi.showTab('prof'); 71}; 72 73this.dumpSelectedProcessMmaps_ = function() { 74 if (!this.selProcUri_) 75 return alert('Must select a process!'); 76 mmap.dumpMmaps(this.selProcUri_, false); 77 rootUi.showTab('mm'); 78}; 79 80this.showAndroidProvisionDialog_ = function() { 81 $("#android_provision_dialog").dialog({ 82 modal: true, 83 width: '50em', 84 buttons: { 85 Continue: function() { 86 devices.initializeSelectedDevice(true); 87 $(this).dialog('close'); 88 rootUi.showDialog( 89 'Wait device to complete reboot (~30 s) then retry.', 90 'Device rebooting'); 91 processes.clear(); 92 }, 93 Cancel: function() { 94 $(this).dialog('close'); 95 } 96 } 97 }); 98}; 99 100this.showTracingDialog_ = function() { 101 if (!this.selProcUri_) 102 return alert('Must select a process!'); 103 $('#ps-tracer-process').val(this.selProcName_); 104 $('#ps-tracer-dialog').dialog('open'); 105}; 106 107this.startTracingSelectedProcess_ = function() { 108 if (!this.selProcUri_) 109 return alert('The process ' + this.selProcUri_ + ' died.'); 110 var traceNativeHeap = $('#ps-tracer-bt').prop('checked'); 111 112 $('#ps-tracer-dialog').dialog('close'); 113 114 if (traceNativeHeap && !devices.getSelectedDevice().isNativeTracingEnabled) { 115 this.showAndroidProvisionDialog_(); 116 return; 117 } 118 119 var postArgs = {interval: $('#ps-tracer-period').val(), 120 count: $('#ps-tracer-snapshots').val(), 121 traceNativeHeap: traceNativeHeap}; 122 123 webservice.ajaxRequest('/tracer/start/' + this.selProcUri_, 124 this.onStartTracerAjaxResponse_.bind(this), 125 null, // Use default error handler 126 postArgs); 127}; 128 129this.onStartTracerAjaxResponse_ = function(data) { 130 this.tracerTaskId_ = data; 131 timers.start('tracer', 132 this.pollTracerStatus_.bind(this), 133 this.TRACER_POLL_INTERVAL_SEC_); 134}; 135 136this.pollTracerStatus_ = function() { 137 if (!this.tracerTaskId_) { 138 timers.stop('tracer'); 139 return; 140 } 141 webservice.ajaxRequest('/tracer/status/' + this.tracerTaskId_, 142 this.onTracerStatusAjaxResponse_.bind(this)); 143}; 144 145this.onTracerStatusAjaxResponse_ = function(data) { 146 var logMessages = ''; 147 var completionRate = 0; 148 data.forEach(function(progress) { 149 completionRate = progress[0]; 150 logMessages += '\n' + progress[1]; 151 }, this); 152 rootUi.setProgress(completionRate); 153 rootUi.setStatusMessage(logMessages); 154 155 if (completionRate >= 100) { 156 tracerTaskId_ = null; 157 timers.stop('tracer'); 158 } 159}; 160 161this.refreshPsTable = function() { 162 var targetDevUri = devices.getSelectedURI(); 163 if (!targetDevUri) 164 return this.stopPsTable(); 165 166 var showAllParam = $('#ps-show_all').prop('checked') ? '?all=1' : ''; 167 webservice.ajaxRequest('/ps/' + targetDevUri + showAllParam, 168 this.onPsAjaxResponse_.bind(this), 169 this.stopPsTable.bind(this)); 170}; 171 172this.startPsTable = function() { 173 timers.start('ps_table', 174 this.refreshPsTable.bind(this), 175 this.PS_INTERVAL_SEC_); 176}; 177 178this.stopPsTable = function() { 179 this.selProcUri_ = null; 180 this.selProcName_ = null; 181 timers.stop('ps_table'); 182}; 183 184this.onPsTableRowSelect_ = function() { 185 var targetDevUri = devices.getSelectedURI(); 186 if (!targetDevUri) 187 return; 188 189 var sel = this.psTable_.getSelection(); 190 if (!sel.length || !this.psTableData_) 191 return; 192 var pid = this.psTableData_.getValue(sel[0].row, 0); 193 this.selProcUri_ = targetDevUri + '/' + pid; 194 this.selProcName_ = this.psTableData_.getValue(sel[0].row, 1); 195 this.startSelectedProcessStats(); 196}; 197 198this.onPsAjaxResponse_ = function(data) { 199 this.psTableData_ = new google.visualization.DataTable(data); 200 this.redrawPsTable_(); 201}; 202 203this.redrawPsTable_ = function(data) { 204 if (!this.psTableData_) 205 return; 206 207 // Redraw table preserving sorting info. 208 var sort = this.psTable_.getSortInfo() || {column: -1, ascending: false}; 209 this.psTable_.draw(this.psTableData_, {sortColumn: sort.column, 210 sortAscending: sort.ascending}); 211}; 212 213this.refreshDeviceStats = function() { 214 var targetDevUri = devices.getSelectedURI(); 215 if (!targetDevUri) 216 return this.stopDeviceStats(); 217 218 webservice.ajaxRequest('/stats/' + targetDevUri, 219 this.onDevStatsAjaxResponse_.bind(this), 220 this.stopDeviceStats.bind(this)); 221}; 222 223this.startDeviceStats = function() { 224 timers.start('device_stats', 225 this.refreshDeviceStats.bind(this), 226 this.DEV_STATS_INTERVAL_SEC_); 227}; 228 229this.stopDeviceStats = function() { 230 timers.stop('device_stats'); 231}; 232 233this.onDevStatsAjaxResponse_ = function(data) { 234 this.memChartData_ = new google.visualization.DataTable(data.mem); 235 this.cpuChartData_ = new google.visualization.DataTable(data.cpu); 236 this.redrawDevStats_(); 237}; 238 239this.redrawDevStats_ = function(data) { 240 if (!this.memChartData_ || !this.cpuChartData_) 241 return; 242 243 this.memChart_.draw(this.memChartData_, 244 {title: 'System Memory Usage (MB)', is3D: true}); 245 this.cpuChart_.draw(this.cpuChartData_, 246 {title: 'CPU Usage', 247 isStacked: true, 248 hAxis: {maxValue: 100, viewWindow: {max: 100}}}); 249}; 250 251this.refreshSelectedProcessStats = function() { 252 if (!this.selProcUri_) 253 return this.stopSelectedProcessStats(); 254 255 webservice.ajaxRequest('/stats/' + this.selProcUri_, 256 this.onPsStatsAjaxResponse_.bind(this), 257 this.stopSelectedProcessStats.bind(this)); 258}; 259 260this.startSelectedProcessStats = function() { 261 timers.start('proc_stats', 262 this.refreshSelectedProcessStats.bind(this), 263 this.PROC_STATS_INTERVAL_SEC_); 264 $('#device_tabs').tabs('option', 'active', 1); 265}; 266 267this.stopSelectedProcessStats = function() { 268 timers.stop('proc_stats'); 269}; 270 271this.onPsStatsAjaxResponse_ = function(data) { 272 this.procCpuChartData_ = new google.visualization.DataTable(data.cpu); 273 this.procMemChartData_ = new google.visualization.DataTable(data.mem); 274 this.redrawPsStats_(); 275}; 276 277this.redrawPsStats_ = function() { 278 if (!this.procCpuChartData_ || !this.procMemChartData_) 279 return; 280 281 this.procCpuChart_.draw(this.procCpuChartData_, { 282 title: 'CPU stats for ' + this.selProcUri_, 283 seriesType: 'line', 284 vAxes: {0: {title: 'CPU %', maxValue: 100}, 1: {title: '# Threads'}}, 285 series: {1: {type: 'bars', targetAxisIndex: 1}}, 286 hAxis: {title: 'Run Time'}, 287 legend: {alignment: 'end'}, 288 }); 289 this.procMemChart_.draw(this.procMemChartData_, { 290 title: 'Memory stats for ' + this.selProcUri_, 291 seriesType: 'line', 292 vAxes: {0: {title: 'VM Rss KB'}, 1: {title: '# Page Faults'}}, 293 series: {1: {type: 'bars', targetAxisIndex: 1}}, 294 hAxis: {title: 'Run Time'}, 295 legend: {alignment: 'end'}, 296 }); 297}; 298 299this.redraw = function() { 300 this.redrawPsTable_(); 301 if ($('#device_tabs').tabs('option', 'active') == 0) 302 this.redrawDevStats_(); 303 else 304 this.redrawPsStats_(); 305}; 306 307this.clear = function() { 308 this.stopSelectedProcessStats(); 309 $('#device_tabs').tabs('option', 'active', 0); 310 this.psTableData_ = new google.visualization.DataTable(); 311 this.redraw(); 312}; 313 314$(document).ready(this.onDomReady_.bind(this)); 315 316})();