processes.js revision 0529e5d033099cbfc42635f6f6183833b09dff6e
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.showTracingDialog_ = function() { 81 if (!this.selProcUri_) 82 return alert('Must select a process!'); 83 $('#ps-tracer-process').val(this.selProcName_); 84 $('#ps-tracer-dialog').dialog('open'); 85}; 86 87this.startTracingSelectedProcess_ = function() { 88 if (!this.selProcUri_) 89 return alert('The process ' + this.selProcUri_ + ' died.'); 90 var traceNativeHeap = $('#ps-tracer-bt').prop('checked'); 91 92 $('#ps-tracer-dialog').dialog('close'); 93 94 if (traceNativeHeap && !devices.getSelectedDevice().isNativeTracingEnabled) { 95 var shouldProvision = confirm('Native heap tracing is not enabled.\n' + 96 'Do you want to enable it (will cause a reboot on Android)?'); 97 if (shouldProvision) { 98 devices.initializeSelectedDevice(true); 99 alert('Wait device to complete reboot and then retry.'); 100 return; 101 } 102 } 103 104 var postArgs = {interval: $('#ps-tracer-period').val(), 105 count: $('#ps-tracer-snapshots').val(), 106 traceNativeHeap: traceNativeHeap}; 107 108 webservice.ajaxRequest('/tracer/start/' + this.selProcUri_, 109 this.onStartTracerAjaxResponse_.bind(this), 110 null, // Use default error handler 111 postArgs); 112}; 113 114this.onStartTracerAjaxResponse_ = function(data) { 115 this.tracerTaskId_ = data; 116 timers.start('tracer', 117 this.pollTracerStatus_.bind(this), 118 this.TRACER_POLL_INTERVAL_SEC_); 119}; 120 121this.pollTracerStatus_ = function() { 122 if (!this.tracerTaskId_) { 123 timers.stop('tracer'); 124 return; 125 } 126 webservice.ajaxRequest('/tracer/status/' + this.tracerTaskId_, 127 this.onTracerStatusAjaxResponse_.bind(this)); 128}; 129 130this.onTracerStatusAjaxResponse_ = function(data) { 131 var logMessages = ''; 132 var completionRate = 0; 133 data.forEach(function(progress) { 134 completionRate = progress[0]; 135 logMessages += '\n' + progress[1]; 136 }, this); 137 rootUi.setProgress(completionRate); 138 rootUi.setStatusMessage(logMessages); 139 140 if (completionRate >= 100) { 141 tracerTaskId_ = null; 142 timers.stop('tracer'); 143 } 144}; 145 146this.refreshPsTable = function() { 147 var targetDevUri = devices.getSelectedURI(); 148 if (!targetDevUri) 149 return this.stopPsTable(); 150 151 var showAllParam = $('#ps-show_all').prop('checked') ? '?all=1' : ''; 152 webservice.ajaxRequest('/ps/' + targetDevUri + showAllParam, 153 this.onPsAjaxResponse_.bind(this), 154 this.stopPsTable.bind(this)); 155}; 156 157this.startPsTable = function() { 158 timers.start('ps_table', 159 this.refreshPsTable.bind(this), 160 this.PS_INTERVAL_SEC_); 161}; 162 163this.stopPsTable = function() { 164 this.selProcUri_ = null; 165 this.selProcName_ = null; 166 timers.stop('ps_table'); 167}; 168 169this.onPsTableRowSelect_ = function() { 170 var targetDevUri = devices.getSelectedURI(); 171 if (!targetDevUri) 172 return; 173 174 var sel = this.psTable_.getSelection(); 175 if (!sel.length || !this.psTableData_) 176 return; 177 var pid = this.psTableData_.getValue(sel[0].row, 0); 178 this.selProcUri_ = targetDevUri + '/' + pid; 179 this.selProcName_ = this.psTableData_.getValue(sel[0].row, 1); 180 this.startSelectedProcessStats(); 181}; 182 183this.onPsAjaxResponse_ = function(data) { 184 this.psTableData_ = new google.visualization.DataTable(data); 185 this.redrawPsTable_(); 186}; 187 188this.redrawPsTable_ = function(data) { 189 if (!this.psTableData_) 190 return; 191 192 // Redraw table preserving sorting info. 193 var sort = this.psTable_.getSortInfo() || {column: -1, ascending: false}; 194 this.psTable_.draw(this.psTableData_, {sortColumn: sort.column, 195 sortAscending: sort.ascending}); 196}; 197 198this.refreshDeviceStats = function() { 199 var targetDevUri = devices.getSelectedURI(); 200 if (!targetDevUri) 201 return this.stopDeviceStats(); 202 203 webservice.ajaxRequest('/stats/' + targetDevUri, 204 this.onDevStatsAjaxResponse_.bind(this), 205 this.stopDeviceStats.bind(this)); 206}; 207 208this.startDeviceStats = function() { 209 timers.start('device_stats', 210 this.refreshDeviceStats.bind(this), 211 this.DEV_STATS_INTERVAL_SEC_); 212}; 213 214this.stopDeviceStats = function() { 215 timers.stop('device_stats'); 216}; 217 218this.onDevStatsAjaxResponse_ = function(data) { 219 this.memChartData_ = new google.visualization.DataTable(data.mem); 220 this.cpuChartData_ = new google.visualization.DataTable(data.cpu); 221 this.redrawDevStats_(); 222}; 223 224this.redrawDevStats_ = function(data) { 225 if (!this.memChartData_ || !this.cpuChartData_) 226 return; 227 228 this.memChart_.draw(this.memChartData_, 229 {title: 'System Memory Usage (MB)', is3D: true}); 230 this.cpuChart_.draw(this.cpuChartData_, 231 {title: 'CPU Usage', 232 isStacked: true, 233 hAxis: {maxValue: 100, viewWindow: {max: 100}}}); 234}; 235 236this.refreshSelectedProcessStats = function() { 237 if (!this.selProcUri_) 238 return this.stopSelectedProcessStats(); 239 240 webservice.ajaxRequest('/stats/' + this.selProcUri_, 241 this.onPsStatsAjaxResponse_.bind(this), 242 this.stopSelectedProcessStats.bind(this)); 243}; 244 245this.startSelectedProcessStats = function() { 246 timers.start('proc_stats', 247 this.refreshSelectedProcessStats.bind(this), 248 this.PROC_STATS_INTERVAL_SEC_); 249 $('#device_tabs').tabs('option', 'active', 1); 250}; 251 252this.stopSelectedProcessStats = function() { 253 timers.stop('proc_stats'); 254}; 255 256this.onPsStatsAjaxResponse_ = function(data) { 257 this.procCpuChartData_ = new google.visualization.DataTable(data.cpu); 258 this.procMemChartData_ = new google.visualization.DataTable(data.mem); 259 this.redrawPsStats_(); 260}; 261 262this.redrawPsStats_ = function() { 263 if (!this.procCpuChartData_ || !this.procMemChartData_) 264 return; 265 266 this.procCpuChart_.draw(this.procCpuChartData_, { 267 title: 'CPU stats for ' + this.selProcUri_, 268 seriesType: 'line', 269 vAxes: {0: {title: 'CPU %', maxValue: 100}, 1: {title: '# Threads'}}, 270 series: {1: {type: 'bars', targetAxisIndex: 1}}, 271 hAxis: {title: 'Run Time'}, 272 legend: {alignment: 'end'}, 273 }); 274 this.procMemChart_.draw(this.procMemChartData_, { 275 title: 'Memory stats for ' + this.selProcUri_, 276 seriesType: 'line', 277 vAxes: {0: {title: 'VM Rss KB'}, 1: {title: '# Page Faults'}}, 278 series: {1: {type: 'bars', targetAxisIndex: 1}}, 279 hAxis: {title: 'Run Time'}, 280 legend: {alignment: 'end'}, 281 }); 282}; 283 284this.redraw = function() { 285 this.redrawPsTable_(); 286 if ($('#device_tabs').tabs('option', 'active') == 0) 287 this.redrawDevStats_(); 288 else 289 this.redrawPsStats_(); 290}; 291 292$(document).ready(this.onDomReady_.bind(this)); 293 294})();