Skip to content

Commit 73d8d2d

Browse files
committed
Auto merge of #7397 - ehuss:fix-timing-scale, r=alexcrichton
Fix some rendering issues with -Ztimings. - Cap the max width to 4096. This is still quite large, but should help for some large graphs failing to display for using too much memory. - Don't allow labels to overflow past the right side of the graph. - Fix issue for very fast builds causing an error because there aren't enough CPU_USAGE entries. - Fix bug where `split_ticks` would enter an infinite loop (caused by small scale values). Added a counter to abort in case there are any other bugs. Closes #7392 Closes #7388
2 parents 2fd180f + e6c5758 commit 73d8d2d

File tree

1 file changed

+51
-37
lines changed

1 file changed

+51
-37
lines changed

src/cargo/core/compiler/timings.js

Lines changed: 51 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,14 @@ function render_pipeline_graph() {
4444
const units = UNIT_DATA.filter(unit => unit.duration >= min_time);
4545

4646
const graph_height = Y_TICK_DIST * units.length;
47-
const {ctx, width, height} = draw_graph_axes('pipeline-graph', graph_height);
47+
const {ctx, graph_width, canvas_width, canvas_height, px_per_sec} = draw_graph_axes('pipeline-graph', graph_height);
4848
const container = document.getElementById('pipeline-container');
49-
container.style.width = width;
50-
container.style.height = height;
51-
const PX_PER_SEC = document.getElementById('scale').valueAsNumber;
49+
container.style.width = canvas_width;
50+
container.style.height = canvas_height;
5251

5352
// Canvas for hover highlights. This is a separate layer to improve performance.
54-
const linectx = setup_canvas('pipeline-graph-lines', width, height);
55-
linectx.clearRect(0, 0, width, height);
53+
const linectx = setup_canvas('pipeline-graph-lines', canvas_width, canvas_height);
54+
linectx.clearRect(0, 0, canvas_width, canvas_height);
5655

5756
// Draw Y tick marks.
5857
for (let n=1; n<units.length; n++) {
@@ -79,12 +78,12 @@ function render_pipeline_graph() {
7978
for (i=0; i<units.length; i++) {
8079
let unit = units[i];
8180
let y = i * Y_TICK_DIST + 1;
82-
let x = PX_PER_SEC * unit.start;
81+
let x = px_per_sec * unit.start;
8382
let rmeta_x = null;
8483
if (unit.rmeta_time != null) {
85-
rmeta_x = x + PX_PER_SEC * unit.rmeta_time;
84+
rmeta_x = x + px_per_sec * unit.rmeta_time;
8685
}
87-
let width = Math.max(PX_PER_SEC * unit.duration, 1.0);
86+
let width = Math.max(px_per_sec * unit.duration, 1.0);
8887
UNIT_COORDS[unit.i] = {x, y, width, rmeta_x};
8988
}
9089

@@ -104,14 +103,17 @@ function render_pipeline_graph() {
104103
ctx.beginPath();
105104
ctx.fillStyle = '#aa95e8';
106105
let ctime = unit.duration - unit.rmeta_time;
107-
roundedRect(ctx, rmeta_x, y, PX_PER_SEC * ctime, BOX_HEIGHT, RADIUS);
106+
roundedRect(ctx, rmeta_x, y, px_per_sec * ctime, BOX_HEIGHT, RADIUS);
108107
ctx.fill();
109108
}
110109
ctx.fillStyle = "#000";
111110
ctx.textAlign = 'start';
112111
ctx.textBaseline = 'hanging';
113112
ctx.font = '14px sans-serif';
114-
ctx.fillText(`${unit.name}${unit.target} ${unit.duration}s`, x + 5.0, y + BOX_HEIGHT / 2 - 6);
113+
const label = `${unit.name}${unit.target} ${unit.duration}s`;
114+
const text_info = ctx.measureText(label);
115+
const label_x = Math.min(x + 5.0, canvas_width - text_info.width - X_LINE);
116+
ctx.fillText(label, label_x, y + BOX_HEIGHT / 2 - 6);
115117
draw_dep_lines(ctx, unit.i, false);
116118
}
117119
ctx.restore();
@@ -154,7 +156,7 @@ function render_timing_graph() {
154156
const TOP_MARGIN = 10;
155157
const GRAPH_HEIGHT = AXIS_HEIGHT - TOP_MARGIN;
156158

157-
const {graph_width, ctx} = draw_graph_axes('timing-graph', AXIS_HEIGHT);
159+
const {canvas_width, graph_width, ctx} = draw_graph_axes('timing-graph', AXIS_HEIGHT);
158160

159161
// Draw Y tick marks and labels.
160162
let max_v = 0;
@@ -195,18 +197,20 @@ function render_timing_graph() {
195197
}
196198

197199
const cpuFillStyle = 'rgba(250, 119, 0, 0.2)';
198-
ctx.beginPath();
199-
ctx.fillStyle = cpuFillStyle;
200-
let bottomLeft = coord(CPU_USAGE[0][0], 0);
201-
ctx.moveTo(bottomLeft.x, bottomLeft.y);
202-
for (let i=0; i < CPU_USAGE.length; i++) {
203-
let [time, usage] = CPU_USAGE[i];
204-
let {x, y} = coord(time, usage / 100.0 * max_v);
205-
ctx.lineTo(x, y);
200+
if (CPU_USAGE.length > 1) {
201+
ctx.beginPath();
202+
ctx.fillStyle = cpuFillStyle;
203+
let bottomLeft = coord(CPU_USAGE[0][0], 0);
204+
ctx.moveTo(bottomLeft.x, bottomLeft.y);
205+
for (let i=0; i < CPU_USAGE.length; i++) {
206+
let [time, usage] = CPU_USAGE[i];
207+
let {x, y} = coord(time, usage / 100.0 * max_v);
208+
ctx.lineTo(x, y);
209+
}
210+
let bottomRight = coord(CPU_USAGE[CPU_USAGE.length - 1][0], 0);
211+
ctx.lineTo(bottomRight.x, bottomRight.y);
212+
ctx.fill();
206213
}
207-
let bottomRight = coord(CPU_USAGE[CPU_USAGE.length - 1][0], 0);
208-
ctx.lineTo(bottomRight.x, bottomRight.y);
209-
ctx.fill();
210214

211215
function draw_line(style, key) {
212216
let first = CONCURRENCY_DATA[0];
@@ -231,7 +235,7 @@ function render_timing_graph() {
231235
// Draw a legend.
232236
ctx.restore();
233237
ctx.save();
234-
ctx.translate(graph_width-150, MARGIN);
238+
ctx.translate(canvas_width-200, MARGIN);
235239
// background
236240
ctx.fillStyle = '#fff';
237241
ctx.strokeStyle = '#000';
@@ -289,13 +293,18 @@ function setup_canvas(id, width, height) {
289293
}
290294

291295
function draw_graph_axes(id, graph_height) {
292-
const PX_PER_SEC = document.getElementById('scale').valueAsNumber;
293-
const graph_width = PX_PER_SEC * DURATION;
294-
const width = graph_width + X_LINE + 30;
295-
const height = graph_height + MARGIN + Y_LINE;
296-
let ctx = setup_canvas(id, width, height);
296+
const scale = document.getElementById('scale').valueAsNumber;
297+
// Cap the size of the graph. It is hard to view if it is too large, and
298+
// browsers may not render a large graph because it takes too much memory.
299+
// 4096 is still ridiculously large, and probably won't render on mobile
300+
// browsers, but should be ok for many desktop environments.
301+
const graph_width = Math.min(scale * DURATION, 4096);
302+
const px_per_sec = Math.floor(graph_width / DURATION);
303+
const canvas_width = Math.max(graph_width + X_LINE + 30, X_LINE + 250);
304+
const canvas_height = graph_height + MARGIN + Y_LINE;
305+
let ctx = setup_canvas(id, canvas_width, canvas_height);
297306
ctx.fillStyle = '#f7f7f7';
298-
ctx.fillRect(0, 0, width, height);
307+
ctx.fillRect(0, 0, canvas_width, canvas_height);
299308

300309
ctx.lineWidth = 2;
301310
ctx.font = '16px sans-serif';
@@ -309,19 +318,18 @@ function draw_graph_axes(id, graph_height) {
309318
ctx.stroke();
310319

311320
// Draw X tick marks.
312-
const tick_width = graph_width - 10;
313-
const [step, top] = split_ticks(DURATION, tick_width / MIN_TICK_DIST);
321+
const [step, top] = split_ticks(DURATION, graph_width / MIN_TICK_DIST);
314322
const num_ticks = top / step;
315-
const tick_dist = tick_width / num_ticks;
323+
const tick_dist = graph_width / num_ticks;
316324
ctx.fillStyle = '#303030';
317325
for (let n=0; n<num_ticks; n++) {
318326
const x = X_LINE + ((n + 1) * tick_dist);
319327
ctx.beginPath();
320-
ctx.moveTo(x, height-Y_LINE);
321-
ctx.lineTo(x, height-Y_LINE+5);
328+
ctx.moveTo(x, canvas_height-Y_LINE);
329+
ctx.lineTo(x, canvas_height-Y_LINE+5);
322330
ctx.stroke();
323331

324-
ctx.fillText(`${(n+1) * step}s`, x, height - Y_LINE + 20);
332+
ctx.fillText(`${(n+1) * step}s`, x, canvas_height - Y_LINE + 20);
325333
}
326334

327335
// Draw vertical lines.
@@ -336,7 +344,7 @@ function draw_graph_axes(id, graph_height) {
336344
}
337345
ctx.strokeStyle = '#000';
338346
ctx.setLineDash([]);
339-
return {width, height, graph_width, graph_height, ctx};
347+
return {canvas_width, canvas_height, graph_width, graph_height, ctx, px_per_sec};
340348
}
341349

342350
function round_up(n, step) {
@@ -349,6 +357,7 @@ function round_up(n, step) {
349357

350358
// Determine the `(step, max_value)` of the number of ticks along an axis.
351359
function split_ticks(n, max_ticks) {
360+
max_ticks = Math.ceil(max_ticks);
352361
if (n <= max_ticks) {
353362
return [1, n];
354363
} else if (n <= max_ticks * 2) {
@@ -359,7 +368,12 @@ function split_ticks(n, max_ticks) {
359368
return [5, round_up(n, 5)];
360369
} else {
361370
let step = 10;
371+
let count = 0;
362372
while (true) {
373+
if (count > 100) {
374+
throw Error("tick loop too long");
375+
}
376+
count += 1;
363377
let top = round_up(n, step);
364378
if (top <= max_ticks * step) {
365379
return [step, top];

0 commit comments

Comments
 (0)