diff --git a/Cargo.lock b/Cargo.lock index 2438fcb9bb..63b7972de5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1198,6 +1198,7 @@ name = "enso-profiler-metadata" version = "0.1.0" dependencies = [ "enso-profiler", + "ensogl-core", "serde", ] @@ -2478,6 +2479,7 @@ version = "0.1.0" dependencies = [ "enso-prelude", "enso-profiler", + "enso-profiler-data", "enso-shapely", "enso-web", "failure", diff --git a/app/gui/enso-profiler-metadata/Cargo.toml b/app/gui/enso-profiler-metadata/Cargo.toml index cc4c56ecb2..e1b559f4e9 100644 --- a/app/gui/enso-profiler-metadata/Cargo.toml +++ b/app/gui/enso-profiler-metadata/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +ensogl-core = { path = "../../../lib/rust/ensogl/core"} enso-profiler = { path = "../../../lib/rust/profiler"} serde = { version = "1" } diff --git a/app/gui/enso-profiler-metadata/src/lib.rs b/app/gui/enso-profiler-metadata/src/lib.rs index b66a716c76..246232b663 100644 --- a/app/gui/enso-profiler-metadata/src/lib.rs +++ b/app/gui/enso-profiler-metadata/src/lib.rs @@ -10,16 +10,19 @@ use std::fmt::Formatter; // ================ /// Metadata that is logged within the Enso core libraries. -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Eq, PartialEq)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum Metadata { /// An RPC event that was received from the backend. RpcEvent(String), + /// Performance stats gathered from the EnsoGL rendering engine. + RenderStats(ensogl_core::debug::StatsData), } impl Display for Metadata { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Metadata::RpcEvent(name) => f.collect_str(name), + Metadata::RenderStats(stats) => f.collect_str(&format!("{:#?}", stats)), } } } diff --git a/app/gui/src/model/project/synchronized.rs b/app/gui/src/model/project/synchronized.rs index 5ac4cb8f48..d04fd3ba4e 100644 --- a/app/gui/src/model/project/synchronized.rs +++ b/app/gui/src/model/project/synchronized.rs @@ -33,7 +33,7 @@ use parser::Parser; // ================= thread_local! { - /// A common preamble used to start every shader program. + /// Profiling metadata logger for RPC event names.. static RPC_EVENT_LOGGER: enso_profiler::MetadataLogger<& 'static str> = enso_profiler::MetadataLogger::new("RpcEvent"); } diff --git a/build/run.js b/build/run.js index 0fffea70d7..60ef860ef5 100755 --- a/build/run.js +++ b/build/run.js @@ -198,7 +198,7 @@ commands.build.rust = async function (argv) { console.log('Minimizing the WASM binary.') await gzip(paths.wasm.main, paths.wasm.mainGz) - const limitMb = 4.05 + const limitMb = 4.06 await checkWasmSize(paths.wasm.mainGz, limitMb) } // Copy WASM files from temporary directory to Webpack's `dist` directory. diff --git a/lib/rust/ensogl/component/flame-graph/src/lib.rs b/lib/rust/ensogl/component/flame-graph/src/lib.rs index e5b30c94e3..fe38178a19 100644 --- a/lib/rust/ensogl/component/flame-graph/src/lib.rs +++ b/lib/rust/ensogl/component/flame-graph/src/lib.rs @@ -24,12 +24,14 @@ use ensogl_core::display; mod block; mod mark; -use enso_profiler_flame_graph::State; +use enso_profiler_flame_graph::Activity; +use enso_profiler_flame_graph::Performance; use ensogl_core::data::color; use ensogl_core::display::shape::StyleWatchFrp; -use mark::Mark; +use ensogl_core::display::style; pub use block::Block; +pub use mark::Mark; @@ -43,6 +45,61 @@ pub(crate) const BASE_TEXT_SIZE: f32 = 18.0; +// ============== +// === Colors === +// ============== + +/// Theme path for the color of an activity block that is active. +pub const COLOR_BLOCK_ACTIVE: &str = "flame_graph_block_color_active"; +/// Theme path for the color of an activity block that is paused. +pub const COLOR_BLOCK_PAUSED: &str = "flame_graph_block_color_paused"; + +/// Theme path for the color of a performance block that indicates good performance. +pub const COLOR_PERFORMANCE_GOOD: &str = "flame_graph_block_color_performance_good"; +/// Theme path for the color of a performance block that indicates medium performance. +pub const COLOR_PERFORMANCE_MEDIUM: &str = "flame_graph_block_color_performance_medium"; +/// Theme path for the color of a performance block that indicates bad performance.. +pub const COLOR_PERFORMANCE_BAD: &str = "flame_graph_block_color_performance_bad"; + +/// Theme path for the color that is sued to color a mark. +pub const COLOR_MARK_DEFAULT: &str = "flame_graph_mark_color"; + + +/// Trait that allows retrieval of a style::Path. +pub trait IntoThemePath { + /// Return the `style::Path` associated with this object. + fn theme_path(&self) -> style::Path; +} + +impl IntoThemePath for Activity { + fn theme_path(&self) -> style::Path { + match self { + Activity::Active => COLOR_BLOCK_ACTIVE, + Activity::Paused => COLOR_BLOCK_PAUSED, + } + .into() + } +} + +impl IntoThemePath for Performance { + fn theme_path(&self) -> style::Path { + match self { + Performance::Good => COLOR_PERFORMANCE_GOOD, + Performance::Medium => COLOR_PERFORMANCE_MEDIUM, + Performance::Bad => COLOR_PERFORMANCE_BAD, + } + .into() + } +} + +impl IntoThemePath for profiler_flame_graph::Block { + fn theme_path(&self) -> style::Path { + self.block_type.theme_path() + } +} + + + // =================== // === Flame Graph === // =================== @@ -55,12 +112,22 @@ pub struct FlameGraph { display_object: display::object::Instance, blocks: Vec, marks: Vec, + origin_x: f64, + app: Application, } /// Instantiate a `Block` shape for the given block data from the profiler. -fn shape_from_block(block: profiler_flame_graph::Block, app: &Application) -> Block { +pub fn shape_from_block( + block: profiler_flame_graph::Block, + app: &Application, +) -> Block { let component = app.new_view::(); + let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet); + let color: color::Rgba = style.get_color(block.theme_path()).value(); + let color: color::Lcha = color.into(); + component.set_color(color); + let size = Vector2::new(block.width() as f32, ROW_HEIGHT as f32); let x = block.start + block.width() / 2.0; let y = block.row as f64 * (ROW_HEIGHT + ROW_PADDING); @@ -70,15 +137,6 @@ fn shape_from_block(block: profiler_flame_graph::Block, app: &Application) -> Bl component.set_size.emit(size); component.set_position_xy(pos); - let style = StyleWatchFrp::new(&app.display.default_scene.style_sheet); - - let color: color::Rgba = match block.state { - State::Active => style.get_color("flame_graph_block_color_active").value(), - State::Paused => style.get_color("flame_graph_block_color_paused").value(), - }; - let color: color::Lcha = color.into(); - component.set_color(color); - component } @@ -100,41 +158,55 @@ fn shape_from_mark(mark: profiler_flame_graph::Mark, app: &Application) -> Mark const MIN_INTERVAL_TIME_MS: f64 = 0.0; const X_SCALE: f64 = 1.0; +fn align_block( + mut block: profiler_flame_graph::Block, + origin_x: f64, +) -> profiler_flame_graph::Block { + // Shift + block.start -= origin_x; + block.end -= origin_x; + // Scale + block.start *= X_SCALE; + block.end *= X_SCALE; + block +} + +fn align_mark(mut mark: profiler_flame_graph::Mark, origin_x: f64) -> profiler_flame_graph::Mark { + mark.position -= origin_x; + mark.position *= X_SCALE; + mark +} + impl FlameGraph { /// Create a `FlameGraph` EnsoGL component from the given graph data from the profiler. pub fn from_data(data: profiler_flame_graph::Graph, app: &Application) -> Self { let logger = Logger::new("FlameGraph"); let display_object = display::object::Instance::new(&logger); - let blocks = data.blocks.into_iter().filter(|block| block.width() > MIN_INTERVAL_TIME_MS); + let activity_blocks = + data.activity_blocks.into_iter().filter(|block| block.width() > MIN_INTERVAL_TIME_MS); + let performance_blocks = data.performance_blocks.into_iter(); let marks = data.marks; - let origin_x = - blocks.clone().map(|block| block.start.floor() as u32).min().unwrap_or_default(); + let origin_x = activity_blocks + .clone() + .map(|block| block.start.floor() as u32) + .min() + .unwrap_or_default() as f64; - let blocks_zero_aligned = blocks.clone().map(|mut block| { - // Shift - block.start -= origin_x as f64; - block.end -= origin_x as f64; - // Scale - block.start *= X_SCALE; - block.end *= X_SCALE; - block - }); - let blocks = blocks_zero_aligned.map(|block| shape_from_block(block, app)).collect_vec(); + let activity_block_shapes = + activity_blocks.map(|block| shape_from_block(align_block(block, origin_x), app)); + let performance_block_shapes = + performance_blocks.map(|block| shape_from_block(align_block(block, origin_x), app)); + + let blocks = activity_block_shapes.chain(performance_block_shapes).collect_vec(); blocks.iter().for_each(|item| display_object.add_child(item)); - - let blocks_marks_aligned = marks.into_iter().map(|mut mark| { - mark.position -= origin_x as f64; - mark.position *= X_SCALE; - mark - }); - let marks: Vec<_> = - blocks_marks_aligned.into_iter().map(|mark| shape_from_mark(mark, app)).collect(); + let marks: Vec<_> = marks.into_iter().map(|mark| shape_from_mark(mark, app)).collect(); marks.iter().for_each(|item| display_object.add_child(item)); - Self { display_object, blocks, marks } + let app = app.clone_ref(); + Self { display_object, blocks, marks, origin_x, app } } /// Return a reference to the blocks that make up the flame graph. @@ -146,6 +218,25 @@ impl FlameGraph { pub fn marks(&self) -> &[Mark] { &self.marks } + + /// Add an additional activity block to the visualisation. + pub fn add_block( + &mut self, + block: profiler_flame_graph::Block, + ) { + let block = align_block(block, self.origin_x); + let shape = shape_from_block(block, &self.app); + self.display_object.add_child(&shape); + self.blocks.push(shape); + } + + /// Add additional mark to the visualisation. + pub fn add_mark(&mut self, mark: profiler_flame_graph::Mark) { + let mark = align_mark(mark, self.origin_x); + let shape = shape_from_mark(mark, &self.app); + self.display_object.add_child(&shape); + self.marks.push(shape); + } } impl display::Object for FlameGraph { diff --git a/lib/rust/ensogl/core/src/debug/stats.rs b/lib/rust/ensogl/core/src/debug/stats.rs index 1e95aa8809..9489426a64 100644 --- a/lib/rust/ensogl/core/src/debug/stats.rs +++ b/lib/rust/ensogl/core/src/debug/stats.rs @@ -158,7 +158,7 @@ macro_rules! gen_stats { // === StatsData === /// Raw data of all the gathered stats. - #[derive(Debug,Default,Clone,Copy)] + #[derive(Debug,Default,Clone,Copy,serde::Serialize,serde::Deserialize)] #[allow(missing_docs)] pub struct StatsData { $(pub $field : $field_type),* diff --git a/lib/rust/ensogl/core/src/display/world.rs b/lib/rust/ensogl/core/src/display/world.rs index 1a3cd72118..93f28c0d23 100644 --- a/lib/rust/ensogl/core/src/display/world.rs +++ b/lib/rust/ensogl/core/src/display/world.rs @@ -55,6 +55,22 @@ impl Uniforms { } +// ========================= +// === Metadata Profiler === +// ========================= + + +thread_local! { + /// Profiling metadata logger for `StatsData`. + static RENDER_STATS_LOGGER: enso_profiler::MetadataLogger = enso_profiler::MetadataLogger::new("RenderStats"); +} + +/// Log rendering stats to the profiling framework. +pub fn log_render_stats(stats: StatsData) { + RENDER_STATS_LOGGER.with(|logger| logger.log(stats)); +} + + // ============= // === World === @@ -204,9 +220,9 @@ impl WorldData { let uniforms = Uniforms::new(&default_scene.variables); let debug_hotkeys_handle = default(); let garbage_collector = default(); - let stats_draw_handle = on.prev_frame_stats.add(f!([stats_monitor] (stats: &StatsData) { stats_monitor.sample_and_draw(stats); + log_render_stats(*stats) })); Self { diff --git a/lib/rust/ensogl/example/profiling-run-graph/Cargo.toml b/lib/rust/ensogl/example/profiling-run-graph/Cargo.toml index fbc280f632..cebd649c40 100644 --- a/lib/rust/ensogl/example/profiling-run-graph/Cargo.toml +++ b/lib/rust/ensogl/example/profiling-run-graph/Cargo.toml @@ -11,8 +11,8 @@ crate-type = ["cdylib", "rlib"] enso-frp = { path = "../../../frp" } enso-profiler = { path = "../../../profiler" } enso-profiler-data = { path = "../../../profiler/data" } -enso-profiler-metadata = { path = "../../../../../app/gui/enso-profiler-metadata" } enso-profiler-flame-graph = { path = "../../../profiler/flame-graph" } +enso-profiler-metadata = { path = "../../../../../app/gui/enso-profiler-metadata" } enso-web = { path = "../../../web" } ensogl-core = { path = "../../core" } ensogl-flame-graph = { path = "../../component/flame-graph" } diff --git a/lib/rust/ensogl/example/profiling-run-graph/src/lib.rs b/lib/rust/ensogl/example/profiling-run-graph/src/lib.rs index 6594aeddff..eed84b48f0 100644 --- a/lib/rust/ensogl/example/profiling-run-graph/src/lib.rs +++ b/lib/rust/ensogl/example/profiling-run-graph/src/lib.rs @@ -21,6 +21,7 @@ use enso_profiler as profiler; use enso_profiler::profile; use enso_profiler_data::Profile; use enso_profiler_flame_graph as profiler_flame_graph; +use enso_profiler_flame_graph::Performance; use enso_profiler_metadata::Metadata; use ensogl_core::application::Application; use ensogl_core::data::color; @@ -30,12 +31,23 @@ use ensogl_core::display::style::theme; use ensogl_core::display::Scene; use ensogl_core::system::web; use ensogl_flame_graph as flame_graph; +use ensogl_flame_graph::COLOR_BLOCK_ACTIVE; +use ensogl_flame_graph::COLOR_BLOCK_PAUSED; +use ensogl_flame_graph::COLOR_MARK_DEFAULT; +use ensogl_flame_graph::COLOR_PERFORMANCE_BAD; +use ensogl_flame_graph::COLOR_PERFORMANCE_GOOD; +use ensogl_flame_graph::COLOR_PERFORMANCE_MEDIUM; + + +// ================= +// === Constants === +// ================= /// Content of a profiler log, that will be rendered. If this is `None` some dummy data will be /// generated and rendered. The file must be located in the assets subdirectory that is /// served by the webserver, i.e. `enso/dist/content` or `app/ide-desktop/lib/content/assets`. /// For example use `Some("profile.json"))`. -const PROFILER_LOG_NAME: Option<&str> = None; +const PROFILER_LOG_NAME: Option<&str> = Some("profile.json"); @@ -61,19 +73,15 @@ pub async fn main() { let profile = if let Some(profile) = get_log_data().await { profile } else { create_dummy_data().await }; - let mut measurements = profiler_flame_graph::Graph::new_hybrid_graph(&profile); + let measurements = profiler_flame_graph::Graph::new_hybrid_graph(&profile); - let marks = profile - .iter_metadata() - .map(|metadata: &enso_profiler_data::Metadata| { - let position = metadata.mark.into_ms(); - let label = metadata.data.to_string(); - profiler_flame_graph::Mark { position, label } - }) - .collect(); - measurements.marks = marks; + let mut flame_graph = flame_graph::FlameGraph::from_data(measurements, app); - let flame_graph = flame_graph::FlameGraph::from_data(measurements, app); + let marks = make_marks_from_profile(&profile); + marks.into_iter().for_each(|mark| flame_graph.add_mark(mark)); + + let performance_blocks = make_rendering_performance_blocks(&profile); + performance_blocks.into_iter().for_each(|block| flame_graph.add_block(block)); world.add_child(&flame_graph); scene.add_child(&flame_graph); @@ -97,16 +105,66 @@ fn init_theme(scene: &Scene) { let theme_manager = theme::Manager::from(&scene.style_sheet); let theme = theme::Theme::new(); - theme.set("flame_graph_block_color_active", color::Lcha::blue_green(0.5, 0.8)); - theme.set("flame_graph_block_color_paused", color::Lcha::blue_green(0.8, 0.0)); - theme.set("flame_graph_mark_color", color::Lcha::blue_green(0.9, 0.1)); + theme.set(COLOR_BLOCK_ACTIVE, color::Lcha::blue_green(0.5, 0.8)); + theme.set(COLOR_BLOCK_PAUSED, color::Lcha::blue_green(0.8, 0.0)); + theme.set(COLOR_PERFORMANCE_BAD, color::Lcha::red(0.4, 0.5)); + theme.set(COLOR_PERFORMANCE_GOOD, color::Lcha::green(0.8, 0.5)); + theme.set(COLOR_PERFORMANCE_MEDIUM, color::Lcha::yellow(0.6, 0.5)); + theme.set(COLOR_MARK_DEFAULT, color::Lcha::blue_green(0.9, 0.1)); theme_manager.register("theme", theme); - theme_manager.set_enabled(&["theme".to_string()]); +} - let style_watch = ensogl_core::display::shape::StyleWatch::new(&scene.style_sheet); - style_watch.get("flame_graph_color"); + + +// =========================== +// === Metadata Processing === +// =========================== + + +// Create marks for metadata. This will skip `RenderStats` as they are added separately as blocks. +fn make_marks_from_profile(profile: &Profile) -> Vec { + profile + .iter_metadata() + .filter_map(|metadata: &enso_profiler_data::Metadata| { + let position = metadata.mark.into_ms(); + match metadata.data { + Metadata::RenderStats(_) => None, + _ => { + let label = metadata.data.to_string(); + Some(profiler_flame_graph::Mark { position, label }) + } + } + }) + .collect() +} + +fn make_rendering_performance_blocks( + profile: &Profile, +) -> Vec> { + let mut blocks = Vec::default(); + let render_stats = profile.iter_metadata().filter_map(|metadata| match metadata.data { + Metadata::RenderStats(data) => { + let mark = metadata.mark; + Some(enso_profiler_data::Metadata { mark, data }) + } + _ => None, + }); + for (prev, current) in render_stats.tuple_windows() { + let start = prev.mark.into_ms(); + let end = current.mark.into_ms(); + let row = -1; + let label = format!("{:#?}", current.data); + let block_type = match current.data.fps { + fps if fps > 55.0 => Performance::Good, + fps if fps > 25.0 => Performance::Medium, + _ => Performance::Bad, + }; + let block = profiler_flame_graph::Block { start, end, row, label, block_type }; + blocks.push(block); + } + blocks } diff --git a/lib/rust/json-rpc/Cargo.toml b/lib/rust/json-rpc/Cargo.toml index 286845e851..5a2e81029e 100644 --- a/lib/rust/json-rpc/Cargo.toml +++ b/lib/rust/json-rpc/Cargo.toml @@ -11,6 +11,7 @@ crate-type = ["cdylib", "rlib"] enso-prelude = { path = "../prelude", features = ["futures"]} enso-shapely = { path = "../shapely"} enso-web = { path = "../web" } +enso-profiler-data = {path = "../profiler/data"} enso-profiler = {path = "../profiler"} futures = { version = "0.3.1" } failure = { version = "0.1.6" } diff --git a/lib/rust/json-rpc/src/lib.rs b/lib/rust/json-rpc/src/lib.rs index 5e0876fe6e..4b88defd9a 100644 --- a/lib/rust/json-rpc/src/lib.rs +++ b/lib/rust/json-rpc/src/lib.rs @@ -32,6 +32,7 @@ pub use api::RemoteMethodCall; pub use api::Result; pub use enso_prelude as prelude; pub use enso_profiler; +pub use enso_profiler_data; pub use enso_web as ensogl; pub use error::RpcError; pub use handler::Event; diff --git a/lib/rust/profiler/flame-graph/src/lib.rs b/lib/rust/profiler/flame-graph/src/lib.rs index 69b56ddf4b..57de79ff62 100644 --- a/lib/rust/profiler/flame-graph/src/lib.rs +++ b/lib/rust/profiler/flame-graph/src/lib.rs @@ -6,41 +6,51 @@ #![deny(non_ascii_idents)] #![warn(unsafe_code)] -use crate::State::Active; -use crate::State::Paused; - use enso_profiler as profiler; use enso_profiler_data as data; + +// ================= +// === Constants === +// ================= + +type RowNumber = i32; + + // ================== // === Block Data === // ================== -/// Indicates whether a block indicates an active interval or a paused interval. Paused intervals -/// are used to represent async tasks that are started and awaited, but that have made no progress. #[derive(Copy, Clone, Debug)] -pub enum State { +pub enum Activity { Active, Paused, } -/// A `Block` contains the data required to render a single block of a frame graph. -#[derive(Clone, Debug)] -pub struct Block { - /// Start x coordinate of the block. - pub start: f64, - /// End x coordinate of the block. - pub end: f64, - /// Row that the block should be placed in. - pub row: u32, - /// The label to be displayed with the block. - pub label: String, - /// Indicates what state this block represents (active/paused). - pub state: State, +#[derive(Copy, Clone, Debug)] +pub enum Performance { + Good, + Medium, + Bad, } -impl Block { +/// A `Block` contains the data required to render a single block of a frame graph. +#[derive(Clone, Debug)] +pub struct Block { + /// Start x coordinate of the block. + pub start: f64, + /// End x coordinate of the block. + pub end: f64, + /// Row that the block should be placed in. + pub row: RowNumber, + /// The label to be displayed with the block. + pub label: String, + /// Indicates the type of the block. + pub block_type: T, +} + +impl Block { /// Width of the block. pub fn width(&self) -> f64 { self.end - self.start @@ -72,9 +82,11 @@ pub struct Mark { #[derive(Debug, Default)] pub struct Graph { /// Collection of all blocks making up the flame graph. - pub blocks: Vec, + pub activity_blocks: Vec>, + /// Collection of all blocks indicating performance characteristics. + pub performance_blocks: Vec>, /// Collection of marks that can be shown in the flame graph. - pub marks: Vec, + pub marks: Vec, } impl Graph { @@ -115,7 +127,7 @@ impl Graph { /// Build a graph that illustrates the call stack over time. struct CallgraphBuilder<'p, Metadata> { profile: &'p data::Profile, - blocks: Vec, + blocks: Vec>, } impl<'p, Metadata> CallgraphBuilder<'p, Metadata> { @@ -128,14 +140,17 @@ impl<'p, Metadata> CallgraphBuilder<'p, Metadata> { builder.visit_interval(*child, 0); } let Self { blocks, .. } = builder; - let marks = Vec::default(); - Graph { blocks, marks } + Graph { + activity_blocks: blocks, + marks: Vec::default(), + performance_blocks: Vec::default(), + } } } impl<'p, Metadata> CallgraphBuilder<'p, Metadata> { /// Create a block for an interval; recurse into children. - fn visit_interval(&mut self, active: data::IntervalId, row: u32) { + fn visit_interval(&mut self, active: data::IntervalId, row: RowNumber) { let active = &self.profile[active]; let start = active.interval.start.into_ms(); let end = active.interval.end.map(|mark| mark.into_ms()).unwrap_or(f64::MAX); @@ -144,7 +159,7 @@ impl<'p, Metadata> CallgraphBuilder<'p, Metadata> { return; } let label = self.profile[active.measurement].label.to_string(); - self.blocks.push(Block { start, end, label, row, state: Active }); + self.blocks.push(Block { start, end, label, row, block_type: Activity::Active }); for child in &active.children { self.visit_interval(*child, row + 1); } @@ -160,8 +175,8 @@ impl<'p, Metadata> CallgraphBuilder<'p, Metadata> { /// Build a graph that illustrates async tasks over time. struct RungraphBuilder<'p, Metadata> { profile: &'p data::Profile, - blocks: Vec, - next_row: u32, + blocks: Vec>, + next_row: RowNumber, } impl<'p, Metadata> RungraphBuilder<'p, Metadata> { @@ -175,8 +190,11 @@ impl<'p, Metadata> RungraphBuilder<'p, Metadata> { builder.visit_measurement(*child); } let Self { blocks, .. } = builder; - let marks = Vec::default(); - Graph { blocks, marks } + Graph { + activity_blocks: blocks, + marks: Vec::default(), + performance_blocks: Vec::default(), + } } } @@ -211,7 +229,7 @@ impl<'p, Metadata> RungraphBuilder<'p, Metadata> { end: active_interval[1], label: label_active, row, - state: Active, + block_type: Activity::Active, }); self.blocks.push(Block { @@ -219,7 +237,7 @@ impl<'p, Metadata> RungraphBuilder<'p, Metadata> { end: sleep_interval[1], label: label_sleep, row, - state: Paused, + block_type: Activity::Paused, }); } } @@ -232,7 +250,7 @@ impl<'p, Metadata> RungraphBuilder<'p, Metadata> { end: first.interval.start.into_ms(), label: self.profile[first.measurement].label.to_string(), row, - state: Paused, + block_type: Activity::Paused, }); // Add last active interval. @@ -243,7 +261,7 @@ impl<'p, Metadata> RungraphBuilder<'p, Metadata> { end: last.interval.end.map(|end| end.into_ms()).unwrap_or(f64::INFINITY), label: self.profile[last.measurement].label.to_string(), row, - state: Active, + block_type: Activity::Active, }); } @@ -271,8 +289,11 @@ fn new_hybrid_graph(profile: &data::Profile) -> Graph { callgraph.visit_interval(*child, next_row); } let CallgraphBuilder { blocks, .. } = callgraph; - let marks = Vec::default(); - Graph { blocks, marks } + Graph { + activity_blocks: blocks, + marks: Vec::default(), + performance_blocks: Vec::default(), + } } @@ -302,23 +323,26 @@ impl From for Graph { grapher.visit_frame(frame, label.to_string(), 0); } let FlamegraphGrapher { blocks, .. } = grapher; - let marks = Vec::default(); - Self { blocks, marks } + Graph { + activity_blocks: blocks, + marks: Vec::default(), + performance_blocks: Vec::default(), + } } } /// Builds a flamegraph [`Graph`] from [`data::aggregate::Frame`]s. #[derive(Default)] struct FlamegraphGrapher { - blocks: Vec, + blocks: Vec>, time: f64, } impl FlamegraphGrapher { - fn visit_frame(&mut self, frame: &data::aggregate::Frame, label: String, row: u32) { + fn visit_frame(&mut self, frame: &data::aggregate::Frame, label: String, row: RowNumber) { let start = self.time; let end = self.time + frame.total_duration(); - self.blocks.push(Block { start, end, label, row, state: State::Active }); + self.blocks.push(Block { start, end, label, row, block_type: Activity::Active }); for (label, frame) in &frame.children { self.visit_frame(frame, label.to_string(), row + 1); } @@ -351,11 +375,11 @@ mod tests { let profile: data::Profile = profiler::internal::take_log().parse().unwrap(); let flame_graph = Graph::new_callgraph(&profile); - assert_eq!(flame_graph.blocks.len(), 2); + assert_eq!(flame_graph.activity_blocks.len(), 2); - assert_eq!(flame_graph.blocks[1].row, 1); - assert!(flame_graph.blocks[1].label.contains("profiled_b")); - assert_eq!(flame_graph.blocks[0].row, 0); - assert!(flame_graph.blocks[0].label.contains("profiled_a")); + assert_eq!(flame_graph.activity_blocks[1].row, 1); + assert!(flame_graph.activity_blocks[1].label.contains("profiled_b")); + assert_eq!(flame_graph.activity_blocks[0].row, 0); + assert!(flame_graph.activity_blocks[0].label.contains("profiled_a")); } }