leetcode

Log | Files | Refs | README

commit 93d8a9a54ff8eae2c2997137c0e7bd75e632ec80
parent e32682e996ed465d71843253f435e8ef81297964
Author: ling0x <ling0x@users.noreply.github.com>
Date:   Sat, 11 Apr 2026 12:04:14 +0100

tests: add benchmark

Diffstat:
MCargo.lock | 180+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MCargo.toml | 4++++
Msrc/hash_table/two_sum.rs | 7++++---
Msrc/lib.rs | 2++
Asrc/test_utils/benchmark.rs | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_utils/mod.rs | 1+
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;