profview: Improve behavior when given a log with few ticks.

Previously, when given a log with few ticks, the timeline would lump
them all into one or two buckets. This patch allows ticks to be assigned
to buckets more sparsely.

This patch also fixes a bug where there was a gap on the right side of
the timeline, which also caused the function tick marks to be slightly
misaligned. This was more noticable with fewer buckets.

Bug: v8:6240
Change-Id: Ib7353c0420caec8591590815271d329ea1a030fb
Reviewed-on: https://chromium-review.googlesource.com/1174440
Commit-Queue: Bret Sepulveda <bsep@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55125}
This commit is contained in:
Bret Sepulveda 2018-08-14 14:51:12 +02:00 committed by Commit Bot
parent 87eedbc132
commit 6fcf0a0e3d

View File

@ -809,7 +809,6 @@ class TimelineView {
return; return;
} }
this.currentState = newState;
if (oldState) { if (oldState) {
if (newState.timeLine.width === oldState.timeLine.width && if (newState.timeLine.width === oldState.timeLine.width &&
newState.timeLine.height === oldState.timeLine.height && newState.timeLine.height === oldState.timeLine.height &&
@ -821,21 +820,27 @@ class TimelineView {
return; return;
} }
} }
this.currentState = newState;
this.element.style.display = "inherit"; this.element.style.display = "inherit";
// Make sure the canvas has the right dimensions. let file = this.currentState.file;
let width = this.currentState.timeLine.width; let width = this.currentState.timeLine.width;
let height = this.currentState.timeLine.height; let height = this.currentState.timeLine.height;
const minPixelsPerBucket = 10;
const minTicksPerBucket = 8;
let maxBuckets = Math.round(file.ticks.length / minTicksPerBucket);
let bucketCount = Math.min(
Math.round(width / minPixelsPerBucket), maxBuckets);
// Make sure the canvas has the right dimensions.
this.canvas.width = width; this.canvas.width = width;
this.canvas.height = height; this.canvas.height = height;
// Make space for the selection text. // Make space for the selection text.
height -= this.imageOffset; height -= this.imageOffset;
let file = this.currentState.file;
if (!file) return;
let currentCodeId = this.currentState.currentCodeId; let currentCodeId = this.currentState.currentCodeId;
let firstTime = file.ticks[0].tm; let firstTime = file.ticks[0].tm;
@ -846,13 +851,6 @@ class TimelineView {
this.selectionStart = (start - firstTime) / (lastTime - firstTime) * width; this.selectionStart = (start - firstTime) / (lastTime - firstTime) * width;
this.selectionEnd = (end - firstTime) / (lastTime - firstTime) * width; this.selectionEnd = (end - firstTime) / (lastTime - firstTime) * width;
let tickCount = file.ticks.length;
let minBucketPixels = 10;
let minBucketSamples = 30;
let bucketCount = Math.min(width / minBucketPixels,
tickCount / minBucketSamples);
let stackProcessor = new CategorySampler(file, bucketCount); let stackProcessor = new CategorySampler(file, bucketCount);
generateTree(file, 0, Infinity, stackProcessor); generateTree(file, 0, Infinity, stackProcessor);
let codeIdProcessor = new FunctionTimelineProcessor( let codeIdProcessor = new FunctionTimelineProcessor(
@ -873,28 +871,36 @@ class TimelineView {
let sum = 0; let sum = 0;
let bucketData = []; let bucketData = [];
let total = buckets[i].total; let total = buckets[i].total;
for (let j = 0; j < bucketDescriptors.length; j++) { if (total > 0) {
let desc = bucketDescriptors[j]; for (let j = 0; j < bucketDescriptors.length; j++) {
for (let k = 0; k < desc.kinds.length; k++) { let desc = bucketDescriptors[j];
sum += buckets[i][desc.kinds[k]]; for (let k = 0; k < desc.kinds.length; k++) {
sum += buckets[i][desc.kinds[k]];
}
bucketData.push(Math.round(graphHeight * sum / total));
}
} else {
// No ticks fell into this bucket. Fill with "Unknown."
for (let j = 0; j < bucketDescriptors.length; j++) {
let desc = bucketDescriptors[j];
bucketData.push(desc.text === "Unknown" ? graphHeight : 0);
} }
bucketData.push(Math.round(graphHeight * sum / total));
} }
bucketsGraph.push(bucketData); bucketsGraph.push(bucketData);
} }
// Draw the category graph into the buffer. // Draw the category graph into the buffer.
let bucketWidth = width / bucketsGraph.length; let bucketWidth = width / (bucketsGraph.length - 1);
let ctx = buffer.getContext('2d'); let ctx = buffer.getContext('2d');
for (let i = 0; i < bucketsGraph.length - 1; i++) { for (let i = 0; i < bucketsGraph.length - 1; i++) {
let bucketData = bucketsGraph[i]; let bucketData = bucketsGraph[i];
let nextBucketData = bucketsGraph[i + 1]; let nextBucketData = bucketsGraph[i + 1];
let x1 = Math.round(i * bucketWidth);
let x2 = Math.round((i + 1) * bucketWidth);
for (let j = 0; j < bucketData.length; j++) { for (let j = 0; j < bucketData.length; j++) {
let x1 = Math.round(i * bucketWidth);
let x2 = Math.round((i + 1) * bucketWidth);
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(x1, j && bucketData[j - 1]); ctx.moveTo(x1, j > 0 ? bucketData[j - 1] : 0);
ctx.lineTo(x2, j && nextBucketData[j - 1]); ctx.lineTo(x2, j > 0 ? nextBucketData[j - 1] : 0);
ctx.lineTo(x2, nextBucketData[j]); ctx.lineTo(x2, nextBucketData[j]);
ctx.lineTo(x1, bucketData[j]); ctx.lineTo(x1, bucketData[j]);
ctx.closePath(); ctx.closePath();