diff --git a/benches/parse.rs b/benches/parse.rs index e7b7b14..2e08c21 100644 --- a/benches/parse.rs +++ b/benches/parse.rs @@ -1,5 +1,5 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion, BenchmarkId}; -use nsv::{encode, decode, decode_bytes, decode_bytes_projected}; +use nsv::{encode, decode, decode_bytes, decode_bytes_projected, Reader}; fn generate_test_data(rows: usize, cells_per_row: usize) -> Vec> { (0..rows) @@ -151,6 +151,38 @@ fn bench_projection_wide(c: &mut Criterion) { group.finish(); } +// ── Reader (streaming) benchmarks ──────────────────────────────────── + +fn bench_reader_10k(c: &mut Criterion) { + let data = generate_test_data(10_000, 10); + let nsv = encode(&data); + let nsv_bytes = nsv.as_bytes(); + + c.bench_function("reader_10k_rows", |b| { + b.iter(|| { + let mut reader = Reader::new(std::io::Cursor::new(black_box(nsv_bytes))); + while let Some(row) = reader.next_row().unwrap() { + black_box(row); + } + }) + }); +} + +fn bench_reader_100k(c: &mut Criterion) { + let data = generate_test_data(100_000, 10); + let nsv = encode(&data); + let nsv_bytes = nsv.as_bytes(); + + c.bench_function("reader_100k_rows", |b| { + b.iter(|| { + let mut reader = Reader::new(std::io::Cursor::new(black_box(nsv_bytes))); + while let Some(row) = reader.next_row().unwrap() { + black_box(row); + } + }) + }); +} + criterion_group!( benches, bench_loads_small, @@ -162,5 +194,7 @@ criterion_group!( bench_projection_10k, bench_projection_100k, bench_projection_wide, + bench_reader_10k, + bench_reader_100k, ); criterion_main!(benches); diff --git a/src/lib.rs b/src/lib.rs index e09ad25..4cfeb1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,8 +27,8 @@ use std::io::{self, Read, Write}; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); -/// Threshold for using parallel parsing (64KB) -const PARALLEL_THRESHOLD: usize = 64 * 1024; +/// Threshold for using parallel parsing (bytes) +const PARALLEL_THRESHOLD: usize = 256 * 1024; /// Decode an NSV string into a seqseq. pub fn decode(s: &str) -> Vec> { @@ -65,7 +65,7 @@ pub fn decode_bytes<'a>(input: &'a [u8]) -> Vec>> { decode_bytes_sequential(input) } -/// Sequential implementation for small inputs (byte-level). +/// Sequential implementation (byte-level). fn decode_bytes_sequential<'a>(input: &'a [u8]) -> Vec>> { let mut data = Vec::new(); let mut row: Vec> = Vec::new(); @@ -759,11 +759,9 @@ mod tests { // Test parallel path with empty rows mixed in let mut data = Vec::new(); - // Create enough data to exceed 64KB threshold - for i in 0..10_000 { + for i in 0..40_000 { data.push(vec![format!("value{}", i)]); - // Add empty row every 100 rows if i % 100 == 0 { data.push(vec![]); } @@ -781,7 +779,7 @@ mod tests { // Test parallel path with cells containing escape sequences let mut data = Vec::new(); - for i in 0..10_000 { + for i in 0..20_000 { data.push(vec![ format!("Line 1\nLine 2 {}", i), format!("Backslash: \\ {}", i),