commit 93d8a9a54ff8eae2c2997137c0e7bd75e632ec80
parent e32682e996ed465d71843253f435e8ef81297964
Author: ling0x <ling0x@users.noreply.github.com>
Date: Sat, 11 Apr 2026 12:04:14 +0100
tests: add benchmark
Diffstat:
6 files changed, 290 insertions(+), 3 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -3,5 +3,185 @@
version = 4
[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
name = "leetcode"
version = "0.1.0"
+dependencies = [
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "log"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.50.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "syn"
+version = "2.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319"
+dependencies = [
+ "nu-ansi-term",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
diff --git a/Cargo.toml b/Cargo.toml
@@ -4,3 +4,7 @@ version = "0.1.0"
edition = "2024"
[dependencies]
+
+[dev-dependencies]
+tracing = "*"
+tracing-subscriber = "*"
diff --git a/src/hash_table/two_sum.rs b/src/hash_table/two_sum.rs
@@ -23,17 +23,18 @@ pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
#[cfg(test)]
mod tests {
use crate::hash_table::two_sum::two_sum;
+ use crate::test_utils::benchmark::run_with_metrics;
#[test]
fn two_sum_test_1() {
- two_sum(vec![2, 7, 11, 15], 9);
+ let _ = run_with_metrics("two_sum_test_1", || two_sum(vec![2, 7, 11, 15], 9));
}
#[test]
fn two_sum_test_2() {
- two_sum(vec![3, 2, 3], 6);
+ let _ = run_with_metrics("two_sum_test_2", || two_sum(vec![3, 2, 3], 6));
}
#[test]
fn two_sum_test_3() {
- two_sum(vec![3, 2, 4], 6);
+ let _ = run_with_metrics("two_sum_test_3", || two_sum(vec![3, 2, 4], 6));
}
}
diff --git a/src/lib.rs b/src/lib.rs
@@ -1 +1,3 @@
pub mod hash_table;
+#[cfg(test)]
+pub mod test_utils;
diff --git a/src/test_utils/benchmark.rs b/src/test_utils/benchmark.rs
@@ -0,0 +1,99 @@
+use std::alloc::{GlobalAlloc, Layout, System};
+use std::sync::Once;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::time::{Duration, Instant};
+use tracing::info;
+
+static ALLOCATED: AtomicUsize = AtomicUsize::new(0);
+static TRACING_INIT: Once = Once::new();
+
+struct TrackingAllocator;
+
+unsafe impl GlobalAlloc for TrackingAllocator {
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ ALLOCATED.fetch_add(layout.size(), Ordering::SeqCst);
+ unsafe { System.alloc(layout) }
+ }
+
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ ALLOCATED.fetch_sub(layout.size(), Ordering::SeqCst);
+ unsafe { System.dealloc(ptr, layout) }
+ }
+}
+
+#[global_allocator]
+static TRACKING_ALLOCATOR: TrackingAllocator = TrackingAllocator;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub struct BenchmarkResult {
+ pub elapsed: Duration,
+ pub heap_delta_bytes: isize,
+}
+
+pub fn current_heap_allocated_bytes() -> usize {
+ ALLOCATED.load(Ordering::SeqCst)
+}
+
+pub fn init_benchmark_tracing() {
+ TRACING_INIT.call_once(|| {
+ let _ = tracing_subscriber::fmt()
+ .with_test_writer()
+ .with_target(false)
+ .with_level(false)
+ .without_time()
+ .compact()
+ .try_init();
+ });
+}
+
+fn format_duration(elapsed: Duration) -> String {
+ let nanos = elapsed.as_nanos();
+ if nanos >= 1_000_000_000 {
+ format!("{:.3} s", nanos as f64 / 1_000_000_000.0)
+ } else if nanos >= 1_000_000 {
+ format!("{:.3} ms", nanos as f64 / 1_000_000.0)
+ } else if nanos >= 1_000 {
+ format!("{:.3} us", nanos as f64 / 1_000.0)
+ } else {
+ format!("{nanos} ns")
+ }
+}
+
+fn format_signed_bytes(bytes: isize) -> String {
+ let sign = if bytes >= 0 { "+" } else { "-" };
+ let abs = (bytes as i128).abs() as f64;
+ if abs >= 1024.0 * 1024.0 {
+ format!("{sign}{:.2} MiB", abs / (1024.0 * 1024.0))
+ } else if abs >= 1024.0 {
+ format!("{sign}{:.2} KiB", abs / 1024.0)
+ } else {
+ format!("{sign}{} B", abs as u64)
+ }
+}
+
+pub fn run_with_metrics<T, F>(label: &str, test: F) -> (T, BenchmarkResult)
+where
+ F: FnOnce() -> T,
+{
+ init_benchmark_tracing();
+
+ let mem_before = current_heap_allocated_bytes() as isize;
+ let start = Instant::now();
+
+ let output = test();
+
+ let elapsed = start.elapsed();
+ let mem_after = current_heap_allocated_bytes() as isize;
+ let result = BenchmarkResult {
+ elapsed,
+ heap_delta_bytes: mem_after - mem_before,
+ };
+
+ info!(
+ "\n[benchmark] {label}\n time : {}\n heap delta : {}",
+ format_duration(result.elapsed),
+ format_signed_bytes(result.heap_delta_bytes)
+ );
+
+ (output, result)
+}
diff --git a/src/test_utils/mod.rs b/src/test_utils/mod.rs
@@ -0,0 +1 @@
+pub mod benchmark;