From 327deeb0c4a8c8dadbfa3b857ea87974bd335be0 Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Mon, 27 Mar 2023 08:23:53 -0700 Subject: [PATCH] cli: move `jj bench` commands to new module, hide behind feature flag The `jj bench` commands are mostly meant for developers, so lets hide the command from help and behind a `bench` feature flag. The feature flags avoids bloating the binary with the `criterion` dependencies, which was the reason I removed the command in 18c0b97d9d57. --- Cargo.toml | 3 +- src/commands/bench.rs | 161 ++++++++++++++++++++++++++++++++++++++++++ src/commands/mod.rs | 146 ++------------------------------------ 3 files changed, 169 insertions(+), 141 deletions(-) create mode 100644 src/commands/bench.rs diff --git a/Cargo.toml b/Cargo.toml index 4eb222b4d..42afc06cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ clap = { version = "4.1.9", features = ["derive", "deprecated"] } clap_complete = "4.1.5" clap_mangen = "0.2.10" config = { version = "0.13.3", default-features = false, features = ["toml"] } -criterion = "0.4.0" +criterion = {version = "0.4.0", optional = true } crossterm = { version = "0.26", default-features = false } dirs = "4.0.0" esl01-renderdag = "0.3.0" @@ -74,4 +74,5 @@ testutils = { path = "lib/testutils" } [features] default = ["jujutsu-lib/legacy-thrift"] +bench = ["criterion"] vendored-openssl = ["git2/vendored-openssl", "jujutsu-lib/vendored-openssl"] diff --git a/src/commands/bench.rs b/src/commands/bench.rs new file mode 100644 index 000000000..2bb4746a9 --- /dev/null +++ b/src/commands/bench.rs @@ -0,0 +1,161 @@ +// Copyright 2023 The Jujutsu Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::fmt::Debug; +use std::io; +use std::time::Instant; + +use clap::Subcommand; +use criterion::Criterion; +use jujutsu_lib::index::HexPrefix; +use jujutsu_lib::repo::Repo; + +use crate::cli_util::{CommandError, CommandHelper}; +use crate::ui::Ui; + +/// Commands for benchmarking internal operations +#[derive(Subcommand, Clone, Debug)] +#[command(hide = true)] +pub enum BenchCommands { + #[command(name = "commonancestors")] + CommonAncestors(BenchCommonAncestorsArgs), + #[command(name = "isancestor")] + IsAncestor(BenchIsAncestorArgs), + #[command(name = "walkrevs")] + WalkRevs(BenchWalkRevsArgs), + #[command(name = "resolveprefix")] + ResolvePrefix(BenchResolvePrefixArgs), +} + +/// Find the common ancestor(s) of a set of commits +#[derive(clap::Args, Clone, Debug)] +pub struct BenchCommonAncestorsArgs { + revision1: String, + revision2: String, +} + +/// Checks if the first commit is an ancestor of the second commit +#[derive(clap::Args, Clone, Debug)] +pub struct BenchIsAncestorArgs { + ancestor: String, + descendant: String, +} + +/// Walk revisions that are ancestors of the second argument but not ancestors +/// of the first +#[derive(clap::Args, Clone, Debug)] +pub struct BenchWalkRevsArgs { + unwanted: String, + wanted: String, +} + +/// Resolve a commit ID prefix +#[derive(clap::Args, Clone, Debug)] +pub struct BenchResolvePrefixArgs { + prefix: String, +} + +fn run_bench(ui: &mut Ui, id: &str, mut routine: R) -> io::Result<()> +where + R: (FnMut() -> O) + Copy, + O: Debug, +{ + let mut criterion = Criterion::default(); + let before = Instant::now(); + let result = routine(); + let after = Instant::now(); + writeln!( + ui, + "First run took {:?} and produced: {:?}", + after.duration_since(before), + result + )?; + criterion.bench_function(id, |bencher: &mut criterion::Bencher| { + bencher.iter(routine); + }); + Ok(()) +} + +pub(crate) fn cmd_bench( + ui: &mut Ui, + command: &CommandHelper, + subcommand: &BenchCommands, +) -> Result<(), CommandError> { + match subcommand { + BenchCommands::CommonAncestors(command_matches) => { + let workspace_command = command.workspace_helper(ui)?; + let commit1 = workspace_command.resolve_single_rev(&command_matches.revision1)?; + let commit2 = workspace_command.resolve_single_rev(&command_matches.revision2)?; + let index = workspace_command.repo().index(); + let routine = + || index.common_ancestors(&[commit1.id().clone()], &[commit2.id().clone()]); + run_bench( + ui, + &format!( + "commonancestors-{}-{}", + &command_matches.revision1, &command_matches.revision2 + ), + routine, + )?; + } + BenchCommands::IsAncestor(command_matches) => { + let workspace_command = command.workspace_helper(ui)?; + let ancestor_commit = + workspace_command.resolve_single_rev(&command_matches.ancestor)?; + let descendant_commit = + workspace_command.resolve_single_rev(&command_matches.descendant)?; + let index = workspace_command.repo().index(); + let routine = || index.is_ancestor(ancestor_commit.id(), descendant_commit.id()); + run_bench( + ui, + &format!( + "isancestor-{}-{}", + &command_matches.ancestor, &command_matches.descendant + ), + routine, + )?; + } + BenchCommands::WalkRevs(command_matches) => { + let workspace_command = command.workspace_helper(ui)?; + let unwanted_commit = + workspace_command.resolve_single_rev(&command_matches.unwanted)?; + let wanted_commit = workspace_command.resolve_single_rev(&command_matches.wanted)?; + let index = workspace_command.repo().index(); + let routine = || { + index + .walk_revs( + &[wanted_commit.id().clone()], + &[unwanted_commit.id().clone()], + ) + .count() + }; + run_bench( + ui, + &format!( + "walkrevs-{}-{}", + &command_matches.unwanted, &command_matches.wanted + ), + routine, + )?; + } + BenchCommands::ResolvePrefix(command_matches) => { + let workspace_command = command.workspace_helper(ui)?; + let prefix = HexPrefix::new(&command_matches.prefix).unwrap(); + let index = workspace_command.repo().index(); + let routine = || index.resolve_prefix(&prefix); + run_bench(ui, &format!("resolveprefix-{}", prefix.hex()), routine)?; + } + } + Ok(()) +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs index c9ffbdcd9..b0135b689 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[cfg(feature = "bench")] +mod bench; mod branch; mod git; mod operation; @@ -21,19 +23,16 @@ use std::fmt::Debug; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::sync::Arc; -use std::time::Instant; use std::{fs, io}; use clap::builder::NonEmptyStringValueParser; use clap::{ArgGroup, ArgMatches, Command, CommandFactory, FromArgMatches, Subcommand}; -use criterion::Criterion; use indexmap::{IndexMap, IndexSet}; use itertools::Itertools; use jujutsu_lib::backend::{CommitId, ObjectId, TreeValue}; use jujutsu_lib::commit::Commit; use jujutsu_lib::dag_walk::topo_order_reverse; use jujutsu_lib::default_index_store::{DefaultIndexStore, ReadonlyIndexWrapper}; -use jujutsu_lib::index::HexPrefix; use jujutsu_lib::matchers::EverythingMatcher; use jujutsu_lib::op_store::{RefTarget, WorkspaceId}; use jujutsu_lib::repo::{ReadonlyRepo, Repo}; @@ -67,8 +66,9 @@ use crate::{template_parser, text_util}; enum Commands { Abandon(AbandonArgs), Backout(BackoutArgs), + #[cfg(feature = "bench")] #[command(subcommand)] - Bench(BenchCommands), + Bench(bench::BenchCommands), #[command(subcommand)] Branch(branch::BranchSubcommand), #[command(alias = "print")] @@ -928,47 +928,6 @@ struct SupportMangenArgs {} #[derive(clap::Args, Clone, Debug)] struct SupportConfigSchemaArgs {} -/// Commands for benchmarking internal operations -#[derive(Subcommand, Clone, Debug)] -enum BenchCommands { - #[command(name = "commonancestors")] - CommonAncestors(BenchCommonAncestorsArgs), - #[command(name = "isancestor")] - IsAncestor(BenchIsAncestorArgs), - #[command(name = "walkrevs")] - WalkRevs(BenchWalkRevsArgs), - #[command(name = "resolveprefix")] - ResolvePrefix(BenchResolvePrefixArgs), -} - -/// Find the common ancestor(s) of a set of commits -#[derive(clap::Args, Clone, Debug)] -struct BenchCommonAncestorsArgs { - revision1: String, - revision2: String, -} - -/// Checks if the first commit is an ancestor of the second commit -#[derive(clap::Args, Clone, Debug)] -struct BenchIsAncestorArgs { - ancestor: String, - descendant: String, -} - -/// Walk revisions that are ancestors of the second argument but not ancestors -/// of the first -#[derive(clap::Args, Clone, Debug)] -struct BenchWalkRevsArgs { - unwanted: String, - wanted: String, -} - -/// Resolve a commit ID prefix -#[derive(clap::Args, Clone, Debug)] -struct BenchResolvePrefixArgs { - prefix: String, -} - /// Low-level commands not intended for users #[derive(Subcommand, Clone, Debug)] #[command(hide = true)] @@ -3127,100 +3086,6 @@ fn cmd_support( Ok(()) } -fn run_bench(ui: &mut Ui, id: &str, mut routine: R) -> io::Result<()> -where - R: (FnMut() -> O) + Copy, - O: Debug, -{ - let mut criterion = Criterion::default(); - let before = Instant::now(); - let result = routine(); - let after = Instant::now(); - writeln!( - ui, - "First run took {:?} and produced: {:?}", - after.duration_since(before), - result - )?; - criterion.bench_function(id, |bencher: &mut criterion::Bencher| { - bencher.iter(routine); - }); - Ok(()) -} - -fn cmd_bench( - ui: &mut Ui, - command: &CommandHelper, - subcommand: &BenchCommands, -) -> Result<(), CommandError> { - match subcommand { - BenchCommands::CommonAncestors(command_matches) => { - let workspace_command = command.workspace_helper(ui)?; - let commit1 = workspace_command.resolve_single_rev(&command_matches.revision1)?; - let commit2 = workspace_command.resolve_single_rev(&command_matches.revision2)?; - let index = workspace_command.repo().index(); - let routine = - || index.common_ancestors(&[commit1.id().clone()], &[commit2.id().clone()]); - run_bench( - ui, - &format!( - "commonancestors-{}-{}", - &command_matches.revision1, &command_matches.revision2 - ), - routine, - )?; - } - BenchCommands::IsAncestor(command_matches) => { - let workspace_command = command.workspace_helper(ui)?; - let ancestor_commit = - workspace_command.resolve_single_rev(&command_matches.ancestor)?; - let descendant_commit = - workspace_command.resolve_single_rev(&command_matches.descendant)?; - let index = workspace_command.repo().index(); - let routine = || index.is_ancestor(ancestor_commit.id(), descendant_commit.id()); - run_bench( - ui, - &format!( - "isancestor-{}-{}", - &command_matches.ancestor, &command_matches.descendant - ), - routine, - )?; - } - BenchCommands::WalkRevs(command_matches) => { - let workspace_command = command.workspace_helper(ui)?; - let unwanted_commit = - workspace_command.resolve_single_rev(&command_matches.unwanted)?; - let wanted_commit = workspace_command.resolve_single_rev(&command_matches.wanted)?; - let index = workspace_command.repo().index(); - let routine = || { - index - .walk_revs( - &[wanted_commit.id().clone()], - &[unwanted_commit.id().clone()], - ) - .count() - }; - run_bench( - ui, - &format!( - "walkrevs-{}-{}", - &command_matches.unwanted, &command_matches.wanted - ), - routine, - )?; - } - BenchCommands::ResolvePrefix(command_matches) => { - let workspace_command = command.workspace_helper(ui)?; - let prefix = HexPrefix::new(&command_matches.prefix).unwrap(); - let index = workspace_command.repo().index(); - let routine = || index.resolve_prefix(&prefix); - run_bench(ui, &format!("resolveprefix-{}", prefix.hex()), routine)?; - } - } - Ok(()) -} - fn cmd_debug( ui: &mut Ui, command: &CommandHelper, @@ -3604,7 +3469,8 @@ pub fn run_command( Commands::Sparse(sub_args) => cmd_sparse(ui, command_helper, sub_args), Commands::Git(sub_args) => git::cmd_git(ui, command_helper, sub_args), Commands::Support(sub_args) => cmd_support(ui, command_helper, sub_args), - Commands::Bench(sub_args) => cmd_bench(ui, command_helper, sub_args), + #[cfg(feature = "bench")] + Commands::Bench(sub_args) => bench::cmd_bench(ui, command_helper, sub_args), Commands::Debug(sub_args) => cmd_debug(ui, command_helper, sub_args), } }