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.
5 processes = new (function() {
7 this.PS_INTERVAL_SEC_ = 2;
8 this.DEV_STATS_INTERVAL_SEC_ = 2;
9 this.PROC_STATS_INTERVAL_SEC_ = 1;
10 this.TRACER_POLL_INTERVAL_SEC_ = 2;
12 this.selProcUri_ = null;
13 this.selProcName_ = null;
15 this.psTableData_ = null;
16 this.memChart_ = null;
17 this.memChartData_ = null;
18 this.cpuChart_ = null;
19 this.cpuChartData_ = null;
20 this.procCpuChart_ = null;
21 this.procCpuChartData_ = null;
22 this.procMemChart_ = null;
23 this.procMemChartData_ = null;
24 this.tracerTaskId_ = null;
26 this.onDomReady_ = function() {
27 $('#device_tabs').tabs();
28 $('#device_tabs').on('tabsactivate', this.redrawPsStats_.bind(this));
29 $('#device_tabs').on('tabsactivate', this.redrawDevStats_.bind(this));
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));
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});
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));
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]);
55 // Create the selected process stats charts.
57 new google.visualization.ComboChart($('#proc-cpu_chart')[0]);
59 new google.visualization.ComboChart($('#proc-mem_chart')[0]);
62 this.getSelectedProcessURI = function() {
63 return this.selProcUri_;
66 this.snapshotSelectedProcess_ = function() {
67 if (!this.selProcUri_)
68 return alert('Must select a process!');
69 mmap.dumpMmaps(this.selProcUri_, true);
70 rootUi.showTab('prof');
73 this.dumpSelectedProcessMmaps_ = function() {
74 if (!this.selProcUri_)
75 return alert('Must select a process!');
76 mmap.dumpMmaps(this.selProcUri_, false);
80 this.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');
87 this.startTracingSelectedProcess_ = function() {
88 if (!this.selProcUri_)
89 return alert('The process ' + this.selProcUri_ + ' died.');
90 var traceNativeHeap = $('#ps-tracer-bt').prop('checked');
92 $('#ps-tracer-dialog').dialog('close');
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.');
104 var postArgs = {interval: $('#ps-tracer-period').val(),
105 count: $('#ps-tracer-snapshots').val(),
106 traceNativeHeap: traceNativeHeap};
108 webservice.ajaxRequest('/tracer/start/' + this.selProcUri_,
109 this.onStartTracerAjaxResponse_.bind(this),
110 null, // Use default error handler
114 this.onStartTracerAjaxResponse_ = function(data) {
115 this.tracerTaskId_ = data;
116 timers.start('tracer',
117 this.pollTracerStatus_.bind(this),
118 this.TRACER_POLL_INTERVAL_SEC_);
121 this.pollTracerStatus_ = function() {
122 if (!this.tracerTaskId_) {
123 timers.stop('tracer');
126 webservice.ajaxRequest('/tracer/status/' + this.tracerTaskId_,
127 this.onTracerStatusAjaxResponse_.bind(this));
130 this.onTracerStatusAjaxResponse_ = function(data) {
131 var logMessages = '';
132 var completionRate = 0;
133 data.forEach(function(progress) {
134 completionRate = progress[0];
135 logMessages += '\n' + progress[1];
137 rootUi.setProgress(completionRate);
138 rootUi.setStatusMessage(logMessages);
140 if (completionRate >= 100) {
141 tracerTaskId_ = null;
142 timers.stop('tracer');
146 this.refreshPsTable = function() {
147 var targetDevUri = devices.getSelectedURI();
149 return this.stopPsTable();
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));
157 this.startPsTable = function() {
158 timers.start('ps_table',
159 this.refreshPsTable.bind(this),
160 this.PS_INTERVAL_SEC_);
163 this.stopPsTable = function() {
164 this.selProcUri_ = null;
165 this.selProcName_ = null;
166 timers.stop('ps_table');
169 this.onPsTableRowSelect_ = function() {
170 var targetDevUri = devices.getSelectedURI();
174 var sel = this.psTable_.getSelection();
175 if (!sel.length || !this.psTableData_)
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();
183 this.onPsAjaxResponse_ = function(data) {
184 this.psTableData_ = new google.visualization.DataTable(data);
185 this.redrawPsTable_();
188 this.redrawPsTable_ = function(data) {
189 if (!this.psTableData_)
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});
198 this.refreshDeviceStats = function() {
199 var targetDevUri = devices.getSelectedURI();
201 return this.stopDeviceStats();
203 webservice.ajaxRequest('/stats/' + targetDevUri,
204 this.onDevStatsAjaxResponse_.bind(this),
205 this.stopDeviceStats.bind(this));
208 this.startDeviceStats = function() {
209 timers.start('device_stats',
210 this.refreshDeviceStats.bind(this),
211 this.DEV_STATS_INTERVAL_SEC_);
214 this.stopDeviceStats = function() {
215 timers.stop('device_stats');
218 this.onDevStatsAjaxResponse_ = function(data) {
219 this.memChartData_ = new google.visualization.DataTable(data.mem);
220 this.cpuChartData_ = new google.visualization.DataTable(data.cpu);
221 this.redrawDevStats_();
224 this.redrawDevStats_ = function(data) {
225 if (!this.memChartData_ || !this.cpuChartData_)
228 this.memChart_.draw(this.memChartData_,
229 {title: 'System Memory Usage (MB)', is3D: true});
230 this.cpuChart_.draw(this.cpuChartData_,
233 hAxis: {maxValue: 100, viewWindow: {max: 100}}});
236 this.refreshSelectedProcessStats = function() {
237 if (!this.selProcUri_)
238 return this.stopSelectedProcessStats();
240 webservice.ajaxRequest('/stats/' + this.selProcUri_,
241 this.onPsStatsAjaxResponse_.bind(this),
242 this.stopSelectedProcessStats.bind(this));
245 this.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);
252 this.stopSelectedProcessStats = function() {
253 timers.stop('proc_stats');
256 this.onPsStatsAjaxResponse_ = function(data) {
257 this.procCpuChartData_ = new google.visualization.DataTable(data.cpu);
258 this.procMemChartData_ = new google.visualization.DataTable(data.mem);
259 this.redrawPsStats_();
262 this.redrawPsStats_ = function() {
263 if (!this.procCpuChartData_ || !this.procMemChartData_)
266 this.procCpuChart_.draw(this.procCpuChartData_, {
267 title: 'CPU stats for ' + this.selProcUri_,
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'},
274 this.procMemChart_.draw(this.procMemChartData_, {
275 title: 'Memory stats for ' + this.selProcUri_,
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'},
284 this.redraw = function() {
285 this.redrawPsTable_();
286 if ($('#device_tabs').tabs('option', 'active') == 0)
287 this.redrawDevStats_();
289 this.redrawPsStats_();
292 $(document).ready(this.onDomReady_.bind(this));