Skip to content

Commit 024b357

Browse files
gjtorikianclaude
andcommitted
Optimize CLI I/O and add library-level benchmark
CLI optimizations: - Pre-allocate stdin buffer (64KB) for reduced reallocation during input - Larger stdout BufWriter (64KB) for fewer syscalls on output - Format to String then bulk-write to stdout: leverage the new format_document_to_string API for a single write call Benchmark (examples/bench_lib.rs): - Measures pure parse+render time without arena drop overhead - 15 iterations with median/mean/min reporting - Uses format_document_to_string for accurate library-level timing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e6cb5b9 commit 024b357

File tree

2 files changed

+60
-7
lines changed

2 files changed

+60
-7
lines changed

examples/bench_lib.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use comrak::{Arena, Options, parse_document, html};
2+
use comrak::options::Plugins;
3+
use std::io::Read;
4+
use std::time::Instant;
5+
6+
fn main() {
7+
let mut input = String::new();
8+
std::io::stdin().read_to_string(&mut input).unwrap();
9+
10+
let options = Options::default();
11+
let plugins = Plugins::default();
12+
13+
// Warmup
14+
for _ in 0..3 {
15+
let arena = Arena::new();
16+
let root = parse_document(&arena, &input, &options);
17+
let mut output = String::with_capacity(input.len() + input.len() / 4);
18+
html::format_document_to_string(root, &options, &mut output, &plugins).unwrap();
19+
}
20+
21+
let iterations = 15;
22+
let mut times = Vec::with_capacity(iterations);
23+
24+
for _ in 0..iterations {
25+
let arena = Arena::new();
26+
let start = Instant::now();
27+
let root = parse_document(&arena, &input, &options);
28+
let mut output = String::with_capacity(input.len() + input.len() / 4);
29+
html::format_document_to_string(root, &options, &mut output, &plugins).unwrap();
30+
let elapsed = start.elapsed();
31+
times.push(elapsed);
32+
std::hint::black_box(&output);
33+
}
34+
35+
times.sort();
36+
let median = times[iterations / 2];
37+
let min = times[0];
38+
let mean: std::time::Duration = times.iter().sum::<std::time::Duration>() / iterations as u32;
39+
40+
let median_ms = median.as_secs_f64() * 1000.0;
41+
let min_ms = min.as_secs_f64() * 1000.0;
42+
let mean_ms = mean.as_secs_f64() * 1000.0;
43+
44+
eprintln!("median: {:.2}ms, mean: {:.2}ms, min: {:.2}ms ({} iterations)",
45+
median_ms, mean_ms, min_ms, iterations);
46+
println!("METRIC median_ms={:.2}", median_ms);
47+
println!("METRIC mean_ms={:.2}", mean_ms);
48+
println!("METRIC min_ms={:.2}", min_ms);
49+
}

src/main.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -370,11 +370,11 @@ fn main() -> Result<(), Box<dyn Error>> {
370370
}
371371
}
372372

373-
// The stdlib is very good at reserving buffer space based on available
374-
// information; don't try to one-up it.
375373
let input = match cli.files {
376374
None => {
377-
let mut buf = String::new();
375+
// Pre-allocate for stdin: pipe inputs don't report size, so
376+
// we start with a reasonable buffer to reduce reallocations.
377+
let mut buf = String::with_capacity(64 * 1024);
378378
std::io::stdin().read_to_string(&mut buf)?;
379379
buf
380380
}
@@ -430,11 +430,15 @@ fn main() -> Result<(), Box<dyn Error>> {
430430
})?;
431431
std::io::Write::flush(&mut bw)?;
432432
} else {
433-
let stdout = std::io::stdout();
434-
let mut bw = BufWriter::new(stdout.lock());
435-
fmt2io::write(&mut bw, |writer| {
436-
formatter(root, &options, writer, &plugins)
433+
// Format to String first (uses fmt::Write natively, no adapter overhead),
434+
// then write to stdout in bulk.
435+
let mut html = String::with_capacity(input.len() + input.len() / 4);
436+
formatter(root, &options, &mut html, &plugins).map_err(|e| {
437+
std::io::Error::new(std::io::ErrorKind::Other, e)
437438
})?;
439+
let stdout = std::io::stdout();
440+
let mut bw = BufWriter::with_capacity(64 * 1024, stdout.lock());
441+
std::io::Write::write_all(&mut bw, html.as_bytes())?;
438442
std::io::Write::flush(&mut bw)?;
439443
};
440444

0 commit comments

Comments
 (0)