Log simple performance metrics (#4596)
Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -450,3 +450,9 @@ PS: for the debug panel, the following JSON is useful for snapping the camera
|
|||||||
## KCL
|
## KCL
|
||||||
|
|
||||||
For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl).
|
For how to contribute to KCL, [see our KCL README](https://github.com/KittyCAD/modeling-app/tree/main/src/wasm-lib/kcl).
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
To display logging (to the terminal or console) set `ZOO_LOG=1`. This will log some warnings and simple performance metrics. To view these in test runs, use `-- --nocapture`.
|
||||||
|
|
||||||
|
To enable memory metrics, build with `--features dhat-heap`.
|
||||||
|
40
src/wasm-lib/Cargo.lock
generated
40
src/wasm-lib/Cargo.lock
generated
@ -774,6 +774,22 @@ dependencies = [
|
|||||||
"syn 2.0.87",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dhat"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98cd11d84628e233de0ce467de10b8633f4ddaecafadefc86e13b84b8739b827"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
"lazy_static",
|
||||||
|
"mintex",
|
||||||
|
"parking_lot 0.12.3",
|
||||||
|
"rustc-hash 1.1.0",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thousands",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diff"
|
name = "diff"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
@ -1705,6 +1721,7 @@ dependencies = [
|
|||||||
"dashmap 6.1.0",
|
"dashmap 6.1.0",
|
||||||
"databake",
|
"databake",
|
||||||
"derive-docs",
|
"derive-docs",
|
||||||
|
"dhat",
|
||||||
"expectorate",
|
"expectorate",
|
||||||
"fnv",
|
"fnv",
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
@ -1749,6 +1766,7 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
|
"web-time",
|
||||||
"winnow",
|
"winnow",
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
@ -2056,6 +2074,12 @@ version = "0.5.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"
|
checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mintex"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9bec4598fddb13cc7b528819e697852653252b760f1228b7642679bf2ff2cd07"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@ -2644,7 +2668,7 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"quinn-proto",
|
"quinn-proto",
|
||||||
"quinn-udp",
|
"quinn-udp",
|
||||||
"rustc-hash",
|
"rustc-hash 2.0.0",
|
||||||
"rustls",
|
"rustls",
|
||||||
"socket2",
|
"socket2",
|
||||||
"thiserror 1.0.68",
|
"thiserror 1.0.68",
|
||||||
@ -2661,7 +2685,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"ring",
|
"ring",
|
||||||
"rustc-hash",
|
"rustc-hash 2.0.0",
|
||||||
"rustls",
|
"rustls",
|
||||||
"slab",
|
"slab",
|
||||||
"thiserror 1.0.68",
|
"thiserror 1.0.68",
|
||||||
@ -3001,6 +3025,12 @@ version = "0.1.24"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-hash"
|
name = "rustc-hash"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@ -3637,6 +3667,12 @@ dependencies = [
|
|||||||
"syn 2.0.87",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thousands"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.1.8"
|
version = "1.1.8"
|
||||||
|
@ -21,6 +21,7 @@ convert_case = "0.6.0"
|
|||||||
dashmap = "6.1.0"
|
dashmap = "6.1.0"
|
||||||
databake = { version = "0.1.8", features = ["derive"] }
|
databake = { version = "0.1.8", features = ["derive"] }
|
||||||
derive-docs = { version = "0.1.29", path = "../derive-docs" }
|
derive-docs = { version = "0.1.29", path = "../derive-docs" }
|
||||||
|
dhat = { version = "0.3", optional = true }
|
||||||
fnv = "1.0.7"
|
fnv = "1.0.7"
|
||||||
form_urlencoded = "1.2.1"
|
form_urlencoded = "1.2.1"
|
||||||
futures = { version = "0.3.31" }
|
futures = { version = "0.3.31" }
|
||||||
@ -51,6 +52,7 @@ url = { version = "2.5.3", features = ["serde"] }
|
|||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
uuid = { version = "1.11.0", features = ["v4", "js", "serde"] }
|
uuid = { version = "1.11.0", features = ["v4", "js", "serde"] }
|
||||||
validator = { version = "0.19.0", features = ["derive"] }
|
validator = { version = "0.19.0", features = ["derive"] }
|
||||||
|
web-time = "1.1"
|
||||||
winnow = "0.6.18"
|
winnow = "0.6.18"
|
||||||
zip = { version = "2.0.0", default-features = false }
|
zip = { version = "2.0.0", default-features = false }
|
||||||
|
|
||||||
@ -72,6 +74,7 @@ tower-lsp = { version = "0.20.0", features = ["proposed"] }
|
|||||||
[features]
|
[features]
|
||||||
default = ["engine"]
|
default = ["engine"]
|
||||||
cli = ["dep:clap"]
|
cli = ["dep:clap"]
|
||||||
|
dhat-heap = ["dep:dhat"]
|
||||||
# For the lsp server, when run with stdout for rpc we want to disable println.
|
# For the lsp server, when run with stdout for rpc we want to disable println.
|
||||||
# This is used for editor extensions that use the lsp server.
|
# This is used for editor extensions that use the lsp server.
|
||||||
disable-println = []
|
disable-println = []
|
||||||
|
@ -282,8 +282,8 @@ impl EngineConnection {
|
|||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
match &e {
|
match &e {
|
||||||
WebSocketReadError::Read(e) => eprintln!("could not read from WS: {:?}", e),
|
WebSocketReadError::Read(e) => crate::logln!("could not read from WS: {:?}", e),
|
||||||
WebSocketReadError::Deser(e) => eprintln!("could not deserialize msg from WS: {:?}", e),
|
WebSocketReadError::Deser(e) => crate::logln!("could not deserialize msg from WS: {:?}", e),
|
||||||
}
|
}
|
||||||
*socket_health_tcp_read.lock().unwrap() = SocketHealth::Inactive;
|
*socket_health_tcp_read.lock().unwrap() = SocketHealth::Inactive;
|
||||||
return Err(e);
|
return Err(e);
|
||||||
|
@ -1909,6 +1909,7 @@ impl ExecutorContext {
|
|||||||
program: &Program,
|
program: &Program,
|
||||||
exec_state: &mut ExecState,
|
exec_state: &mut ExecState,
|
||||||
) -> Result<Option<ModelingSessionData>, KclError> {
|
) -> Result<Option<ModelingSessionData>, KclError> {
|
||||||
|
let _stats = crate::log::LogPerfStats::new("Interpretation");
|
||||||
// TODO: Use the top-level file's path.
|
// TODO: Use the top-level file's path.
|
||||||
exec_state.add_module(std::path::PathBuf::from(""));
|
exec_state.add_module(std::path::PathBuf::from(""));
|
||||||
// Before we even start executing the program, set the units.
|
// Before we even start executing the program, set the units.
|
||||||
|
@ -8,11 +8,54 @@
|
|||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
macro_rules! println {
|
macro_rules! println {
|
||||||
($($rest:tt)*) => {
|
($($rest:tt)*) => {
|
||||||
|
#[cfg(feature = "disable-println")]
|
||||||
|
{
|
||||||
|
let _ = format!($($rest)*);
|
||||||
|
}
|
||||||
#[cfg(not(feature = "disable-println"))]
|
#[cfg(not(feature = "disable-println"))]
|
||||||
std::println!($($rest)*)
|
std::println!($($rest)*)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! eprintln {
|
||||||
|
($($rest:tt)*) => {
|
||||||
|
#[cfg(feature = "disable-println")]
|
||||||
|
{
|
||||||
|
let _ = format!($($rest)*);
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "disable-println"))]
|
||||||
|
std::eprintln!($($rest)*)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! print {
|
||||||
|
($($rest:tt)*) => {
|
||||||
|
#[cfg(feature = "disable-println")]
|
||||||
|
{
|
||||||
|
let _ = format!($($rest)*);
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "disable-println"))]
|
||||||
|
std::print!($($rest)*)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! eprint {
|
||||||
|
($($rest:tt)*) => {
|
||||||
|
#[cfg(feature = "disable-println")]
|
||||||
|
{
|
||||||
|
let _ = format!($($rest)*);
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "disable-println"))]
|
||||||
|
std::eprint!($($rest)*)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(feature = "dhat-heap")]
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOC: dhat::Alloc = dhat::Alloc;
|
||||||
|
|
||||||
mod ast;
|
mod ast;
|
||||||
mod coredump;
|
mod coredump;
|
||||||
mod docs;
|
mod docs;
|
||||||
@ -23,6 +66,7 @@ mod fs;
|
|||||||
mod function_param;
|
mod function_param;
|
||||||
mod kcl_value;
|
mod kcl_value;
|
||||||
pub mod lint;
|
pub mod lint;
|
||||||
|
mod log;
|
||||||
mod lsp;
|
mod lsp;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod settings;
|
mod settings;
|
||||||
@ -71,6 +115,8 @@ pub mod std_utils {
|
|||||||
pub use crate::std::utils::{get_tangential_arc_to_info, is_points_ccw_wasm, TangentialArcInfoInput};
|
pub use crate::std::utils::{get_tangential_arc_to_info, is_points_ccw_wasm, TangentialArcInfoInput};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use crate::log::{log, logln};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
116
src/wasm-lib/kcl/src/log.rs
Normal file
116
src/wasm-lib/kcl/src/log.rs
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#![allow(dead_code)]
|
||||||
|
#[cfg(feature = "dhat-heap")]
|
||||||
|
use dhat::{HeapStats, Profiler};
|
||||||
|
use std::env;
|
||||||
|
use web_time::Instant;
|
||||||
|
|
||||||
|
const LOG_ENV_VAR: &str = "ZOO_LOG";
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref ENABLED: bool = {
|
||||||
|
let env_var = env::var(LOG_ENV_VAR);
|
||||||
|
let Ok(env_var) = env_var else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
!env_var.is_empty()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dhat-heap")]
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref PROFILER: Profiler = Profiler::builder().testing().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Log a message
|
||||||
|
pub(crate) fn log(msg: impl Into<String>) {
|
||||||
|
if *ENABLED {
|
||||||
|
log_inner(msg.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused_macros)]
|
||||||
|
macro_rules! logln {
|
||||||
|
($($rest:tt)*) => {
|
||||||
|
crate::log::log(format!($($rest)*))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub(crate) use logln;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "disable-println"))]
|
||||||
|
#[inline]
|
||||||
|
fn log_inner(msg: String) {
|
||||||
|
eprintln!("{msg}");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "disable-println", target_arch = "wasm32"))]
|
||||||
|
#[inline]
|
||||||
|
fn log_inner(msg: String) {
|
||||||
|
web_sys::console::log_1(&msg.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "disable-println", not(target_arch = "wasm32")))]
|
||||||
|
#[inline]
|
||||||
|
fn log_inner(_msg: String) {}
|
||||||
|
|
||||||
|
/// A helper struct for recording and logging basic performance metrics.
|
||||||
|
///
|
||||||
|
/// It will log the metrics when dropped or if `log_now` is called.
|
||||||
|
pub(crate) struct LogPerfStats<'a> {
|
||||||
|
msg: &'a str,
|
||||||
|
start_time: Instant,
|
||||||
|
#[cfg(feature = "dhat-heap")]
|
||||||
|
start_stats: HeapStats,
|
||||||
|
cancelled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LogPerfStats<'a> {
|
||||||
|
#[cfg(not(feature = "dhat-heap"))]
|
||||||
|
pub fn new(msg: &'a str) -> Self {
|
||||||
|
LogPerfStats {
|
||||||
|
msg,
|
||||||
|
start_time: Instant::now(),
|
||||||
|
cancelled: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "dhat-heap")]
|
||||||
|
pub fn new(msg: &'a str) -> Self {
|
||||||
|
lazy_static::initialize(&PROFILER);
|
||||||
|
LogPerfStats {
|
||||||
|
msg,
|
||||||
|
start_time: Instant::now(),
|
||||||
|
start_stats: HeapStats::get(),
|
||||||
|
cancelled: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn log_now(&self) {
|
||||||
|
let time = Instant::now().duration_since(self.start_time).as_secs_f64() * 1000.0;
|
||||||
|
logln!("{}\n time: {time:.3}ms", self.msg);
|
||||||
|
#[cfg(feature = "dhat-heap")]
|
||||||
|
{
|
||||||
|
let stats = HeapStats::get();
|
||||||
|
let blocks = stats.total_blocks - self.start_stats.total_blocks;
|
||||||
|
let bytes = (stats.total_bytes - self.start_stats.total_bytes) as f64 / 1_000_000.0;
|
||||||
|
let cur = stats.curr_bytes as f64 / 1000.0;
|
||||||
|
let max = stats.curr_bytes as f64 / 1000.0;
|
||||||
|
|
||||||
|
logln!(" memory:");
|
||||||
|
logln!(" allocations: {bytes:.5} MB ({blocks} blocks)");
|
||||||
|
logln!(" currently allocated: {cur:.3} KB");
|
||||||
|
logln!(" max allocated: {max:.3} KB");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// After `cancel`ing, this object will not log its stats on drop (you can still can `log_now`).
|
||||||
|
pub fn cancel(&mut self) {
|
||||||
|
self.cancelled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for LogPerfStats<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.cancelled {
|
||||||
|
self.log_now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -38,6 +38,7 @@ thread_local! {
|
|||||||
pub type TokenSlice<'slice, 'input> = &'slice mut &'input [Token];
|
pub type TokenSlice<'slice, 'input> = &'slice mut &'input [Token];
|
||||||
|
|
||||||
pub fn run_parser(i: TokenSlice) -> super::ParseResult {
|
pub fn run_parser(i: TokenSlice) -> super::ParseResult {
|
||||||
|
let _stats = crate::log::LogPerfStats::new("Parsing");
|
||||||
ParseContext::init();
|
ParseContext::init();
|
||||||
|
|
||||||
let result = program.parse(i).save_err();
|
let result = program.parse(i).save_err();
|
||||||
|
Reference in New Issue
Block a user