3 Copyright (c) 2013 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file.
8 <link rel="stylesheet" href="/system_stats/system_stats_instance_track.css">
9 <link rel="import" href="/tvcm/sorted_array_utils.html">
10 <link rel="import" href="/tracing/tracks/stacked_bars_track.html">
11 <link rel="import" href="/tracing/tracks/object_instance_track.html">
12 <link rel="import" href="/tracing/color_scheme.html">
13 <link rel="import" href="/tvcm/ui.html">
18 tvcm.exportTo('system_stats', function() {
19 var EventPresenter = tracing.EventPresenter;
21 var palette = tvcm.ui.getColorPalette();
22 var highlightIdBoost = tvcm.ui.getColorPaletteHighlightIdBoost();
26 var excludedStats = {'meminfo': {
38 'weighted_io_time': 0,
46 * Tracks that display system stats data.
49 * @extends {StackedBarsTrack}
52 var SystemStatsInstanceTrack = tvcm.ui.define(
53 'system-stats-instance-track', tracing.tracks.StackedBarsTrack);
55 SystemStatsInstanceTrack.prototype = {
57 __proto__: tracing.tracks.StackedBarsTrack.prototype,
59 decorate: function(viewport) {
60 tracing.tracks.StackedBarsTrack.prototype.decorate.call(this, viewport);
61 this.classList.add('system-stats-instance-track');
62 this.objectInstance_ = null;
65 set objectInstances(objectInstances) {
66 if (!objectInstances) {
67 this.objectInstance_ = [];
70 if (objectInstances.length != 1)
71 throw new Error('Bad object instance count.');
72 this.objectInstance_ = objectInstances[0];
73 if (this.objectInstance_ !== null) {
74 this.computeRates_(this.objectInstance_.snapshots);
75 this.maxStats_ = this.computeMaxStats_(
76 this.objectInstance_.snapshots);
80 computeRates_: function(snapshots) {
81 for (var i = 0; i < snapshots.length; i++) {
82 var snapshot = snapshots[i];
83 var stats = snapshot.getStats();
88 // Deltas will be zero.
89 prevSnapshot = snapshots[0];
91 prevSnapshot = snapshots[i - 1];
93 prevStats = prevSnapshot.getStats();
94 var timeIntervalSeconds = (snapshot.ts - prevSnapshot.ts) / 1000;
95 // Prevent divide by zero.
96 if (timeIntervalSeconds == 0)
97 timeIntervalSeconds = 1;
99 this.computeRatesRecursive_(prevStats, stats,
100 timeIntervalSeconds);
104 computeRatesRecursive_: function(prevStats, stats,
105 timeIntervalSeconds) {
106 for (var statName in stats) {
107 if (stats[statName] instanceof Object) {
108 this.computeRatesRecursive_(prevStats[statName],
110 timeIntervalSeconds);
112 if (statName == 'sectors_read') {
113 stats['bytes_read_per_sec'] = (stats['sectors_read'] -
114 prevStats['sectors_read']) *
115 512 / timeIntervalSeconds;
117 if (statName == 'sectors_written') {
118 stats['bytes_written_per_sec'] =
119 (stats['sectors_written'] -
120 prevStats['sectors_written']) *
121 512 / timeIntervalSeconds;
123 if (statName == 'pgmajfault') {
124 stats['pgmajfault_per_sec'] = (stats['pgmajfault'] -
125 prevStats['pgmajfault']) /
128 if (statName == 'pswpin') {
129 stats['bytes_swpin_per_sec'] = (stats['pswpin'] -
130 prevStats['pswpin']) *
131 1000 / timeIntervalSeconds;
133 if (statName == 'pswpout') {
134 stats['bytes_swpout_per_sec'] = (stats['pswpout'] -
135 prevStats['pswpout']) *
136 1000 / timeIntervalSeconds;
142 computeMaxStats_: function(snapshots) {
143 var maxStats = new Object();
146 for (var i = 0; i < snapshots.length; i++) {
147 var snapshot = snapshots[i];
148 var stats = snapshot.getStats();
150 this.computeMaxStatsRecursive_(stats, maxStats,
157 computeMaxStatsRecursive_: function(stats, maxStats, excludedStats) {
158 for (var statName in stats) {
159 if (stats[statName] instanceof Object) {
160 if (!(statName in maxStats))
161 maxStats[statName] = new Object();
164 if (excludedStats && statName in excludedStats)
165 excludedNested = excludedStats[statName];
167 excludedNested = null;
169 this.computeMaxStatsRecursive_(stats[statName],
173 if (excludedStats && statName in excludedStats)
175 if (!(statName in maxStats)) {
176 maxStats[statName] = 0;
179 if (stats[statName] > maxStats[statName])
180 maxStats[statName] = stats[statName];
186 return window.getComputedStyle(this).height;
190 this.style.height = height;
193 draw: function(type, viewLWorld, viewRWorld) {
195 case tracing.tracks.DrawType.SLICE:
196 this.drawStatBars_(viewLWorld, viewRWorld);
201 drawStatBars_: function(viewLWorld, viewRWorld) {
202 var ctx = this.context();
203 var pixelRatio = window.devicePixelRatio || 1;
205 var bounds = this.getBoundingClientRect();
206 var width = bounds.width * pixelRatio;
207 var height = (bounds.height * pixelRatio) / statCount;
209 // Culling parameters.
210 var vp = this.viewport.currentDisplayTransform;
212 // Scale by the size of the largest snapshot.
213 var maxStats = this.maxStats_;
215 var objectSnapshots = this.objectInstance_.snapshots;
216 var lowIndex = tvcm.findLowIndexInSortedArray(
223 // Assure that the stack with the left edge off screen still gets drawn
227 for (var i = lowIndex; i < objectSnapshots.length; ++i) {
228 var snapshot = objectSnapshots[i];
229 var trace = snapshot.getStats();
230 var currentY = height;
232 var left = snapshot.ts;
233 if (left > viewRWorld)
235 var leftView = vp.xWorldToView(left);
239 // Compute the edges for the column graph bar.
241 if (i != objectSnapshots.length - 1) {
242 right = objectSnapshots[i + 1].ts;
244 // If this is the last snaphot of multiple snapshots, use the width of
245 // the previous snapshot for the width.
246 if (objectSnapshots.length > 1)
247 right = objectSnapshots[i].ts + (objectSnapshots[i].ts -
248 objectSnapshots[i - 1].ts);
250 // If there's only one snapshot, use max bounds as the width.
251 right = this.objectInstance_.parent.model.bounds.max;
254 var rightView = vp.xWorldToView(right);
255 if (rightView > width)
258 // Floor the bounds to avoid a small gap between stacks.
259 leftView = Math.floor(leftView);
260 rightView = Math.floor(rightView);
262 // Descend into nested stats.
263 this.drawStatBarsRecursive_(snapshot,
272 this.drawStatNames_(leftView, height, currentY, '', maxStats);
277 drawStatBarsRecursive_: function(snapshot,
284 var ctx = this.context();
286 for (var statName in maxStats) {
287 if (stats[statName] instanceof Object) {
288 // Use the y-position returned from the recursive call.
289 currentY = this.drawStatBarsRecursive_(snapshot,
297 var maxStat = maxStats[statName];
299 // Draw a bar for the stat. The height of the bar is scaled
300 // against the largest value of the stat across all snapshots.
301 ctx.fillStyle = EventPresenter.getBarSnapshotColor(
302 snapshot, Math.round(currentY / height));
307 barHeight = height * Math.max(stats[statName], 0) / maxStat;
312 ctx.fillRect(leftView, currentY - barHeight,
313 Math.max(rightView - leftView, 1), barHeight);
319 // Return the updated y-position.
323 drawStatNames_: function(leftView, height, currentY, prefix, maxStats) {
324 var ctx = this.context();
326 ctx.textAlign = 'end';
327 ctx.font = '12px Arial';
328 ctx.fillStyle = '#000000';
329 for (var statName in maxStats) {
330 if (maxStats[statName] instanceof Object) {
331 currentY = this.drawStatNames_(leftView, height, currentY,
332 statName, maxStats[statName]);
334 var fullname = statName;
337 fullname = prefix + ' :: ' + statName;
339 ctx.fillText(fullname, leftView - 10, currentY - height / 4);
348 tracing.tracks.ObjectInstanceTrack.register(
349 'base::TraceEventSystemStatsMonitor::SystemStats',
350 SystemStatsInstanceTrack);
353 SystemStatsInstanceTrack: SystemStatsInstanceTrack