@@ -9,117 +9,149 @@ const ITERATIONS: u64 = 10_000_000;
99const THREAD_COUNTS : & [ usize ] = & [ 2 , 4 , 8 , 16 ] ;
1010
1111fn bench_std_mutex_uncontended ( ) -> Duration {
12- let mutex = std:: sync:: Mutex :: new ( 0u64 ) ;
13- let start = Instant :: now ( ) ;
14- for _ in 0 ..ITERATIONS {
15- let mut guard = mutex. lock ( ) . unwrap ( ) ;
16- * guard += 1 ;
17- }
18- start. elapsed ( )
12+ let mutex = std:: sync:: Mutex :: new ( 0u64 ) ;
13+ let start = Instant :: now ( ) ;
14+ for _ in 0 ..ITERATIONS {
15+ let mut guard = mutex. lock ( ) . unwrap ( ) ;
16+ * guard += 1 ;
17+ }
18+ start. elapsed ( )
1919}
2020
2121fn bench_parking_lot_uncontended ( ) -> Duration {
22- let mutex = parking_lot:: Mutex :: new ( 0u64 ) ;
23- let start = Instant :: now ( ) ;
24- for _ in 0 ..ITERATIONS {
25- let mut guard = mutex. lock ( ) ;
26- * guard += 1 ;
27- }
28- start. elapsed ( )
22+ let mutex = parking_lot:: Mutex :: new ( 0u64 ) ;
23+ let start = Instant :: now ( ) ;
24+ for _ in 0 ..ITERATIONS {
25+ let mut guard = mutex. lock ( ) ;
26+ * guard += 1 ;
27+ }
28+ start. elapsed ( )
2929}
3030
3131fn bench_std_mutex_contended ( threads : usize ) -> Duration {
32- let mutex = Arc :: new ( std:: sync:: Mutex :: new ( 0u64 ) ) ;
33- let start = Instant :: now ( ) ;
34-
35- let handles: Vec < _ > = ( 0 ..threads)
36- . map ( |_| {
37- let mutex = Arc :: clone ( & mutex) ;
38- thread:: spawn ( move || {
39- for _ in 0 ..( ITERATIONS / threads as u64 ) {
40- let mut guard = mutex. lock ( ) . unwrap ( ) ;
41- * guard += 1 ;
42- }
43- } )
44- } )
45- . collect ( ) ;
46-
47- for handle in handles {
48- handle. join ( ) . unwrap ( ) ;
49- }
50- start. elapsed ( )
32+ let mutex = Arc :: new ( std:: sync:: Mutex :: new ( 0u64 ) ) ;
33+ let start = Instant :: now ( ) ;
34+
35+ let handles: Vec < _ > = ( 0 ..threads)
36+ . map ( |_| {
37+ let mutex = Arc :: clone ( & mutex) ;
38+ thread:: spawn ( move || {
39+ for _ in 0 ..( ITERATIONS / threads as u64 ) {
40+ let mut guard = mutex. lock ( ) . unwrap ( ) ;
41+ * guard += 1 ;
42+ }
43+ } )
44+ } )
45+ . collect ( ) ;
46+
47+ for handle in handles {
48+ handle. join ( ) . unwrap ( ) ;
49+ }
50+ start. elapsed ( )
5151}
5252
5353fn bench_parking_lot_contended ( threads : usize ) -> Duration {
54- let mutex = Arc :: new ( parking_lot:: Mutex :: new ( 0u64 ) ) ;
55- let start = Instant :: now ( ) ;
56-
57- let handles: Vec < _ > = ( 0 ..threads)
58- . map ( |_| {
59- let mutex = Arc :: clone ( & mutex) ;
60- thread:: spawn ( move || {
61- for _ in 0 ..( ITERATIONS / threads as u64 ) {
62- let mut guard = mutex. lock ( ) ;
63- * guard += 1 ;
64- }
65- } )
66- } )
67- . collect ( ) ;
68-
69- for handle in handles {
70- handle. join ( ) . unwrap ( ) ;
71- }
72- start. elapsed ( )
54+ let mutex = Arc :: new ( parking_lot:: Mutex :: new ( 0u64 ) ) ;
55+ let start = Instant :: now ( ) ;
56+
57+ let handles: Vec < _ > = ( 0 ..threads)
58+ . map ( |_| {
59+ let mutex = Arc :: clone ( & mutex) ;
60+ thread:: spawn ( move || {
61+ for _ in 0 ..( ITERATIONS / threads as u64 ) {
62+ let mut guard = mutex. lock ( ) ;
63+ * guard += 1 ;
64+ }
65+ } )
66+ } )
67+ . collect ( ) ;
68+
69+ for handle in handles {
70+ handle. join ( ) . unwrap ( ) ;
71+ }
72+ start. elapsed ( )
7373}
7474
7575fn format_results ( name : & str , std_time : Duration , pl_time : Duration ) {
76- let std_ns = std_time. as_nanos ( ) as f64 / ITERATIONS as f64 ;
77- let pl_ns = pl_time. as_nanos ( ) as f64 / ITERATIONS as f64 ;
78- let speedup = std_time. as_nanos ( ) as f64 / pl_time. as_nanos ( ) as f64 ;
79-
80- println ! ( "\n {name}:" ) ;
81- println ! ( " std::sync::Mutex: {std_ns:.2} ns/op" ) ;
82- println ! ( " parking_lot::Mutex: {pl_ns:.2} ns/op" ) ;
83- println ! ( " Speedup: {speedup:.2}x" ) ;
76+ let std_ns = std_time. as_nanos ( ) as f64 / ITERATIONS as f64 ;
77+ let pl_ns = pl_time. as_nanos ( ) as f64 / ITERATIONS as f64 ;
78+ let speedup = std_time. as_nanos ( ) as f64 / pl_time. as_nanos ( ) as f64 ;
79+
80+ println ! ( "\n {name}:" ) ;
81+ println ! ( " std::sync::Mutex: {std_ns:.2} ns/op" ) ;
82+ println ! ( " parking_lot::Mutex: {pl_ns:.2} ns/op" ) ;
83+ println ! ( " Speedup: {speedup:.2}x" ) ;
8484}
8585
8686fn main ( ) {
87- println ! ( "Mutex Benchmark Comparison" ) ;
88- println ! ( "==========================" ) ;
89- println ! ( "Iterations: {ITERATIONS}" ) ;
90-
91- // Size comparison (important: empty mutex size)
92- println ! ( "\n Size comparison:" ) ;
93- println ! ( " std::sync::Mutex<()>: {} bytes" , std:: mem:: size_of:: <std:: sync:: Mutex <( ) >>( ) ) ;
94- println ! ( " parking_lot::Mutex<()>: {} bytes" , std:: mem:: size_of:: <parking_lot:: Mutex <( ) >>( ) ) ;
95- println ! ( " std::sync::Mutex<u64>: {} bytes" , std:: mem:: size_of:: <std:: sync:: Mutex <u64 >>( ) ) ;
96- println ! ( " parking_lot::Mutex<u64>: {} bytes" , std:: mem:: size_of:: <parking_lot:: Mutex <u64 >>( ) ) ;
97-
98- // Warmup
99- let _ = bench_std_mutex_uncontended ( ) ;
100- let _ = bench_parking_lot_uncontended ( ) ;
101-
102- // Uncontended benchmarks (run 3 times, take best)
103- println ! ( "\n Running uncontended benchmarks (best of 3)..." ) ;
104- let std_uncontended = ( 0 ..3 ) . map ( |_| bench_std_mutex_uncontended ( ) ) . min ( ) . unwrap ( ) ;
105- let pl_uncontended = ( 0 ..3 ) . map ( |_| bench_parking_lot_uncontended ( ) ) . min ( ) . unwrap ( ) ;
106- format_results ( "Uncontended (single thread)" , std_uncontended, pl_uncontended) ;
107-
108- // Contended benchmarks with different thread counts
109- println ! ( "\n Running contended benchmarks..." ) ;
110- for & threads in THREAD_COUNTS {
111- let std_contended = bench_std_mutex_contended ( threads) ;
112- let pl_contended = bench_parking_lot_contended ( threads) ;
113- format_results ( & format ! ( "Contended ({threads} threads)" ) , std_contended, pl_contended) ;
114- }
115-
116- println ! ( "\n === Summary ===" ) ;
117- println ! ( "parking_lot::Mutex advantages:" ) ;
118- println ! ( " - No poisoning (panic safety - if one thread panics, others continue)" ) ;
119- println ! ( " - Cleaner API (no .unwrap() needed after .lock())" ) ;
120- println ! ( " - 8x smaller for Mutex<()>: 1 byte vs 8 bytes" ) ;
121- println ! ( " - Better performance under low-to-moderate contention (2-4 threads)" ) ;
122- println ! ( ) ;
123- println ! ( "Note: std::sync::Mutex may perform better under very high contention" ) ;
124- println ! ( " (8+ threads), but rusty_v8 usage patterns are low contention." ) ;
87+ println ! ( "Mutex Benchmark Comparison" ) ;
88+ println ! ( "==========================" ) ;
89+ println ! ( "Iterations: {ITERATIONS}" ) ;
90+
91+ // Size comparison (important: empty mutex size)
92+ println ! ( "\n Size comparison:" ) ;
93+ println ! (
94+ " std::sync::Mutex<()>: {} bytes" ,
95+ std:: mem:: size_of:: <std:: sync:: Mutex <( ) >>( )
96+ ) ;
97+ println ! (
98+ " parking_lot::Mutex<()>: {} bytes" ,
99+ std:: mem:: size_of:: <parking_lot:: Mutex <( ) >>( )
100+ ) ;
101+ println ! (
102+ " std::sync::Mutex<u64>: {} bytes" ,
103+ std:: mem:: size_of:: <std:: sync:: Mutex <u64 >>( )
104+ ) ;
105+ println ! (
106+ " parking_lot::Mutex<u64>: {} bytes" ,
107+ std:: mem:: size_of:: <parking_lot:: Mutex <u64 >>( )
108+ ) ;
109+
110+ // Warmup
111+ let _ = bench_std_mutex_uncontended ( ) ;
112+ let _ = bench_parking_lot_uncontended ( ) ;
113+
114+ // Uncontended benchmarks (run 3 times, take best)
115+ println ! ( "\n Running uncontended benchmarks (best of 3)..." ) ;
116+ let std_uncontended =
117+ ( 0 ..3 ) . map ( |_| bench_std_mutex_uncontended ( ) ) . min ( ) . unwrap ( ) ;
118+ let pl_uncontended = ( 0 ..3 )
119+ . map ( |_| bench_parking_lot_uncontended ( ) )
120+ . min ( )
121+ . unwrap ( ) ;
122+ format_results (
123+ "Uncontended (single thread)" ,
124+ std_uncontended,
125+ pl_uncontended,
126+ ) ;
127+
128+ // Contended benchmarks with different thread counts
129+ println ! ( "\n Running contended benchmarks..." ) ;
130+ for & threads in THREAD_COUNTS {
131+ let std_contended = bench_std_mutex_contended ( threads) ;
132+ let pl_contended = bench_parking_lot_contended ( threads) ;
133+ format_results (
134+ & format ! ( "Contended ({threads} threads)" ) ,
135+ std_contended,
136+ pl_contended,
137+ ) ;
138+ }
139+
140+ println ! ( "\n === Summary ===" ) ;
141+ println ! ( "parking_lot::Mutex advantages:" ) ;
142+ println ! (
143+ " - No poisoning (panic safety - if one thread panics, others continue)"
144+ ) ;
145+ println ! ( " - Cleaner API (no .unwrap() needed after .lock())" ) ;
146+ println ! ( " - 8x smaller for Mutex<()>: 1 byte vs 8 bytes" ) ;
147+ println ! (
148+ " - Better performance under low-to-moderate contention (2-4 threads)"
149+ ) ;
150+ println ! ( ) ;
151+ println ! (
152+ "Note: std::sync::Mutex may perform better under very high contention"
153+ ) ;
154+ println ! (
155+ " (8+ threads), but rusty_v8 usage patterns are low contention."
156+ ) ;
125157}
0 commit comments