Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(579)

Unified Diff: chrome/browser/resources/tracing/timeline_track.js

Issue 8513009: Add TRACE_COUNTER support to about:tracing (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/tracing/timeline_track.js
diff --git a/chrome/browser/resources/tracing/timeline_track.js b/chrome/browser/resources/tracing/timeline_track.js
index 206dc976e6f43489d200cc5547221de47b4a5778..e8f22545c1c37a53c03a8797cf20c90665c9d11a 100644
--- a/chrome/browser/resources/tracing/timeline_track.js
+++ b/chrome/browser/resources/tracing/timeline_track.js
@@ -66,64 +66,32 @@ cr.define('tracing', function() {
return w;
}
- function addTrack(thisTrack, slices) {
- var track = new TimelineSliceTrack();
-
- track.heading = '';
- track.slices = slices;
- track.viewport = thisTrack.viewport_;
-
- thisTrack.tracks_.push(track);
- thisTrack.appendChild(track);
- }
-
/**
- * Generic base class for timeline tracks
+ * A generic track that contains other tracks as its children.
+ * @constructor
*/
- TimelineThreadTrack = cr.ui.define('div');
- TimelineThreadTrack.prototype = {
+ var TimelineContainerTrack = cr.ui.define('div');
+ TimelineContainerTrack.prototype = {
__proto__: HTMLDivElement.prototype,
decorate: function() {
- this.className = 'timeline-thread-track';
- },
-
- set thread(thread) {
- this.thread_ = thread;
- this.updateChildTracks_();
+ this.tracks_ = [];
},
- /**
- * @return {string} A human-readable name for the track.
- */
- get heading() {
- if (!this.thread_)
- return '';
- var tname = this.thread_.name || this.thread_.tid;
- return this.thread_.parent.pid + ': ' +
- tname + ':';
+ detach: function() {
+ for (var i = 0; i < this.tracks_.length; i++)
+ this.tracks_[i].detach();
},
- set headingWidth(width) {
- for (var i = 0; i < this.tracks_.length; i++)
- this.tracks_[i].headingWidth = width;
+ get viewport() {
+ return this.viewport_;
},
set viewport(v) {
this.viewport_ = v;
for (var i = 0; i < this.tracks_.length; i++)
this.tracks_[i].viewport = v;
- this.invalidate();
- },
-
- invalidate: function() {
- if (this.parentNode)
- this.parentNode.invalidate();
- },
-
- onResize: function() {
- for (var i = 0; i < this.tracks_.length; i++)
- this.tracks_[i].onResize();
+ this.updateChildTracks_();
},
get firstCanvas() {
@@ -132,30 +100,6 @@ cr.define('tracing', function() {
return undefined;
},
- redraw: function() {
- for (var i = 0; i < this.tracks_.length; i++)
- this.tracks_[i].redraw();
- },
-
- updateChildTracks_: function() {
- this.textContent = '';
- this.tracks_ = [];
- if (this.thread_) {
- for (var srI = 0; srI < this.thread_.nonNestedSubRows.length; ++srI) {
- addTrack(this, this.thread_.nonNestedSubRows[srI]);
- }
- for (var srI = 0; srI < this.thread_.subRows.length; ++srI) {
- addTrack(this, this.thread_.subRows[srI]);
- }
- if (this.tracks_.length > 0) {
- this.tracks_[0].heading = this.heading;
- this.tracks_[0].tooltip = 'pid: ' + this.thread_.parent.pid +
- ', tid: ' + this.thread_.tid +
- (this.thread_.name ? ', name: ' + this.thread_.name : '');
- }
- }
- },
-
/**
* Picks a slice, if any, at a given location.
* @param {number} wX X location to search at, in worldspace.
@@ -199,33 +143,120 @@ cr.define('tracing', function() {
};
/**
- * Creates a new timeline track div element
+ * Visualizes a TimelineThread using a series of of TimelineSliceTracks.
+ * @constructor
+ */
+ var TimelineThreadTrack = cr.ui.define(TimelineContainerTrack);
+ TimelineThreadTrack.prototype = {
+ __proto__: TimelineContainerTrack.prototype,
+
+ decorate: function() {
+ this.classList.add('timeline-thread-track');
+ },
+
+ get thread(thread) {
+ return this.thread_;
+ },
+
+ set thread(thread) {
+ this.thread_ = thread;
+ this.updateChildTracks_();
+ },
+
+ get tooltip() {
+ return this.tooltip_;
+ },
+
+ set tooltip(value) {
+ this.tooltip_ = value;
+ this.updateChildTracks_();
+ },
+
+ get heading() {
+ return this.heading_;
+ },
+
+ set heading(h) {
+ this.heading_ = h;
+ this.updateChildTracks_();
+ },
+
+ get headingWidth() {
+ return this.headingWidth_;
+ },
+
+ set headingWidth(width) {
+ this.headingWidth_ = width;
+ this.updateChildTracks_();
+ },
+
+ addTrack_: function(slices) {
+ var track = new TimelineSliceTrack();
+ track.heading = '';
+ track.slices = slices;
+ track.headingWidth = this.headingWidth_;
+ track.viewport = this.viewport_;
+
+ this.tracks_.push(track);
+ this.appendChild(track);
+ },
+
+ updateChildTracks_: function() {
+ this.detach();
+ this.textContent = '';
+ this.tracks_ = [];
+ if (this.thread_) {
+ for (var srI = 0; srI < this.thread_.nonNestedSubRows.length; ++srI) {
+ this.addTrack_(this.thread_.nonNestedSubRows[srI]);
+ }
+ for (var srI = 0; srI < this.thread_.subRows.length; ++srI) {
+ this.addTrack_(this.thread_.subRows[srI]);
+ }
+ if (this.tracks_.length > 0) {
+ this.tracks_[0].heading = this.heading_;
+ this.tracks_[0].tooltip = this.tooltip_;
+ }
+ }
+ }
+ };
+
+ /**
+ * A canvas-based track constructed. Provides the basic heading and
+ * invalidation-managment infrastructure. Subclasses must implement drawing
+ * and picking code.
* @constructor
* @extends {HTMLDivElement}
*/
- TimelineSliceTrack = cr.ui.define('div');
+ var CanvasBasedTrack = cr.ui.define('div');
- TimelineSliceTrack.prototype = {
+ CanvasBasedTrack.prototype = {
__proto__: HTMLDivElement.prototype,
decorate: function() {
- this.className = 'timeline-slice-track';
+ this.className = 'timeline-canvas-based-track';
this.slices_ = null;
this.headingDiv_ = document.createElement('div');
- this.headingDiv_.className = 'timeline-slice-track-title';
+ this.headingDiv_.className = 'timeline-canvas-based-track-title';
this.appendChild(this.headingDiv_);
this.canvasContainer_ = document.createElement('div');
- this.canvasContainer_.className = 'timeline-slice-track-canvas-container';
+ this.canvasContainer_.className =
+ 'timeline-canvas-based-track-canvas-container';
this.appendChild(this.canvasContainer_);
this.canvas_ = document.createElement('canvas');
- this.canvas_.className = 'timeline-slice-track-canvas';
+ this.canvas_.className = 'timeline-canvas-based-track-canvas';
this.canvasContainer_.appendChild(this.canvas_);
this.ctx_ = this.canvas_.getContext('2d');
},
+ detach: function() {
+ if (this.viewport_)
+ this.viewport_.removeEventListener('change',
+ this.viewportChangeBoundToThis_);
+ },
+
set headingWidth(width) {
this.headingDiv_.style.width = width;
},
@@ -242,41 +273,85 @@ cr.define('tracing', function() {
this.headingDiv_.title = text;
},
- set slices(slices) {
- this.slices_ = slices;
- this.invalidate();
+ get viewport() {
+ return this.viewport_;
},
set viewport(v) {
this.viewport_ = v;
+ if (this.viewport_)
+ this.viewport_.removeEventListener('change',
+ this.viewportChangeBoundToThis_);
+ this.viewport_ = v;
+ if (this.viewport_) {
+ this.viewportChangeBoundToThis_ = this.viewportChange_.bind(this);
+ this.viewport_.addEventListener('change',
+ this.viewportChangeBoundToThis_);
+ }
+ this.invalidate();
+ },
+
+ viewportChange_: function() {
this.invalidate();
},
invalidate: function() {
- if (this.parentNode)
- this.parentNode.invalidate();
+ if (this.rafPending_)
+ return;
+ webkitRequestAnimationFrame(function() {
+ this.rafPending_ = false;
+ if (!this.viewport_)
+ return;
+
+ if (this.canvas_.width != this.canvasContainer_.clientWidth)
+ this.canvas_.width = this.canvasContainer_.clientWidth;
+ if (this.canvas_.height != this.canvasContainer_.clientHeight)
+ this.canvas_.height = this.canvasContainer_.clientHeight;
+
+ this.redraw();
+ }.bind(this), this);
+ this.rafPending_ = true;
},
get firstCanvas() {
return this.canvas_;
+ }
+
+ };
+
+ /**
+ * A track that displays an array of TimelineSlice objects.
+ * @constructor
+ * @extends {CanvasBasedTrack}
+ */
+
+ var TimelineSliceTrack = cr.ui.define(CanvasBasedTrack);
+
+ TimelineSliceTrack.prototype = {
+
+ __proto__: CanvasBasedTrack.prototype,
+
+ decorate: function() {
+ this.classList.add('timeline-slice-track');
+ },
+
+ get slices() {
+ return this.slices_;
},
- onResize: function() {
- this.canvas_.width = this.canvasContainer_.clientWidth;
- this.canvas_.height = this.canvasContainer_.clientHeight;
+ set slices(slices) {
+ this.slices_ = slices;
this.invalidate();
},
redraw: function() {
- if (!this.viewport_)
- return;
var ctx = this.ctx_;
var canvasW = this.canvas_.width;
var canvasH = this.canvas_.height;
ctx.clearRect(0, 0, canvasW, canvasH);
- // culling...
+ // Culling parameters.
var vp = this.viewport_;
var pixWidth = vp.xViewVectorToWorld(1);
var viewLWorld = vp.xViewToWorld(0);
@@ -301,11 +376,11 @@ cr.define('tracing', function() {
ctx.stroke();
}
- // begin rendering in world space
+ // Begin rendering in world space.
ctx.save();
vp.applyTransformToCanavs(ctx);
- // tracks
+ // Slices.
var tr = new tracing.FastRectRenderer(ctx, viewLWorld, 2 * pixWidth,
2 * pixWidth, viewRWorld, pallette);
tr.setYandH(0, canvasH);
@@ -343,7 +418,7 @@ cr.define('tracing', function() {
tr.flush();
ctx.restore();
- // labels
+ // Labels.
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.font = '10px sans-serif';
@@ -473,7 +548,153 @@ cr.define('tracing', function() {
};
+ /**
+ * A track that displays a TimelineCounter object.
+ * @constructor
+ * @extends {CanvasBasedTrack}
+ */
+
+ var TimelineCounterTrack = cr.ui.define(CanvasBasedTrack);
+
+ TimelineCounterTrack.prototype = {
+
+ __proto__: CanvasBasedTrack.prototype,
+
+ decorate: function() {
+ this.classList.add('timeline-counter-track');
+ },
+
+ get counter() {
+ return this.counter_;
+ },
+
+ set counter(counter) {
+ this.counter_ = counter;
+ this.invalidate();
+ },
+
+ redraw: function() {
+ var ctr = this.counter_;
+ var ctx = this.ctx_;
+ var canvasW = this.canvas_.width;
+ var canvasH = this.canvas_.height;
+
+ ctx.clearRect(0, 0, canvasW, canvasH);
+
+ // Culling parametrs.
+ var vp = this.viewport_;
+ var pixWidth = vp.xViewVectorToWorld(1);
+ var viewLWorld = vp.xViewToWorld(0);
+ var viewRWorld = vp.xViewToWorld(canvasW);
+
+ // Drop sampels that are less than skipDistancePix apart.
+ var skipDistancePix = 16;
+ var skipDistanceWorld = vp.xViewVectorToWorld(skipDistancePix);
+
+ // Begin rendering in world space.
+ ctx.save();
+ vp.applyTransformToCanavs(ctx);
+
+ // Figure out where drawing should begin.
+ var numSeries = ctr.numSeries;
+ var numSamples = ctr.numSamples;
+ var startIndex = tracing.findLowIndexInSortedArray(ctr.timestamps,
+ function() {
+ },
+ viewLWorld);
+
+ // Draw indices one by one until we fall off the viewRWorld.
+ var yScale = canvasH / ctr.maxTotal;
+ for (var seriesIndex = ctr.numSeries - 1;
+ seriesIndex >= 0; seriesIndex--) {
+ var colorId = ctr.seriesColors[seriesIndex];
+ ctx.fillStyle = pallette[colorId];
+ ctx.beginPath();
+
+ // Set iLast and xLast such that the first sample we draw is the
+ // startIndex sample.
+ var iLast = startIndex - 1;
+ var xLast = iLast >= 0 ? ctr.timestamps[iLast] - skipDistanceWorld : -1;
+ var yLastView = canvasH;
+
+ // Iterate over samples from iLast onward until we either fall off the
+ // viewRWorld or we run out of samples. To avoid drawing too much, after
+ // drawing a sample at xLast, skip subsequent samples that are less than
+ // skipDistanceWorld from xLast.
+ var hasMoved = false;
+ while (true) {
+ var i = iLast + 1;
+ if (i >= numSamples) {
+ ctx.lineTo(xLast, yLastView);
+ ctx.lineTo(xLast + 8 * pixWidth, yLastView);
+ ctx.lineTo(xLast + 8 * pixWidth, canvasH);
+ break;
+ }
+
+ var x = ctr.timestamps[i];
+
+ var y = ctr.totals[i * numSeries + seriesIndex];
+ var yView = canvasH - (yScale * y);
+
+ if (x > viewRWorld) {
+ ctx.lineTo(x, yLastView);
+ ctx.lineTo(x, canvasH);
+ break;
+ }
+
+ if (x - xLast < skipDistanceWorld) {
+ iLast = i;
+ continue;
+ }
+
+ if (!hasMoved) {
+ ctx.moveTo(viewLWorld, canvasH);
+ hasMoved = true;
+ }
+ ctx.lineTo(x, yLastView);
+ ctx.lineTo(x, yView);
+ iLast = i;
+ xLast = x;
+ yLastView = yView;
+ }
+ ctx.closePath();
+ ctx.fill();
+ }
+ ctx.restore();
+ },
+
+ /**
+ * Picks a slice, if any, at a given location.
+ * @param {number} wX X location to search at, in worldspace.
+ * @param {number} wY Y location to search at, in offset space.
+ * offset space.
+ * @param {function():*} onHitCallback Callback to call with the slice,
+ * if one is found.
+ * @return {boolean} true if a slice was found, otherwise false.
+ */
+ pick: function(wX, wY, onHitCallback) {
+ },
+
+ /**
+ * Finds slices intersecting the given interval.
+ * @param {number} loWX Lower X bound of the interval to search, in
+ * worldspace.
+ * @param {number} hiWX Upper X bound of the interval to search, in
+ * worldspace.
+ * @param {number} loY Lower Y bound of the interval to search, in
+ * offset space.
+ * @param {number} hiY Upper Y bound of the interval to search, in
+ * offset space.
+ * @param {function():*} onHitCallback Function to call for each slice
+ * intersecting the interval.
+ */
+ pickRange: function(loWX, hiWX, loY, hiY, onHitCallback) {
+ }
+
+ };
+
return {
+ TimelineCounterTrack: TimelineCounterTrack,
TimelineSliceTrack: TimelineSliceTrack,
TimelineThreadTrack: TimelineThreadTrack
};

Powered by Google App Engine
This is Rietveld 408576698