#![allow(missing_docs)]
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use rustledger_parser::logos_lexer::tokenize;
use rustledger_parser::parse;
#[allow(clippy::vec_init_then_push)]
fn generate_ledger(num_transactions: usize) -> String {
let mut lines = Vec::new();
lines.push("2024-01-01 open Assets:Bank:Checking USD".to_string());
lines.push("2024-01-01 open Expenses:Food USD".to_string());
lines.push("2024-01-01 open Expenses:Coffee USD".to_string());
lines.push("2024-01-01 open Expenses:Groceries USD".to_string());
lines.push("2024-01-01 open Expenses:Transport USD".to_string());
lines.push(String::new());
let categories = ["Food", "Coffee", "Groceries", "Transport"];
let payees = ["Store A", "Store B", "Cafe", "Gas Station", "Supermarket"];
let mut day = 1;
let mut month = 1;
let mut year = 2024;
for i in 0..num_transactions {
let category = categories[i % categories.len()];
let payee = payees[i % payees.len()];
let amount = format!("{:.2}", 10.0 + (i % 100) as f64);
lines.push(format!(
"{year:04}-{month:02}-{day:02} * \"{payee}\" \"Transaction {i}\""
));
lines.push(format!(" Expenses:{category} {amount} USD"));
lines.push(format!(" Assets:Bank:Checking -{amount} USD"));
lines.push(String::new());
day += 1;
if day > 28 {
day = 1;
month += 1;
if month > 12 {
month = 1;
year += 1;
}
}
}
lines.join("\n")
}
fn bench_parse_small(c: &mut Criterion) {
let ledger = generate_ledger(10);
let bytes = ledger.len();
let mut group = c.benchmark_group("parse_small");
group.throughput(Throughput::Bytes(bytes as u64));
group.bench_function("10_transactions", |b| {
b.iter(|| parse(std::hint::black_box(&ledger)));
});
group.finish();
}
fn bench_parse_medium(c: &mut Criterion) {
let ledger = generate_ledger(100);
let bytes = ledger.len();
let mut group = c.benchmark_group("parse_medium");
group.throughput(Throughput::Bytes(bytes as u64));
group.bench_function("100_transactions", |b| {
b.iter(|| parse(std::hint::black_box(&ledger)));
});
group.finish();
}
fn bench_parse_large(c: &mut Criterion) {
let ledger = generate_ledger(1000);
let bytes = ledger.len();
let mut group = c.benchmark_group("parse_large");
group.throughput(Throughput::Bytes(bytes as u64));
group.bench_function("1000_transactions", |b| {
b.iter(|| parse(std::hint::black_box(&ledger)));
});
group.finish();
}
fn bench_parse_scaling(c: &mut Criterion) {
let mut group = c.benchmark_group("parse_scaling");
for size in [10, 50, 100, 500, 1000] {
let ledger = generate_ledger(size);
group.throughput(Throughput::Bytes(ledger.len() as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &ledger, |b, ledger| {
b.iter(|| parse(std::hint::black_box(ledger)));
});
}
group.finish();
}
fn bench_tokenize_small(c: &mut Criterion) {
let ledger = generate_ledger(10);
let bytes = ledger.len();
let mut group = c.benchmark_group("tokenize_small");
group.throughput(Throughput::Bytes(bytes as u64));
group.bench_function("10_transactions", |b| {
b.iter(|| tokenize(std::hint::black_box(&ledger)));
});
group.finish();
}
fn bench_tokenize_large(c: &mut Criterion) {
let ledger = generate_ledger(1000);
let bytes = ledger.len();
let mut group = c.benchmark_group("tokenize_large");
group.throughput(Throughput::Bytes(bytes as u64));
group.bench_function("1000_transactions", |b| {
b.iter(|| tokenize(std::hint::black_box(&ledger)));
});
group.finish();
}
fn bench_tokenize_scaling(c: &mut Criterion) {
let mut group = c.benchmark_group("tokenize_scaling");
for size in [10, 50, 100, 500, 1000] {
let ledger = generate_ledger(size);
group.throughput(Throughput::Bytes(ledger.len() as u64));
group.bench_with_input(BenchmarkId::from_parameter(size), &ledger, |b, ledger| {
b.iter(|| tokenize(std::hint::black_box(ledger)));
});
}
group.finish();
}
fn bench_tokenize_vs_parse(c: &mut Criterion) {
let ledger = generate_ledger(1000);
let bytes = ledger.len();
let mut group = c.benchmark_group("tokenize_vs_parse");
group.throughput(Throughput::Bytes(bytes as u64));
group.bench_function("tokenize_only", |b| {
b.iter(|| tokenize(std::hint::black_box(&ledger)));
});
group.bench_function("full_parse", |b| {
b.iter(|| parse(std::hint::black_box(&ledger)));
});
group.finish();
}
criterion_group!(
benches,
bench_parse_small,
bench_parse_medium,
bench_parse_large,
bench_parse_scaling,
bench_tokenize_small,
bench_tokenize_large,
bench_tokenize_scaling,
bench_tokenize_vs_parse,
);
criterion_main!(benches);