Repository navigation
fix(fs): cut round trips for rg, find and tree walkers on remote backends #2816
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
e07e4d3
fix(fs): cut round trips for rg, find and tree walkers on remote back…
chaliy b4c8d20
fix(fs): bound walk batches and rg reads so huge trees never load at …
chaliy 7c155c3
chore(bench): save remote_fs results with bounded walk batches
chaliy d9c52b6
chore(knowledge): merge remote VFS log entry after rebase
chaliy 022e2ba
fix(fs): refuse index answers after a mount change; lease-check searc…
chaliy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,226 @@ | ||
| //! Tree-walking builtins over a simulated remote filesystem. | ||
| //! | ||
| //! Remote VFS backends (a database, an object store, a network share) pay | ||
| //! one round trip per `FileSystem` call, ~10 ms in production. What makes a | ||
| //! command slow there is its call count, not CPU. This bench loads a real | ||
| //! tree, the bashkit checkout itself (`git ls-files`, ~3.7k files), into a | ||
| //! `CountingFs` and: | ||
| //! | ||
| //! 1. prints, per command and backend, the call counts and the time they | ||
| //! would cost at 10 ms per call (`--counts` or always, before timing); | ||
| //! 2. times each command with a simulated per-call latency | ||
| //! (`BASHKIT_BENCH_LATENCY_US`, default 100 us) under criterion. | ||
| //! | ||
| //! Backends: `plain` (no index, `walk` = `read_dir` per directory), `index` | ||
| //! (`SearchCapable` content index), `index+walk` (index plus a one-call bulk | ||
| //! `walk`, like a path-prefix query). | ||
| //! | ||
| //! Run with: `cargo bench --bench remote_fs` | ||
| //! Counts only: `cargo bench --bench remote_fs -- --counts` | ||
|
|
||
| use bashkit::testing::{CallCounts, CountingFs}; | ||
| use bashkit::{Bash, FileSystem, FsLimits}; | ||
| use criterion::{BenchmarkId, Criterion, criterion_group}; | ||
| use std::path::{Path, PathBuf}; | ||
| use std::sync::Arc; | ||
| use std::time::Duration; | ||
| use tokio::runtime::Runtime; | ||
|
|
||
| /// Per-call latency the production report is about. | ||
| const REMOTE_CALL_MS: f64 = 10.0; | ||
| /// Files above this are skipped (generated fixtures, lockfiles). | ||
| const MAX_FILE_BYTES: u64 = 1 << 20; | ||
|
|
||
| /// Commands under test, run with cwd `/workspace` (the checkout root). | ||
| const COMMANDS: &[&str] = &[ | ||
| // The production report's commands (no match in this checkout: worst case). | ||
| "rg -l markkit crates", | ||
| "grep -rln markkit crates", | ||
| "find /workspace -path '*markkit*'", | ||
| // A rare match and a common one. | ||
| "rg -l SearchCapable crates", | ||
| "rg -l --no-ignore SearchCapable crates", | ||
| "grep -rl SearchCapable crates", | ||
| "rg -c fn crates/bashkit/src/builtins", | ||
| "find crates -type f -name '*.rs'", | ||
| "find crates -ls", | ||
| "ls -R crates", | ||
| "du -s crates", | ||
| "tree crates", | ||
| "tar -cf /tmp/src.tar crates/bashkit/src/builtins", | ||
| "cp -r crates/bashkit/src/builtins /tmp/builtins-copy", | ||
| ]; | ||
|
|
||
| #[derive(Clone, Copy)] | ||
| enum Backend { | ||
| Plain, | ||
| Index, | ||
| IndexWalk, | ||
| } | ||
|
|
||
| impl Backend { | ||
| const ALL: [Backend; 3] = [Backend::Plain, Backend::Index, Backend::IndexWalk]; | ||
|
|
||
| fn name(self) -> &'static str { | ||
| match self { | ||
| Backend::Plain => "plain", | ||
| Backend::Index => "index", | ||
| Backend::IndexWalk => "index+walk", | ||
| } | ||
| } | ||
|
|
||
| fn fs(self) -> CountingFs { | ||
| let fs = CountingFs::new(); | ||
| match self { | ||
| Backend::Plain => fs, | ||
| Backend::Index => fs.with_index(), | ||
| Backend::IndexWalk => fs.with_index().with_native_walk(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Repository root and its tracked files. | ||
| fn checkout_files() -> (PathBuf, Vec<String>) { | ||
| let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("../.."); | ||
| let out = std::process::Command::new("git") | ||
| .arg("-C") | ||
| .arg(&root) | ||
| .args(["ls-files", "-z"]) | ||
| .output() | ||
| .expect("git ls-files (the bench needs a git checkout)"); | ||
| let files = out | ||
| .stdout | ||
| .split(|b| *b == 0) | ||
| .filter(|f| !f.is_empty()) | ||
| .map(|f| String::from_utf8_lossy(f).into_owned()) | ||
| .collect(); | ||
| (root, files) | ||
| } | ||
|
|
||
| /// Copy the checkout into a fresh backend under `/workspace`; `latency` | ||
| /// applies after seeding. | ||
| fn load(rt: &Runtime, backend: Backend, latency: Duration) -> (Arc<CountingFs>, usize) { | ||
| let (root, files) = checkout_files(); | ||
| let fs = Arc::new(backend.fs().with_limits(FsLimits::unlimited())); | ||
| let mut loaded = 0; | ||
| rt.block_on(async { | ||
| // `.git` marks the tree as a repository, so `.gitignore` applies. | ||
| fs.mkdir(Path::new("/workspace/.git"), true).await.unwrap(); | ||
| for rel in &files { | ||
| let host = root.join(rel); | ||
| let Ok(meta) = std::fs::symlink_metadata(&host) else { | ||
| continue; | ||
| }; | ||
| if !meta.is_file() || meta.len() > MAX_FILE_BYTES { | ||
| continue; | ||
| } | ||
| let Ok(content) = std::fs::read(&host) else { | ||
| continue; | ||
| }; | ||
| let path = PathBuf::from(format!("/workspace/{rel}")); | ||
| if let Some(parent) = path.parent() { | ||
| fs.mkdir(parent, true).await.unwrap(); | ||
| } | ||
| fs.write_file(&path, &content).await.unwrap(); | ||
| loaded += 1; | ||
| } | ||
| }); | ||
| fs.set_latency(latency); | ||
| (fs, loaded) | ||
| } | ||
|
|
||
| fn bash_for(fs: &Arc<CountingFs>) -> Bash { | ||
| let fs_dyn: Arc<dyn FileSystem> = fs.clone(); | ||
| Bash::builder() | ||
| .fs(fs_dyn) | ||
| .cwd("/workspace") | ||
| .limits(bashkit::ExecutionLimits::default().timeout(Duration::from_secs(600))) | ||
| .build() | ||
| } | ||
|
|
||
| fn run_once(rt: &Runtime, fs: &Arc<CountingFs>, cmd: &str) -> (CallCounts, Duration) { | ||
| let mut bash = bash_for(fs); | ||
| rt.block_on(async { | ||
| let _ = bash.exec("rm -rf /tmp/src.tar /tmp/builtins-copy").await; | ||
| }); | ||
| fs.reset(); | ||
| let start = std::time::Instant::now(); | ||
| let r = rt.block_on(bash.exec(&format!("{cmd} > /dev/null"))); | ||
| let elapsed = start.elapsed(); | ||
| if let Ok(r) = &r | ||
| && r.exit_code > 1 | ||
| { | ||
| eprintln!("warning: `{cmd}` exited {}: {}", r.exit_code, r.stderr); | ||
| } | ||
| (fs.counts(), elapsed) | ||
| } | ||
|
|
||
| /// Markdown table of call counts and projected remote time. | ||
| fn print_counts(rt: &Runtime) { | ||
| println!("\n## Round trips per command (bashkit checkout, cwd = repo root)\n"); | ||
| let mut header_done = false; | ||
| for backend in Backend::ALL { | ||
| let (fs, loaded) = load(rt, backend, Duration::ZERO); | ||
| if !header_done { | ||
| println!("{loaded} files loaded. Projected time = calls x {REMOTE_CALL_MS} ms.\n"); | ||
| println!( | ||
| "| command | backend | calls | read_file | read_dir | stat+lstat+exists | walk | search | at 10 ms |" | ||
| ); | ||
| println!("|---|---|---:|---:|---:|---:|---:|---:|---:|"); | ||
| header_done = true; | ||
| } | ||
| for cmd in COMMANDS { | ||
| let (c, _) = run_once(rt, &fs, cmd); | ||
| println!( | ||
| "| `{cmd}` | {} | {} | {} | {} | {} | {} | {} | {:.1} s |", | ||
| backend.name(), | ||
| c.total(), | ||
| c.read_file, | ||
| c.read_dir, | ||
| c.metadata(), | ||
| c.walk, | ||
| c.search, | ||
| c.total() as f64 * REMOTE_CALL_MS / 1000.0 | ||
| ); | ||
| } | ||
| } | ||
| println!(); | ||
| } | ||
|
|
||
| fn latency() -> Duration { | ||
| let us = std::env::var("BASHKIT_BENCH_LATENCY_US") | ||
| .ok() | ||
| .and_then(|v| v.parse().ok()) | ||
| .unwrap_or(100); | ||
| Duration::from_micros(us) | ||
| } | ||
|
|
||
| fn bench_remote(c: &mut Criterion) { | ||
| let rt = Runtime::new().unwrap(); | ||
| let latency = latency(); | ||
| let mut group = c.benchmark_group(format!("remote_fs_{}us", latency.as_micros())); | ||
| group.sample_size(10); | ||
| group.measurement_time(Duration::from_secs(5)); | ||
| for backend in Backend::ALL { | ||
| let (fs, _) = load(&rt, backend, latency); | ||
| for cmd in COMMANDS { | ||
| group.bench_with_input(BenchmarkId::new(backend.name(), cmd), cmd, |b, cmd| { | ||
| b.iter(|| run_once(&rt, &fs, cmd)) | ||
| }); | ||
| } | ||
| } | ||
| group.finish(); | ||
| } | ||
|
|
||
| criterion_group!(benches, bench_remote); | ||
|
|
||
| fn main() { | ||
| let counts_only = std::env::args().any(|a| a == "--counts"); | ||
| let rt = Runtime::new().unwrap(); | ||
| print_counts(&rt); | ||
| if counts_only { | ||
| return; | ||
| } | ||
| benches(); | ||
| Criterion::default().configure_from_args().final_summary(); | ||
| } |
120 changes: 120 additions & 0 deletions
120
crates/bashkit/benches/results/criterion-remote_fs-linux-x86_64-1793656706.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,120 @@ | ||
| # remote_fs bench, bashkit checkout (598ebb4 + this change) | ||
|
|
||
| Host: cloud container, linux x86_64. Tree: `git ls-files` of this repo, 3,720 files under `/workspace` (a `.git` dir present so `.gitignore` applies). Command: `cargo bench --bench remote_fs`. | ||
|
|
||
| Call counts are the signal: on a remote backend each call is a round trip ("at 10 ms" column). | ||
|
|
||
| ## Before (origin/main, same CountingFs, no `walk` hook) | ||
|
|
||
| | command | backend | calls | read_file | read_dir | stat+lstat+exists | walk | search | at 10 ms | | ||
| |---|---|---:|---:|---:|---:|---:|---:|---:| | ||
| | `rg -l markkit crates` | index | 176281 | 7101 | 1981 | 167199 | 0 | 0 | 1762.8 s | | ||
| | `grep -rln markkit crates` | index | 23709 | 3140 | 1982 | 18587 | 0 | 0 | 237.1 s | | ||
| | `find /workspace -path '*markkit*'` | index | 7831 | 0 | 2055 | 5776 | 0 | 0 | 78.3 s | | ||
| | `rg -l SearchCapable crates` | index | 176281 | 7101 | 1981 | 167199 | 0 | 0 | 1762.8 s | | ||
| | `rg -l --no-ignore SearchCapable crates` | index | 5116 | 3133 | 1981 | 2 | 0 | 0 | 51.2 s | | ||
| | `grep -rl SearchCapable crates` | index | 23709 | 3140 | 1982 | 18587 | 0 | 0 | 237.1 s | | ||
| | `rg -c fn crates/bashkit/src/builtins` | index | 1255 | 264 | 17 | 974 | 0 | 0 | 12.6 s | | ||
| | `find crates -type f -name '*.rs'` | index | 7105 | 0 | 1982 | 5123 | 0 | 0 | 71.0 s | | ||
| | `find crates -ls` | index | 9087 | 0 | 3964 | 5123 | 0 | 0 | 90.9 s | | ||
| | `ls -R crates` | index | 1982 | 0 | 1981 | 1 | 0 | 0 | 19.8 s | | ||
| | `du -s crates` | index | 7105 | 0 | 1982 | 5123 | 0 | 0 | 71.0 s | | ||
| | `tree crates` | index | 1982 | 0 | 1981 | 1 | 0 | 0 | 19.8 s | | ||
| | `tar -cf /tmp/src.tar crates/bashkit/src/builtins` | index | 463 | 212 | 17 | 233 | 0 | 0 | 4.6 s | | ||
| | `cp -r crates/bashkit/src/builtins /tmp/builtins-copy` | index | 2785 | 0 | 17 | 2522 | 0 | 0 | 27.9 s | | ||
|
|
||
| ## After | ||
|
|
||
| | command | backend | calls | read_file | read_dir | stat+lstat+exists | walk | search | at 10 ms | | ||
| |---|---|---:|---:|---:|---:|---:|---:|---:| | ||
| | `rg -l markkit crates` | plain | 5127 | 3135 | 1983 | 9 | 0 | 0 | 51.3 s | | ||
| | `grep -rln markkit crates` | plain | 5125 | 3140 | 1982 | 3 | 0 | 0 | 51.2 s | | ||
| | `find /workspace -path '*markkit*'` | plain | 2056 | 0 | 2055 | 1 | 0 | 0 | 20.6 s | | ||
| | `rg -l SearchCapable crates` | plain | 5127 | 3135 | 1983 | 9 | 0 | 0 | 51.3 s | | ||
| | `rg -l --no-ignore SearchCapable crates` | plain | 5116 | 3133 | 1981 | 2 | 0 | 0 | 51.2 s | | ||
| | `grep -rl SearchCapable crates` | plain | 5125 | 3140 | 1982 | 3 | 0 | 0 | 51.2 s | | ||
| | `rg -c fn crates/bashkit/src/builtins` | plain | 245 | 214 | 22 | 9 | 0 | 0 | 2.5 s | | ||
| | `find crates -type f -name '*.rs'` | plain | 1983 | 0 | 1982 | 1 | 0 | 0 | 19.8 s | | ||
| | `find crates -ls` | plain | 1983 | 0 | 1982 | 1 | 0 | 0 | 19.8 s | | ||
| | `ls -R crates` | plain | 1982 | 0 | 1981 | 1 | 0 | 0 | 19.8 s | | ||
| | `du -s crates` | plain | 1983 | 0 | 1982 | 1 | 0 | 0 | 19.8 s | | ||
| | `tree crates` | plain | 1982 | 0 | 1981 | 1 | 0 | 0 | 19.8 s | | ||
| | `tar -cf /tmp/src.tar crates/bashkit/src/builtins` | plain | 233 | 212 | 17 | 3 | 0 | 0 | 2.3 s | | ||
| | `cp -r crates/bashkit/src/builtins /tmp/builtins-copy` | plain | 780 | 0 | 17 | 517 | 0 | 0 | 7.8 s | | ||
| | `rg -l markkit crates` | index | 3 | 0 | 0 | 2 | 0 | 1 | 0.0 s | | ||
| | `grep -rln markkit crates` | index | 2 | 0 | 0 | 1 | 0 | 1 | 0.0 s | | ||
| | `find /workspace -path '*markkit*'` | index | 2056 | 0 | 2055 | 1 | 0 | 0 | 20.6 s | | ||
| | `rg -l SearchCapable crates` | index | 33 | 15 | 8 | 9 | 0 | 1 | 0.3 s | | ||
| | `rg -l --no-ignore SearchCapable crates` | index | 16 | 13 | 0 | 2 | 0 | 1 | 0.2 s | | ||
| | `grep -rl SearchCapable crates` | index | 28 | 13 | 0 | 14 | 0 | 1 | 0.3 s | | ||
| | `rg -c fn crates/bashkit/src/builtins` | index | 242 | 210 | 22 | 9 | 0 | 1 | 2.4 s | | ||
| | `find crates -type f -name '*.rs'` | index | 1983 | 0 | 1982 | 1 | 0 | 0 | 19.8 s | | ||
| | `find crates -ls` | index | 1983 | 0 | 1982 | 1 | 0 | 0 | 19.8 s | | ||
| | `ls -R crates` | index | 1982 | 0 | 1981 | 1 | 0 | 0 | 19.8 s | | ||
| | `du -s crates` | index | 1983 | 0 | 1982 | 1 | 0 | 0 | 19.8 s | | ||
| | `tree crates` | index | 1982 | 0 | 1981 | 1 | 0 | 0 | 19.8 s | | ||
| | `tar -cf /tmp/src.tar crates/bashkit/src/builtins` | index | 233 | 212 | 17 | 3 | 0 | 0 | 2.3 s | | ||
| | `cp -r crates/bashkit/src/builtins /tmp/builtins-copy` | index | 780 | 0 | 17 | 517 | 0 | 0 | 7.8 s | | ||
| | `rg -l markkit crates` | index+walk | 3 | 0 | 0 | 2 | 0 | 1 | 0.0 s | | ||
| | `grep -rln markkit crates` | index+walk | 2 | 0 | 0 | 1 | 0 | 1 | 0.0 s | | ||
| | `find /workspace -path '*markkit*'` | index+walk | 2 | 0 | 0 | 1 | 1 | 0 | 0.0 s | | ||
| | `rg -l SearchCapable crates` | index+walk | 33 | 15 | 8 | 9 | 0 | 1 | 0.3 s | | ||
| | `rg -l --no-ignore SearchCapable crates` | index+walk | 16 | 13 | 0 | 2 | 0 | 1 | 0.2 s | | ||
| | `grep -rl SearchCapable crates` | index+walk | 28 | 13 | 0 | 14 | 0 | 1 | 0.3 s | | ||
| | `rg -c fn crates/bashkit/src/builtins` | index+walk | 242 | 210 | 22 | 9 | 0 | 1 | 2.4 s | | ||
| | `find crates -type f -name '*.rs'` | index+walk | 2 | 0 | 0 | 1 | 1 | 0 | 0.0 s | | ||
| | `find crates -ls` | index+walk | 2 | 0 | 0 | 1 | 1 | 0 | 0.0 s | | ||
| | `ls -R crates` | index+walk | 1982 | 0 | 1981 | 1 | 0 | 0 | 19.8 s | | ||
| | `du -s crates` | index+walk | 2 | 0 | 0 | 1 | 1 | 0 | 0.0 s | | ||
| | `tree crates` | index+walk | 1982 | 0 | 1981 | 1 | 0 | 0 | 19.8 s | | ||
| | `tar -cf /tmp/src.tar crates/bashkit/src/builtins` | index+walk | 233 | 212 | 17 | 3 | 0 | 0 | 2.3 s | | ||
| | `cp -r crates/bashkit/src/builtins /tmp/builtins-copy` | index+walk | 780 | 0 | 17 | 517 | 0 | 0 | 7.8 s | | ||
|
|
||
| ## Criterion wall time, 100 us simulated latency per call | ||
|
|
||
| Run concurrently with a test build, so noisy. Walk-heavy rows are CPU-bound by `InMemoryFs::read_dir`, which scans every entry per call (O(entries x dirs)); that is the in-memory backend's cost, not round trips. | ||
|
|
||
| | bench | median | | ||
| |---|---:| | ||
| | `plain/rg -l markkit crates` | 3.1882 s | | ||
| | `plain/grep -rln markkit crates` | 2.9633 s | | ||
| | `plain/find /workspace -path '*markkit*'` | 2.5221 s | | ||
| | `plain/rg -l SearchCapable crates` | 3.2156 s | | ||
| | `plain/rg -l --no-ignore SearchCapable crates` | 3.0005 s | | ||
| | `plain/grep -rl SearchCapable crates` | 2.9670 s | | ||
| | `plain/rg -c fn crates/bashkit/src/builtins` | 67.001 ms | | ||
| | `plain/find crates -type f -name '*.rs'` | 2.3600 s | | ||
| | `plain/find crates -ls` | 2.3169 s | | ||
| | `plain/ls -R crates` | 2.4517 s | | ||
| | `plain/du -s crates` | 2.4584 s | | ||
| | `plain/tree crates` | 2.6678 s | | ||
| | `plain/tar -cf /tmp/src.tar crates/bashkit/src/builtins` | 48.890 ms | | ||
| | `plain/cp -r crates/bashkit/src/builtins /tmp/builtins-copy` | 199.99 ms | | ||
| | `index/rg -l markkit crates` | 79.563 ms | | ||
| | `index/grep -rln markkit crates` | 80.336 ms | | ||
| | `index/find /workspace -path '*markkit*'` | 2.9004 s | | ||
| | `index/rg -l SearchCapable crates` | 94.123 ms | | ||
| | `index/rg -l --no-ignore SearchCapable crates` | 82.366 ms | | ||
| | `index/grep -rl SearchCapable crates` | 80.259 ms | | ||
| | `index/rg -c fn crates/bashkit/src/builtins` | 92.512 ms | | ||
| | `index/find crates -type f -name '*.rs'` | 2.8683 s | | ||
| | `index/find crates -ls` | 2.8529 s | | ||
| | `index/ls -R crates` | 2.9771 s | | ||
| | `index/du -s crates` | 3.0325 s | | ||
| | `index/tree crates` | 3.0087 s | | ||
| | `index/tar -cf /tmp/src.tar crates/bashkit/src/builtins` | 56.475 ms | | ||
| | `index/cp -r crates/bashkit/src/builtins /tmp/builtins-copy` | 263.19 ms | | ||
| | `index+walk/rg -l markkit crates` | 80.651 ms | | ||
| | `index+walk/grep -rln markkit crates` | 78.429 ms | | ||
| | `index+walk/find /workspace -path '*markkit*'` | 2.6263 s | | ||
| | `index+walk/rg -l SearchCapable crates` | 96.695 ms | | ||
| | `index+walk/rg -l --no-ignore SearchCapable crates` | 81.962 ms | | ||
| | `index+walk/grep -rl SearchCapable crates` | 96.617 ms | | ||
| | `index+walk/rg -c fn crates/bashkit/src/builtins` | 96.170 ms | | ||
| | `index+walk/find crates -type f -name '*.rs'` | 2.5372 s | | ||
| | `index+walk/find crates -ls` | 2.5755 s | | ||
| | `index+walk/ls -R crates` | 2.8837 s | | ||
| | `index+walk/du -s crates` | 2.6339 s | | ||
| | `index+walk/tree crates` | 3.0670 s | | ||
| | `index+walk/tar -cf /tmp/src.tar crates/bashkit/src/builtins` | 51.691 ms | | ||
| | `index+walk/cp -r crates/bashkit/src/builtins /tmp/builtins-copy` | 249.46 ms | | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[P2] Generated Criterion reports are committed (
crates/bashkit/benches/results/criterion-remote_fs-*.md, e.g. the table with per-command round-trip counts). These are machine- and run-specific artifacts that will churn on every bench run. Fix: gitignorebenches/results/(orcriterion/) and keep at most a hand-written summary in the PR/docs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keeping these: the repo contract (AGENTS.md, Benches) requires saving criterion results under
crates/bashkit/benches/results/ascriterion-<bench>-<moniker>-<timestamp>.md, so future runs have a baseline to diff against. Each run adds a new timestamped file, and existing files are never rewritten.Generated by Claude Code