profiling graphs: fall back to demo data (#3746)

When running the profiling run-graph and flamegraph demo scenes, if a profile file is not found in the directory served over http, fall back to generating demo data.
This commit is contained in:
Kaz Wesley 2022-09-29 23:45:31 -07:00 committed by GitHub
parent 15084feaa6
commit 106bb0a044
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 160 additions and 114 deletions

12
Cargo.lock generated
View File

@ -2290,6 +2290,14 @@ dependencies = [
"serde_json",
]
[[package]]
name = "enso-profiler-demo-data"
version = "0.1.0"
dependencies = [
"enso-profiler",
"futures 0.3.21",
]
[[package]]
name = "enso-profiler-enso-data"
version = "0.1.0"
@ -2654,8 +2662,8 @@ version = "0.1.0"
dependencies = [
"enso-debug-api",
"enso-frp",
"enso-profiler",
"enso-profiler-data",
"enso-profiler-demo-data",
"enso-profiler-enso-data",
"enso-profiler-flame-graph",
"enso-web",
@ -2680,8 +2688,8 @@ name = "ensogl-example-render-profile-flamegraph"
version = "0.1.0"
dependencies = [
"enso-frp",
"enso-profiler",
"enso-profiler-data",
"enso-profiler-demo-data",
"enso-profiler-flame-graph",
"enso-web",
"ensogl-core",

View File

@ -13,6 +13,7 @@ members = [
"lib/rust/parser/jni",
"lib/rust/parser/generate-java",
"lib/rust/profiler/data",
"lib/rust/profiler/demo-data",
"integration-test",
"tools/language-server/logstat",
"tools/language-server/wstest",

View File

@ -10,8 +10,8 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
enso-debug-api = { path = "../../../debug-api" }
enso-frp = { path = "../../../frp" }
enso-profiler = { path = "../../../profiler" }
enso-profiler-data = { path = "../../../profiler/data" }
enso-profiler-demo-data = { path = "../../../profiler/demo-data" }
enso-profiler-enso-data = { path = "../../../../../app/gui/enso-profiler-enso-data" }
enso-profiler-flame-graph = { path = "../../../profiler/flame-graph" }
enso-web = { path = "../../../web" }

View File

@ -19,8 +19,6 @@
use ensogl_core::prelude::*;
use wasm_bindgen::prelude::*;
use enso_profiler as profiler;
use enso_profiler::profile;
use enso_profiler_data::parse_multiprocess_profile;
use enso_profiler_data::Profile;
use enso_profiler_enso_data::Metadata;
@ -66,6 +64,9 @@ const SHOW_BACKEND_MESSAGE_MARKS: bool = true;
#[entry_point]
#[allow(dead_code)]
pub async fn main() {
let profiles = get_log_data().await;
ensogl_text_msdf::initialized().await;
let app = &Application::new("root");
let world = &app.display;
let scene = &world.default_scene;
@ -75,8 +76,6 @@ pub async fn main() {
init_theme(scene);
let profiles = get_log_data().await;
let base_profile = &profiles[0];
let flame_graph = profile_to_graph(base_profile, app);
scene.add_child(&flame_graph);
@ -243,8 +242,14 @@ async fn get_data_http() -> Option<String> {
let window = web_sys::window().unwrap();
let response = window.fetch_with_request(&request);
let response = wasm_bindgen_futures::JsFuture::from(response).await.unwrap();
assert!(response.is_instance_of::<web_sys::Response>());
let response: web_sys::Response = response.dyn_into().unwrap();
if !response.ok() {
ERROR!(
"Error retrieving profile file from {url}: {response.status_text()}. \
Falling back to demo data."
);
return None;
}
let data = response.text().unwrap();
let data = wasm_bindgen_futures::JsFuture::from(data).await.unwrap();
data.as_string()
@ -269,109 +274,10 @@ async fn get_log_data() -> Vec<Profile<Metadata>> {
match data {
Some(data) => data,
None => {
let dummy_data = create_dummy_data().await;
vec![dummy_data]
let dummy_data = enso_profiler_demo_data::create_data().await;
let profile: Result<Profile<Metadata>, _> = dummy_data.parse();
let profile = profile.expect("Failed to deserialize profiling event log.");
vec![profile]
}
}
}
// ==========================
// === Dummy Computations ===
// ==========================
async fn create_dummy_data() -> Profile<Metadata> {
start_project().await;
let log = profiler::internal::take_log();
let profile: Result<Profile<Metadata>, _> = log.parse();
profile.expect("Failed to deserialize profiling event log.")
}
/// A dummy computation that is intended to take some time based on input (where a higher number
///takes longer).
fn work(n: u32) {
let mut m = n;
for x in 0..n {
for y in 0..n {
for z in 0..n {
m = m.wrapping_add(x * y * z)
}
}
}
// Create a side effect to avoid optimising away the computation.
println!("{}", m % 7)
}
#[profile(Objective)]
async fn start_project() {
wake_dragon().await;
feed_troll();
ride_rainbow();
}
#[profile(Objective)]
fn ride_rainbow() {
work(333)
}
#[profile(Objective)]
fn feed_troll() {
gather_herbs_and_spices();
cook_troll_food();
run_away();
}
#[profile(Objective)]
fn run_away() {
work(100)
}
#[profile(Objective)]
fn cook_troll_food() {
work(100)
}
#[profile(Objective)]
fn gather_herbs_and_spices() {
walk_to_woods();
search_stuff();
find_stuff();
gather_stuff();
}
#[profile(Objective)]
fn gather_stuff() {
work(100)
}
#[profile(Objective)]
fn find_stuff() {
work(100)
}
#[profile(Objective)]
fn search_stuff() {
work(100)
}
#[profile(Objective)]
fn walk_to_woods() {
work(100)
}
#[profile(Objective)]
async fn wake_dragon() {
gather_gold().await;
bake_gold_cake().await;
start_tea_party().await;
}
#[profile(Objective)]
async fn start_tea_party() {
work(100)
}
#[profile(Objective)]
async fn bake_gold_cake() {
work(100)
}
#[profile(Objective)]
fn pick_coin() {
work(75)
}
#[profile(Objective)]
async fn gather_gold() {
for _ in 0..5 {
pick_coin()
}
}

View File

@ -9,8 +9,8 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
enso-frp = { path = "../../../frp" }
enso-profiler = { path = "../../../profiler" }
enso-profiler-data = { path = "../../../profiler/data" }
enso-profiler-demo-data = { path = "../../../profiler/demo-data" }
enso-profiler-flame-graph = { path = "../../../profiler/flame-graph" }
enso-web = { path = "../../../web" }
ensogl-core = { path = "../../core" }

View File

@ -37,6 +37,9 @@ use ensogl_flame_graph as flame_graph;
#[wasm_bindgen]
#[allow(dead_code)]
pub async fn entry_point_render_profile_flamegraph() {
let data = get_data().await;
let profile: profiler_data::Profile<profiler_data::OpaqueMetadata> = data.parse().unwrap();
ensogl_text_msdf::initialized().await;
use ensogl_core::display::object::ObjectOps;
let app = &application::Application::new("root");
let world = &app.display;
@ -44,8 +47,6 @@ pub async fn entry_point_render_profile_flamegraph() {
let network = app.frp.network();
let navigator = navigator::Navigator::new(scene, &scene.camera());
init_theme(scene);
let data = get_data().await;
let profile: profiler_data::Profile<profiler_data::OpaqueMetadata> = data.parse().unwrap();
let mut builder = profiler_flame_graph::FlamegraphBuilder::default();
builder.add_profile(&profile);
let flame_graph = flame_graph::FlameGraph::from_data(builder.into(), app);
@ -89,6 +90,13 @@ async fn get_data() -> String {
let response = wasm_bindgen_futures::JsFuture::from(response).await.unwrap();
assert!(response.is_instance_of::<web_sys::Response>());
let response: web_sys::Response = response.dyn_into().unwrap();
if !response.ok() {
ERROR!(
"Error retrieving profile file from {url}: {response.status_text()}. \
Falling back to demo data."
);
return enso_profiler_demo_data::create_data().await;
}
let data = response.text().unwrap();
let data = wasm_bindgen_futures::JsFuture::from(data).await.unwrap();
data.as_string().unwrap()

View File

@ -0,0 +1,9 @@
[package]
name = "enso-profiler-demo-data"
version = "0.1.0"
edition = "2021"
authors = ["Enso Team <contact@enso.org>"]
[dependencies]
futures = "0.3"
enso-profiler = { path = ".." }

View File

@ -0,0 +1,114 @@
//! Produces example profile data.
// === Standard Linter Configuration ===
#![deny(non_ascii_idents)]
#![warn(unsafe_code)]
// === Non-Standard Linter Configuration ===
#![allow(unused_qualifications)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
use enso_profiler as profiler;
use enso_profiler::profile;
// ==========================
// === Dummy Computations ===
// ==========================
/// Create example profiling data.
pub async fn create_data() -> String {
start_project().await;
profiler::internal::take_log()
}
/// A dummy computation that is intended to take some time based on input (where a higher number
///takes longer).
fn work(n: u32) {
let mut m = n;
for x in 0..n {
for y in 0..n {
for z in 0..n {
m = m.wrapping_add(x * y * z)
}
}
}
// Create a side effect to avoid optimising away the computation.
println!("{}", m % 7)
}
#[profile(Objective)]
async fn start_project() {
wake_dragon().await;
feed_troll();
ride_rainbow();
}
#[profile(Objective)]
fn ride_rainbow() {
work(333)
}
#[profile(Objective)]
fn feed_troll() {
gather_herbs_and_spices();
cook_troll_food();
run_away();
}
#[profile(Objective)]
fn run_away() {
work(100)
}
#[profile(Objective)]
fn cook_troll_food() {
work(100)
}
#[profile(Objective)]
fn gather_herbs_and_spices() {
walk_to_woods();
search_stuff();
find_stuff();
gather_stuff();
}
#[profile(Objective)]
fn gather_stuff() {
work(100)
}
#[profile(Objective)]
fn find_stuff() {
work(100)
}
#[profile(Objective)]
fn search_stuff() {
work(100)
}
#[profile(Objective)]
fn walk_to_woods() {
work(100)
}
#[profile(Objective)]
async fn wake_dragon() {
gather_gold().await;
bake_gold_cake().await;
start_tea_party().await;
}
#[profile(Objective)]
async fn start_tea_party() {
work(100)
}
#[profile(Objective)]
async fn bake_gold_cake() {
work(100)
}
#[profile(Objective)]
fn pick_coin() {
work(75)
}
#[profile(Objective)]
async fn gather_gold() {
for _ in 0..5 {
pick_coin()
}
}