From 6bbd90a77b1b334daf5d8fb5032fea5d560a2da7 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 02:13:51 +0000 Subject: [PATCH] feat: Add cargo bench for logging performance This commit introduces benchmark tests for the logging functionality using the Criterion framework. The benchmarks measure the time taken to log messages of varying lengths (10, 100, 1000, and 10000 characters). The benchmark setup includes: - Addition of `criterion` as a dev-dependency. - A new benchmark file `benches/logging_benchmark.rs`. - Configuration in `Cargo.toml` to define the benchmark target. These benchmarks will help in assessing the performance characteristics of the logging system and serve as a regression test for future performance optimization efforts. The logger is configured to output to /dev/null (or NUL on Windows) to isolate logging overhead from disk I/O. --- Cargo.toml | 7 +++++ benches/logging_benchmark.rs | 54 ++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 benches/logging_benchmark.rs diff --git a/Cargo.toml b/Cargo.toml index 6cbb58e..3032e9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,10 @@ edition = "2018" crossbeam-channel = "0.4.4" log = { version = "0.4.6", features = ["std"] } time = "0.1.35" + +[dev-dependencies] +criterion = "0.3" + +[[bench]] +name = "logging_benchmark" +harness = false diff --git a/benches/logging_benchmark.rs b/benches/logging_benchmark.rs new file mode 100644 index 0000000..976fe2e --- /dev/null +++ b/benches/logging_benchmark.rs @@ -0,0 +1,54 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use fastlog::{LogBuilder}; // Logger is not directly used for initialization here +use log::{Level, LevelFilter, Record}; // Import Level for Record builder +use std::path::PathBuf; +// Timespec is not directly needed in the benchmark file if using default formatter +// and directly calling logger.log() + +fn bench_logging(c: &mut Criterion) { + let mut group = c.benchmark_group("logging"); + let sizes = [10, 100, 1000, 10000]; + + for size in sizes.iter() { + group.bench_function(format!("log_{}_chars", size), |b| { + // Initialize logger for each iteration to ensure flushing and re-creation if necessary, + // though for /dev/null it might not matter as much. + // However, the logger has a worker thread, re-creating it each time might be too much overhead. + // Let's create it once outside b.iter() + + let logger = LogBuilder::new() + .file(PathBuf::from(if cfg!(windows) { "NUL" } else { "/dev/null" })) + .max_log_level(LevelFilter::Info) + .build() + .expect("Failed to build logger for benchmarking."); + + let message_to_log = String::from_utf8(vec![b'a'; *size]).unwrap(); + + // The Record needs to be created inside b.iter if its content (like timestamp) should vary per iteration, + // but for benchmarking the logging of a fixed-size message, creating it once is fine. + // However, format_args! captures its arguments by reference. + // To be safe and typical for iter, we'll prepare the static parts outside + // and only construct the record with the message inside. + + b.iter(|| { + // Construct the record inside the iter block. + // The `log` crate's Record builder is suitable here. + let record = Record::builder() + .args(format_args!("{}", message_to_log)) + .level(Level::Info) // Use Level::Info here + .target("benchmark_target") // Provide a target + .module_path(Some("benchmark_module")) + .file(Some("benches/logging_benchmark.rs")) + .line(Some(line!())) // Use actual line number + .build(); + + // Call the log method directly on the logger instance + logger.log(black_box(&record)); + }); + }); + } + group.finish(); +} + +criterion_group!(benches, bench_logging); +criterion_main!(benches);