From 361d45f2b2f7e69d37d4e6d8270e448f72cae9a7 Mon Sep 17 00:00:00 2001 From: konstin Date: Mon, 19 Jun 2023 11:40:09 +0200 Subject: [PATCH] Add `cargo dev repeat` for profiling (#5144) ## Summary This adds a new subcommand that can be used as ```shell cargo build --bin ruff_dev --profile=release-debug perf record -g -F 999 target/release-debug/ruff_dev repeat --repeat 30 --exit-zero --no-cache path/to/cpython > /dev/null flamegraph --perfdata perf.data ``` ## Test Plan This is a ruff internal script. I successfully used it to profile cpython with the instructions above --- .gitignore | 5 +++++ crates/ruff_cli/src/args.rs | 2 +- crates/ruff_cli/src/lib.rs | 2 +- crates/ruff_dev/src/main.rs | 24 ++++++++++++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 55de3ba557e244..562d1b4c5a6dd0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,11 @@ github_search*.jsonl schemastore .venv* scratch.py +perf.data +perf.data.old +flamegraph.svg +# Additional target directories that don't invalidate the main compile cache when changing linker settings +/target* ### # Rust.gitignore diff --git a/crates/ruff_cli/src/args.rs b/crates/ruff_cli/src/args.rs index 09662c827281ad..eb3efc09a5c111 100644 --- a/crates/ruff_cli/src/args.rs +++ b/crates/ruff_cli/src/args.rs @@ -68,7 +68,7 @@ pub enum Command { }, } -#[derive(Debug, clap::Args)] +#[derive(Clone, Debug, clap::Args)] #[allow(clippy::struct_excessive_bools, clippy::module_name_repetitions)] pub struct CheckArgs { /// List of files or directories to check. diff --git a/crates/ruff_cli/src/lib.rs b/crates/ruff_cli/src/lib.rs index a9b53365fb7954..4307f742907e1e 100644 --- a/crates/ruff_cli/src/lib.rs +++ b/crates/ruff_cli/src/lib.rs @@ -159,7 +159,7 @@ fn format(files: &[PathBuf]) -> Result { Ok(ExitStatus::Success) } -fn check(args: CheckArgs, log_level: LogLevel) -> Result { +pub fn check(args: CheckArgs, log_level: LogLevel) -> Result { let (cli, overrides) = args.partition(); // Construct the "default" settings. These are used when no `pyproject.toml` diff --git a/crates/ruff_dev/src/main.rs b/crates/ruff_dev/src/main.rs index c8beed5fb194c8..dbdfb4546693a7 100644 --- a/crates/ruff_dev/src/main.rs +++ b/crates/ruff_dev/src/main.rs @@ -4,6 +4,8 @@ use anyhow::Result; use clap::{Parser, Subcommand}; +use ruff::logging::{set_up_logging, LogLevel}; +use ruff_cli::check; mod generate_all; mod generate_cli_help; @@ -27,6 +29,7 @@ struct Args { } #[derive(Subcommand)] +#[allow(clippy::large_enum_variant)] enum Command { /// Run all code and documentation generation steps. GenerateAll(generate_all::Args), @@ -48,6 +51,16 @@ enum Command { PrintTokens(print_tokens::Args), /// Run round-trip source code generation on a given Python file. RoundTrip(round_trip::Args), + /// Run a ruff command n times for profiling/benchmarking + Repeat { + #[clap(flatten)] + args: ruff_cli::args::CheckArgs, + #[clap(flatten)] + log_level_args: ruff_cli::args::LogLevelArgs, + /// Run this many times + #[clap(long, short = 'n')] + repeat: usize, + }, } fn main() -> Result<()> { @@ -64,6 +77,17 @@ fn main() -> Result<()> { Command::PrintCST(args) => print_cst::main(args)?, Command::PrintTokens(args) => print_tokens::main(args)?, Command::RoundTrip(args) => round_trip::main(args)?, + Command::Repeat { + args, + repeat, + log_level_args, + } => { + let log_level = LogLevel::from(log_level_args); + set_up_logging(&log_level)?; + for _ in 0..*repeat { + check(args.clone(), log_level)?; + } + } } Ok(()) }