perf: add chrome tracing layer

This generates profiles in the Google Chrome JSON tracing format. They can be opened in Chrome's `chrome://tracing` page or in tools like https://ui.perfetto.dev. Enable by running e.g. `JJ_TRACE=1 cargo run -- status`.
This commit is contained in:
Waleed Khan 2023-07-08 13:45:38 +01:00
parent e618b2c14f
commit 6f15a27079
4 changed files with 88 additions and 3 deletions

3
.gitignore vendored
View file

@ -8,3 +8,6 @@ result
# Editor specific ignores
.idea
# Generated by setting `JJ_TRACE` environment variable.
jj-trace-*.json

32
Cargo.lock generated
View file

@ -1035,6 +1035,7 @@ dependencies = [
"timeago",
"toml_edit",
"tracing",
"tracing-chrome",
"tracing-subscriber",
]
@ -2261,6 +2262,17 @@ dependencies = [
"syn 2.0.23",
]
[[package]]
name = "tracing-chrome"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "496b3cd5447f7ff527bbbf19b071ad542a000adf297d4127078b4dfdb931f41a"
dependencies = [
"serde_json",
"tracing-core",
"tracing-subscriber",
]
[[package]]
name = "tracing-core"
version = "0.1.30"
@ -2268,6 +2280,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
dependencies = [
"lazy_static",
"log",
"tracing-core",
]
[[package]]
@ -2281,9 +2305,11 @@ dependencies = [
"once_cell",
"regex",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
@ -2353,6 +2379,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "vcpkg"
version = "0.2.15"

View file

@ -62,6 +62,7 @@ thiserror = "1.0.43"
timeago = { version = "0.4.1", default-features = false }
toml_edit = { version = "0.19.12", features = ["serde"] }
tracing = "0.1.37"
tracing-chrome = "0.7.1"
tracing-subscriber = { version = "0.3.17", default-features = false, features = ["std", "ansi", "env-filter", "fmt"] }
[target.'cfg(unix)'.dependencies]

View file

@ -23,6 +23,7 @@ use std::process::ExitCode;
use std::rc::Rc;
use std::str::FromStr;
use std::sync::Arc;
use std::time::SystemTime;
use clap::builder::{NonEmptyStringValueParser, TypedValueParser, ValueParserFactory};
use clap::{Arg, ArgAction, ArgMatches, Command, FromArgMatches};
@ -62,6 +63,7 @@ use jj_lib::{dag_walk, file_util, git, revset};
use once_cell::unsync::OnceCell;
use thiserror::Error;
use toml_edit;
use tracing_chrome::ChromeLayerBuilder;
use tracing_subscriber::prelude::*;
use crate::config::{
@ -332,6 +334,20 @@ impl From<GitConfigParseError> for CommandError {
}
}
#[derive(Clone)]
struct ChromeTracingFlushGuard {
_inner: Option<Rc<tracing_chrome::FlushGuard>>,
}
impl Debug for ChromeTracingFlushGuard {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { _inner } = self;
f.debug_struct("ChromeTracingFlushGuard")
.field("inner", &"not shown")
.finish()
}
}
/// Handle to initialize or change tracing subscription.
#[derive(Clone, Debug)]
pub struct TracingSubscription {
@ -339,6 +355,7 @@ pub struct TracingSubscription {
tracing_subscriber::EnvFilter,
tracing_subscriber::Registry,
>,
_chrome_tracing_flush_guard: ChromeTracingFlushGuard,
}
impl TracingSubscription {
@ -349,11 +366,43 @@ impl TracingSubscription {
.with_default_directive(tracing::metadata::LevelFilter::ERROR.into())
.from_env_lossy();
let (filter, reload_log_filter) = tracing_subscriber::reload::Layer::new(filter);
let (chrome_tracing_layer, chrome_tracing_flush_guard) = match std::env::var("JJ_TRACE") {
Ok(_) => {
let filename = format!(
"jj-trace-{}.json",
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs(),
);
let include_args = std::env::var("JJ_TRACE_INCLUDE_ARGS").is_ok();
let (layer, guard) = ChromeLayerBuilder::new()
.file(filename)
.include_args(include_args)
.build();
(
Some(layer),
ChromeTracingFlushGuard {
_inner: Some(Rc::new(guard)),
},
)
}
Err(_) => (None, ChromeTracingFlushGuard { _inner: None }),
};
tracing_subscriber::registry()
.with(filter)
.with(tracing_subscriber::fmt::Layer::default().with_writer(std::io::stderr))
.with(
tracing_subscriber::fmt::Layer::default()
.with_writer(std::io::stderr)
.with_filter(filter),
)
.with(chrome_tracing_layer)
.init();
TracingSubscription { reload_log_filter }
TracingSubscription {
reload_log_filter,
_chrome_tracing_flush_guard: chrome_tracing_flush_guard,
}
}
pub fn enable_verbose_logging(&self) -> Result<(), CommandError> {