diff --git a/src/cargo/core/compiler/timings.js b/src/cargo/core/compiler/timings.js index 00b57e33a3b..46efae9394d 100644 --- a/src/cargo/core/compiler/timings.js +++ b/src/cargo/core/compiler/timings.js @@ -66,7 +66,10 @@ const BG_COLOR = getCssColor('--background'); const CANVAS_BG = getCssColor('--canvas-background'); const AXES_COLOR = getCssColor('--canvas-axes'); const GRID_COLOR = getCssColor('--canvas-grid'); -const BLOCK_COLOR = getCssColor('--canvas-block'); +const CODEGEN_COLOR = getCssColor('--canvas-codegen'); +const LINK_COLOR = getCssColor('--canvas-link'); +// Final leftover section after link +const OTHER_COLOR = getCssColor('--canvas-other'); const CUSTOM_BUILD_COLOR = getCssColor('--canvas-custom-build'); const NOT_CUSTOM_BUILD_COLOR = getCssColor('--canvas-not-custom-build'); const DEP_LINE_COLOR = getCssColor('--canvas-dep-line'); @@ -134,21 +137,40 @@ function render_pipeline_graph() { let unit = units[i]; let y = i * Y_TICK_DIST + 1; let x = px_per_sec * unit.start; - let rmeta_x = null; - if (unit.rmeta_time != null) { - rmeta_x = x + px_per_sec * unit.rmeta_time; + + const sections = []; + if (unit.sections !== null) { + // We have access to compilation sections + for (const section of unit.sections) { + const [name, {start, end}] = section; + sections.push({ + name, + start: x + px_per_sec * start, + width: (end - start) * px_per_sec + }); + } + } + else if (unit.rmeta_time != null) { + // We only know the rmeta time + sections.push({ + name: "codegen", + start: x + px_per_sec * unit.rmeta_time, + width: (unit.duration - unit.rmeta_time) * px_per_sec + }); } let width = Math.max(px_per_sec * unit.duration, 1.0); - UNIT_COORDS[unit.i] = {x, y, width, rmeta_x}; + UNIT_COORDS[unit.i] = {x, y, width, sections}; const count = unitCount.get(unit.name) || 0; unitCount.set(unit.name, count + 1); } + const presentSections = new Set(); + // Draw the blocks. for (i=0; i [string], +// "color": [string], +// "line": [bool] +// } +function 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; + } +} + +// 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; + } } // Draws lines from the given unit to the units it unlocks. @@ -296,47 +422,23 @@ function render_timing_graph() { ctx.restore(); ctx.save(); ctx.translate(canvas_width-200, MARGIN); - // background - ctx.fillStyle = BG_COLOR; - ctx.strokeStyle = TEXT_COLOR; - ctx.lineWidth = 1; - ctx.textBaseline = 'middle' - ctx.textAlign = 'start'; - ctx.beginPath(); - ctx.rect(0, 0, 150, 82); - ctx.stroke(); - ctx.fill(); - - ctx.fillStyle = TEXT_COLOR; - ctx.beginPath(); - ctx.lineWidth = 2; - ctx.strokeStyle = 'red'; - ctx.moveTo(5, 10); - ctx.lineTo(50, 10); - ctx.stroke(); - ctx.fillText('Waiting', 54, 11); - - ctx.beginPath(); - ctx.strokeStyle = 'blue'; - ctx.moveTo(5, 30); - ctx.lineTo(50, 30); - ctx.stroke(); - ctx.fillText('Inactive', 54, 31); - - ctx.beginPath(); - ctx.strokeStyle = 'green'; - ctx.moveTo(5, 50); - ctx.lineTo(50, 50); - ctx.stroke(); - ctx.fillText('Active', 54, 51); - - ctx.beginPath(); - ctx.fillStyle = cpuFillStyle - ctx.fillRect(15, 60, 30, 15); - ctx.fill(); - ctx.fillStyle = TEXT_COLOR; - ctx.fillText('CPU Usage', 54, 71); - + 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(); } diff --git a/src/cargo/core/compiler/timings.rs b/src/cargo/core/compiler/timings.rs index e198b05ac40..4f8b2b82b39 100644 --- a/src/cargo/core/compiler/timings.rs +++ b/src/cargo/core/compiler/timings.rs @@ -191,7 +191,6 @@ impl SectionData { } /// Contains post-processed data of individual compilation sections. -#[derive(serde::Serialize)] enum AggregatedSections { /// We know the names and durations of individual compilation sections Sections(Vec<(String, SectionData)>), @@ -587,6 +586,7 @@ impl<'gctx> Timings<'gctx> { rmeta_time: Option, unlocked_units: Vec, unlocked_rmeta_units: Vec, + sections: Option>, } let round = |x: f64| (x * 100.0).round() / 100.0; let unit_data: Vec = self @@ -600,7 +600,6 @@ impl<'gctx> Timings<'gctx> { "todo" } .to_string(); - // These filter on the unlocked units because not all unlocked // units are actually "built". For example, Doctest mode units // don't actually generate artifacts. @@ -614,6 +613,33 @@ impl<'gctx> Timings<'gctx> { .iter() .filter_map(|unit| unit_map.get(unit).copied()) .collect(); + let aggregated = ut.aggregate_sections(); + let sections = match aggregated { + AggregatedSections::Sections(mut sections) => { + // We draw the sections in the pipeline graph in a way where the frontend + // section has the "default" build color, and then additional sections + // (codegen, link) are overlayed on top with a different color. + // However, there might be some time after the final (usually link) section, + // which definitely shouldn't be classified as "Frontend". We thus try to + // detect this situation and add a final "Other" section. + if let Some((_, section)) = sections.last() + && section.end < ut.duration + { + sections.push(( + "other".to_string(), + SectionData { + start: section.end, + end: ut.duration, + }, + )); + } + + Some(sections) + } + AggregatedSections::OnlyMetadataTime { .. } + | AggregatedSections::OnlyTotalDuration => None, + }; + UnitData { i, name: ut.unit.pkg.name().to_string(), @@ -625,6 +651,7 @@ impl<'gctx> Timings<'gctx> { rmeta_time: ut.rmeta_time.map(round), unlocked_units, unlocked_rmeta_units, + sections, } }) .collect(); @@ -871,7 +898,9 @@ static HTML_TMPL: &str = r#" --canvas-background: #f7f7f7; --canvas-axes: #303030; --canvas-grid: #e6e6e6; - --canvas-block: #aa95e8; + --canvas-codegen: #aa95e8; + --canvas-link: #95e8aa; + --canvas-other: #e895aa; --canvas-custom-build: #f0b165; --canvas-not-custom-build: #95cce8; --canvas-dep-line: #ddd;