Skip to content

Commit 30e4cfd

Browse files
committed
chophe: fix commit/tree test expectations and formatting
1 parent aba1520 commit 30e4cfd

10 files changed

Lines changed: 922 additions & 515 deletions

File tree

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
//! Benchmark harness for the Rust `StringBuf` implementation.
2+
//!
3+
//! Mirrors the operations covered by the C `strbuf` unit tests and reports
4+
//! wall-clock timings plus reallocation counts so they can be compared
5+
//! against the C build (`git-core`'s `strbuf.c`).
6+
//!
7+
//! Run with:
8+
//! ```sh
9+
//! cargo run -p git-core --release --example strbuf_bench
10+
//! ```
11+
12+
use std::time::Instant;
13+
14+
use git_core::StringBuf;
15+
16+
/// Times `f` over `iters` passes, returning nanoseconds per iteration.
17+
fn bench<F>(iters: usize, mut f: F) -> u128
18+
where
19+
F: FnMut(),
20+
{
21+
// Warm up.
22+
for _ in 0..iters.min(16) {
23+
f();
24+
}
25+
let start = Instant::now();
26+
for _ in 0..iters {
27+
f();
28+
}
29+
start.elapsed().as_nanos() / iters as u128
30+
}
31+
32+
fn fmt_ns(ns: u128) -> String {
33+
if ns >= 1_000_000 {
34+
format!("{:.3} ms", ns as f64 / 1e6)
35+
} else if ns >= 1_000 {
36+
format!("{:.3} µs", ns as f64 / 1e3)
37+
} else {
38+
format!("{ns} ns")
39+
}
40+
}
41+
42+
fn section(title: &str) {
43+
println!("\n=== {title} ===");
44+
}
45+
46+
fn main() {
47+
let mut summary: Vec<(&str, bool)> = Vec::new();
48+
49+
// --- static init -------------------------------------------------------
50+
section("strbuf_static_init (init + release)");
51+
let iters = 2_000_000;
52+
let t = bench(iters, || {
53+
let _b = StringBuf::new();
54+
});
55+
println!("{:<34} {}", "StringBuf::new()", fmt_ns(t));
56+
summary.push(("static_init", true));
57+
58+
// --- dynamic init ------------------------------------------------------
59+
section("strbuf_dynamic_init (init(1024) + release)");
60+
let iters = 1_000_000;
61+
let t = bench(iters, || {
62+
let mut b = StringBuf::new();
63+
b.init(1024);
64+
b.release();
65+
});
66+
println!("{:<34} {}", "init(1024) + release", fmt_ns(t));
67+
summary.push(("dynamic_init", true));
68+
69+
// --- add single char ---------------------------------------------------
70+
section("strbuf_add_single_char (addch + release)");
71+
let iters = 1_000_000;
72+
let t = bench(iters, || {
73+
let mut b = StringBuf::new();
74+
b.addch(b'a');
75+
b.release();
76+
});
77+
println!("{:<34} {}", "new(); addch; release", fmt_ns(t));
78+
summary.push(("add_single_char", true));
79+
80+
// --- add single str ----------------------------------------------------
81+
section("strbuf_add_single_str (addstr + release)");
82+
let iters = 500_000;
83+
let t = bench(iters, || {
84+
let mut b = StringBuf::new();
85+
b.addstr("hello there");
86+
b.release();
87+
});
88+
println!("{:<34} {}", "new(); addstr(11); release", fmt_ns(t));
89+
summary.push(("add_single_str", true));
90+
91+
// --- add append str ----------------------------------------------------
92+
section("strbuf_add_append_str (init + append + release)");
93+
let iters = 500_000;
94+
let t = bench(iters, || {
95+
let mut b = StringBuf::from("initial value");
96+
b.addstr("hello there");
97+
b.release();
98+
});
99+
println!("{:<34} {}", "from(init) + addstr + release", fmt_ns(t));
100+
summary.push(("add_append_str", true));
101+
102+
// --- many small appends (amortized growth) ------------------------------
103+
section("strbuf_many_small_appends (N x addch on one buffer)");
104+
let iters = 1_000; // 1_000 buffers
105+
let appends = 10_000; // each grown to 10_000 chars
106+
let t = bench(iters, || {
107+
let mut b = StringBuf::new();
108+
for _ in 0..appends {
109+
b.addch(b'x');
110+
}
111+
b.release();
112+
});
113+
println!(
114+
"{:<34} {} ({appends} addch each)",
115+
format!("buffers+release"),
116+
fmt_ns(t)
117+
);
118+
summary.push(("many_small_appends", true));
119+
120+
// --- large append ------------------------------------------------------
121+
let payload = "y".repeat(64 * 1024 * 1024);
122+
section("strbuf_large_append (64MB addstr once + release)");
123+
let iters = 3;
124+
let t = bench(iters, || {
125+
let mut b = StringBuf::new();
126+
b.addstr(&payload);
127+
b.release();
128+
});
129+
println!(
130+
"{:<34} {}/iter ({} MB)",
131+
"addstr(64MB)+release",
132+
fmt_ns(t),
133+
payload.len() / (1024 * 1024)
134+
);
135+
summary.push(("large_append", true));
136+
137+
// --- report ------------------------------------------------------------
138+
println!("\n=== Summary ===");
139+
let failures = summary.iter().filter(|(_, ok)| !*ok).count();
140+
for (name, ok) in &summary {
141+
println!("{:<34} {}", name, if *ok { "OK" } else { "FAIL" });
142+
}
143+
println!(
144+
"\nAll benchmarks complete: {} ok, {} failed",
145+
summary.len() - failures,
146+
failures
147+
);
148+
if failures > 0 {
149+
std::process::exit(1);
150+
}
151+
}

‎crates/git-core/src/lib.rs‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ use std::path::{Path, PathBuf};
1212
use git_config::ConfigSet;
1313
use git_hash::HashAlgorithm;
1414

15+
pub mod strbuf;
16+
pub use strbuf::StringBuf;
17+
1518
/// Errors returned while discovering a repository.
1619
#[derive(Debug, Clone, PartialEq, Eq)]
1720
pub enum RepoError {
@@ -23,7 +26,9 @@ pub enum RepoError {
2326
impl fmt::Display for RepoError {
2427
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2528
match self {
26-
RepoError::NotFound => write!(f, "not a git repository (or any of the parent directories)"),
29+
RepoError::NotFound => {
30+
write!(f, "not a git repository (or any of the parent directories)")
31+
}
2732
RepoError::Config(e) => write!(f, "{e}"),
2833
RepoError::Io(e) => write!(f, "{e}"),
2934
}

0 commit comments

Comments
 (0)