diff --git a/src/cargo/core/compiler/timings/report.rs b/src/cargo/core/compiler/timings/report.rs index 40badbec4e1..9cd7d96ad3f 100644 --- a/src/cargo/core/compiler/timings/report.rs +++ b/src/cargo/core/compiler/timings/report.rs @@ -751,7 +751,6 @@ static HTML_CANVAS: &str = r#" - Renderer: @@ -761,16 +760,6 @@ static HTML_CANVAS: &str = r#" based on the client viewport. --> - - - - @@ -779,13 +768,6 @@ static HTML_CANVAS: &str = r#" -
- - -
-
- -
-
-
+
+
"#; diff --git a/src/cargo/core/compiler/timings/timings.js b/src/cargo/core/compiler/timings/timings.js index 20cf81983e4..2e88d88750c 100644 --- a/src/cargo/core/compiler/timings/timings.js +++ b/src/cargo/core/compiler/timings/timings.js @@ -120,400 +120,6 @@ function compute_unit_coords(units, px_per_sec) { return { UNIT_COORDS, unitCount } } -class CanvasRenderer { - constructor() {} - - render_pipeline_graph() { - if (UNIT_DATA.length == 0) { - return; - } - let g = document.getElementById('pipeline-graph'); - HIT_BOXES.length = 0; - g.onmousemove = this._pipeline_mousemove.bind(this); - const min_time = document.getElementById('min-unit-time').valueAsNumber; - - const units = UNIT_DATA.filter(unit => unit.duration >= min_time); - - const graph_height = Y_TICK_DIST * units.length; - const { ctx, canvas_width, canvas_height, px_per_sec } = this._draw_graph_axes('pipeline-graph', graph_height); - const container = document.getElementById('pipeline-container'); - container.style.width = canvas_width; - container.style.height = canvas_height; - - // Canvas for hover highlights. This is a separate layer to improve performance. - const linectx = this._setup_canvas('pipeline-graph-lines', canvas_width, canvas_height); - linectx.clearRect(0, 0, canvas_width, canvas_height); - ctx.strokeStyle = AXES_COLOR; - // Draw Y tick marks. - for (let n = 1; n < units.length; n++) { - const y = MARGIN + Y_TICK_DIST * n; - ctx.beginPath(); - ctx.moveTo(X_LINE, y); - ctx.lineTo(X_LINE - 5, y); - ctx.stroke(); - } - - // Draw Y labels. - ctx.textAlign = 'end'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = AXES_COLOR; - for (let n = 0; n < units.length; n++) { - let y = MARGIN + Y_TICK_DIST * n + Y_TICK_DIST / 2; - ctx.fillText(n + 1, X_LINE - 4, y); - } - - // Draw the graph. - ctx.save(); - ctx.translate(X_LINE, MARGIN); - - const { UNIT_COORDS, unitCount } = compute_unit_coords(units, px_per_sec); - const presentSections = new Set(); - - // Draw the blocks. - for (let i = 0; i < units.length; i++) { - let unit = units[i]; - let { x, y, width, sections } = UNIT_COORDS[unit.i]; - - HIT_BOXES.push({ x: X_LINE + x, y: MARGIN + y, x2: X_LINE + x + width, y2: MARGIN + y + BOX_HEIGHT, i: unit.i }); - - ctx.beginPath(); - ctx.fillStyle = unit.mode == 'run-custom-build' ? CUSTOM_BUILD_COLOR : NOT_CUSTOM_BUILD_COLOR; - this._roundedRect(ctx, x, y, width, BOX_HEIGHT, RADIUS); - ctx.fill(); - - for (const section of sections) { - ctx.beginPath(); - ctx.fillStyle = get_section_color(section.name); - this._roundedRect(ctx, section.start, y, section.width, BOX_HEIGHT, RADIUS); - ctx.fill(); - presentSections.add(section.name); - } - ctx.fillStyle = TEXT_COLOR; - ctx.textAlign = 'start'; - ctx.textBaseline = 'middle'; - ctx.font = '14px sans-serif'; - - const labelName = (unitCount.get(unit.name) || 0) > 1 ? `${unit.name} (v${unit.version})${unit.target}` : `${unit.name}${unit.target}`; - const label = `${labelName}: ${unit.duration}s`; - - const text_info = ctx.measureText(label); - const label_x = Math.min(x + 5.0, canvas_width - text_info.width - X_LINE); - ctx.fillText(label, label_x, y + BOX_HEIGHT / 2); - this._draw_dep_lines(ctx, unit.i, false); - } - ctx.restore(); - - // Draw a legend. - ctx.save(); - ctx.translate(canvas_width - 200, MARGIN); - - const legend_entries = get_legend_entries(presentSections); - this._draw_legend(ctx, 160, legend_entries); - ctx.restore(); - } - - // Draw a legend at the current position of the ctx. - // entries should be an array of objects with the following scheme: - // { - // "name": [string], - // "color": [string], - // "line": [bool] - // } - _draw_legend(ctx, width, entries) { - const entry_height = 20; - - // Add a bit of margin to the bottom and top - const height = entries.length * entry_height + 4; - - // Draw background - ctx.fillStyle = BG_COLOR; - ctx.strokeStyle = TEXT_COLOR; - ctx.lineWidth = 1; - ctx.textBaseline = 'middle'; - ctx.textAlign = 'start'; - ctx.beginPath(); - ctx.rect(0, 0, width, height); - ctx.stroke(); - ctx.fill(); - - ctx.lineWidth = 2; - - // Dimension of a block - const block_height = 15; - const block_width = 30; - - // Margin from the left edge - const x_start = 5; - // Width of the "mark" section (line/block) - const mark_width = 45; - - // Draw legend entries - let y = 12; - for (const entry of entries) { - ctx.beginPath(); - - if (entry.line) { - ctx.strokeStyle = entry.color; - ctx.moveTo(x_start, y); - ctx.lineTo(x_start + mark_width, y); - ctx.stroke(); - } else { - ctx.fillStyle = entry.color; - ctx.fillRect(x_start + (mark_width - block_width) / 2, y - (block_height / 2), block_width, block_height); - } - - ctx.fillStyle = TEXT_COLOR; - ctx.fillText(entry.name, x_start + mark_width + 4, y + 1); - - y += entry_height; - } - } - - // Draws lines from the given unit to the units it unlocks. - _draw_dep_lines(ctx, unit_idx, highlighted) { - const unit = UNIT_BY_INDEX[unit_idx]; - const { x, y, sections } = UNIT_COORDS[unit_idx]; - ctx.save(); - for (const unblocked of unit.unblocked_units) { - this._draw_one_dep_line(ctx, x, y, unblocked, highlighted); - } - for (const unblocked of unit.unblocked_rmeta_units) { - const codegen_x = get_codegen_section_x(sections); - this._draw_one_dep_line(ctx, codegen_x, y, unblocked, highlighted); - } - ctx.restore(); - } - - _draw_one_dep_line(ctx, from_x, from_y, to_unit, highlighted) { - if (to_unit in UNIT_COORDS) { - let { x: u_x, y: u_y } = UNIT_COORDS[to_unit]; - ctx.strokeStyle = highlighted ? DEP_LINE_HIGHLIGHTED_COLOR : DEP_LINE_COLOR; - ctx.setLineDash([2]); - ctx.beginPath(); - ctx.moveTo(from_x, from_y + BOX_HEIGHT / 2); - ctx.lineTo(from_x - 5, from_y + BOX_HEIGHT / 2); - ctx.lineTo(from_x - 5, u_y + BOX_HEIGHT / 2); - ctx.lineTo(u_x, u_y + BOX_HEIGHT / 2); - ctx.stroke(); - } - } - - render_timing_graph() { - if (CONCURRENCY_DATA.length == 0) { - return; - } - const HEIGHT = 400; - const AXIS_HEIGHT = HEIGHT - MARGIN - Y_LINE; - const TOP_MARGIN = 10; - const GRAPH_HEIGHT = AXIS_HEIGHT - TOP_MARGIN; - - const { canvas_width, graph_width, ctx } = this._draw_graph_axes('timing-graph', AXIS_HEIGHT); - - // Draw Y tick marks and labels. - let max_v = 0; - for (let c of CONCURRENCY_DATA) { - max_v = Math.max(max_v, c.active, c.waiting, c.inactive); - } - const px_per_v = GRAPH_HEIGHT / max_v; - const { step, tick_dist, num_ticks } = split_ticks(max_v, px_per_v, GRAPH_HEIGHT); - ctx.textAlign = 'end'; - for (let n = 0; n < num_ticks; n++) { - let y = HEIGHT - Y_LINE - ((n + 1) * tick_dist); - ctx.beginPath(); - ctx.moveTo(X_LINE, y); - ctx.lineTo(X_LINE - 5, y); - ctx.stroke(); - ctx.fillText((n + 1) * step, X_LINE - 10, y + 5); - } - - // Label the Y axis. - let label_y = (HEIGHT - Y_LINE) / 2; - ctx.save(); - ctx.translate(15, label_y); - ctx.rotate(3 * Math.PI / 2); - ctx.textAlign = 'center'; - ctx.fillText('# Units', 0, 0); - ctx.restore(); - - // Draw the graph. - ctx.save(); - ctx.translate(X_LINE, MARGIN); - - function coord(t, v) { - return { - x: graph_width * (t / DURATION), - y: TOP_MARGIN + GRAPH_HEIGHT * (1.0 - (v / max_v)) - }; - } - - const cpuFillStyle = CPU_COLOR; - if (CPU_USAGE.length > 1) { - ctx.beginPath(); - ctx.fillStyle = cpuFillStyle; - let bottomLeft = coord(CPU_USAGE[0][0], 0); - ctx.moveTo(bottomLeft.x, bottomLeft.y); - for (let i = 0; i < CPU_USAGE.length; i++) { - let [time, usage] = CPU_USAGE[i]; - let { x, y } = coord(time, usage / 100.0 * max_v); - ctx.lineTo(x, y); - } - let bottomRight = coord(CPU_USAGE[CPU_USAGE.length - 1][0], 0); - ctx.lineTo(bottomRight.x, bottomRight.y); - ctx.fill(); - } - - function draw_line(style, key) { - let first = CONCURRENCY_DATA[0]; - let last = coord(first.t, key(first)); - ctx.strokeStyle = style; - ctx.beginPath(); - ctx.moveTo(last.x, last.y); - for (let i = 1; i < CONCURRENCY_DATA.length; i++) { - let c = CONCURRENCY_DATA[i]; - let { x, y } = coord(c.t, key(c)); - ctx.lineTo(x, last.y); - ctx.lineTo(x, y); - last = { x, y }; - } - ctx.stroke(); - } - - draw_line('blue', function(c) { return c.inactive; }); - draw_line('red', function(c) { return c.waiting; }); - draw_line('green', function(c) { return c.active; }); - - // Draw a legend. - ctx.restore(); - ctx.save(); - ctx.translate(canvas_width - 200, MARGIN); - this._draw_legend(ctx, 150, [{ - name: "Waiting", - color: "red", - line: true - }, { - name: "Inactive", - color: "blue", - line: true - }, { - name: "Active", - color: "green", - line: true - }, { - name: "CPU Usage", - color: cpuFillStyle, - line: false - }]); - ctx.restore(); - } - - _setup_canvas(id, width, height) { - let g = document.getElementById(id); - let dpr = window.devicePixelRatio || 1; - g.width = width * dpr; - g.height = height * dpr; - g.style.width = width; - g.style.height = height; - let ctx = g.getContext('2d'); - ctx.scale(dpr, dpr); - return ctx; - } - - _draw_graph_axes(id, graph_height) { - let { canvas_height, canvas_width, graph_width, px_per_sec } = graph_dimension(graph_height); - let ctx = this._setup_canvas(id, canvas_width, canvas_height); - ctx.fillStyle = CANVAS_BG; - ctx.fillRect(0, 0, canvas_width, canvas_height); - - ctx.lineWidth = 2; - ctx.font = '16px sans-serif'; - ctx.textAlign = 'center'; - ctx.strokeStyle = AXES_COLOR; - - // Draw main axes. - ctx.beginPath(); - ctx.moveTo(X_LINE, MARGIN); - ctx.lineTo(X_LINE, graph_height + MARGIN); - ctx.lineTo(X_LINE + graph_width + 20, graph_height + MARGIN); - ctx.stroke(); - - // Draw X tick marks. - const { step, tick_dist, num_ticks } = split_ticks(DURATION, px_per_sec, graph_width); - ctx.fillStyle = AXES_COLOR; - for (let n = 0; n < num_ticks; n++) { - const x = X_LINE + ((n + 1) * tick_dist); - ctx.beginPath(); - ctx.moveTo(x, canvas_height - Y_LINE); - ctx.lineTo(x, canvas_height - Y_LINE + 5); - ctx.stroke(); - - ctx.fillText(`${(n + 1) * step}s`, x, canvas_height - Y_LINE + 20); - } - - // Draw vertical lines. - ctx.strokeStyle = GRID_COLOR; - ctx.setLineDash([2, 4]); - for (let n = 0; n < num_ticks; n++) { - const x = X_LINE + ((n + 1) * tick_dist); - ctx.beginPath(); - ctx.moveTo(x, MARGIN); - ctx.lineTo(x, MARGIN + graph_height); - ctx.stroke(); - } - ctx.strokeStyle = TEXT_COLOR; - ctx.setLineDash([]); - return { canvas_width, canvas_height, graph_width, graph_height, ctx, px_per_sec }; - } - - _roundedRect(ctx, x, y, width, height, r) { - r = Math.min(r, width, height); - ctx.beginPath(); - ctx.moveTo(x + r, y); - ctx.lineTo(x + width - r, y); - ctx.arc(x + width - r, y + r, r, 3 * Math.PI / 2, 0); - ctx.lineTo(x + width, y + height - r); - ctx.arc(x + width - r, y + height - r, r, 0, Math.PI / 2); - ctx.lineTo(x + r, y + height); - ctx.arc(x + r, y + height - r, r, Math.PI / 2, Math.PI); - ctx.lineTo(x, y - r); - ctx.arc(x + r, y + r, r, Math.PI, 3 * Math.PI / 2); - ctx.closePath(); - } - - _pipeline_mousemove(event) { - // Highlight dependency lines on mouse hover. - let box = pipeline_mouse_hit(event); - if (box) { - if (box.i != LAST_HOVER) { - LAST_HOVER = box.i; - let g = document.getElementById('pipeline-graph-lines'); - let ctx = g.getContext('2d'); - ctx.clearRect(0, 0, g.width, g.height); - ctx.save(); - ctx.translate(X_LINE, MARGIN); - ctx.lineWidth = 2; - this._draw_dep_lines(ctx, box.i, true); - - if (box.i in REVERSE_UNIT_DEPS) { - const dep_unit = REVERSE_UNIT_DEPS[box.i]; - if (dep_unit in UNIT_COORDS) { - const { x, y } = UNIT_COORDS[dep_unit]; - this._draw_one_dep_line(ctx, x, y, box.i, true); - } - } - if (box.i in REVERSE_UNIT_RMETA_DEPS) { - const dep_unit = REVERSE_UNIT_RMETA_DEPS[box.i]; - if (dep_unit in UNIT_COORDS) { - const { y, sections } = UNIT_COORDS[dep_unit]; - const codegen_x = get_codegen_section_x(sections); - this._draw_one_dep_line(ctx, codegen_x, y, box.i, true); - } - } - ctx.restore(); - } - } - } -} - class SvgRenderer { constructor() {} @@ -599,7 +205,7 @@ class SvgRenderer { ${this._draw_legend(160, get_legend_entries(presentSections))} `; - const svg_container = document.getElementById("pipeline-container-svg"); + const svg_container = document.getElementById("pipeline-container"); if (svg_container) { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", canvas_width); @@ -861,7 +467,7 @@ ${this._draw_legend(150, [{ }])} `; - const svg_container = document.getElementById("timing-container-svg"); + const svg_container = document.getElementById("timing-container"); if (svg_container) { const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svg.setAttribute("width", canvas_width); @@ -978,20 +584,6 @@ function measure_text_width(text) { return text_info.width; } -// Determine the color of a section block based on the section name. -function get_section_color(name) { - if (name === "codegen") { - return CODEGEN_COLOR; - } else if (name === "link") { - return LINK_COLOR; - } else if (name === "other") { - return OTHER_COLOR; - } else { - // We do not know what section this is, so just use the default color - return NOT_CUSTOM_BUILD_COLOR; - } -} - // Gets the x-coordinate of the codegen section of a unit. // // This is for drawing rmeta dependency lines. @@ -1098,35 +690,7 @@ function hl(i) { } } -function pipeline_mouse_hit(event) { - // This brute-force method can be optimized if needed. - for (let box of HIT_BOXES) { - if (event.offsetX >= box.x && event.offsetX <= box.x2 && - event.offsetY >= box.y && event.offsetY <= box.y2) { - return box; - } - } -} - -const _RENDERER = { canvas: null, svg: null }; - -function setupRenderer(name) { - // Get or init the selected renderer - const r = name === "canvas" ? - _RENDERER[name] || (_RENDERER[name] = new CanvasRenderer()) : - _RENDERER[name] || (_RENDERER[name] = new SvgRenderer()); - // Toggle visibility - Array.from(document.querySelectorAll(`.canvas-container`)) - .map(function(el) { - return { el, op: el.getAttribute("part") === name ? "remove" : "add" }; - }).forEach(function(entry) { - const { el, op } = entry; - el.classList[op]("hidden"); - }) - return r -} - -let renderer = setupRenderer(document.querySelector("input[name='renderer']:checked").value); +let renderer = new SvgRenderer(); try { renderer.render_pipeline_graph(); renderer.render_timing_graph();