@@ -37,7 +37,7 @@ use libdd_profiling::internal::Profile as InternalProfile;
3737use log:: { debug, info, trace, warn} ;
3838use std:: borrow:: Cow ;
3939use std:: collections:: HashMap ;
40- use std:: hash:: Hash ;
40+ use std:: hash:: { BuildHasher , Hash , Hasher } ;
4141use std:: num:: NonZeroI64 ;
4242use std:: sync:: atomic:: { AtomicBool , AtomicPtr , AtomicU32 , AtomicU64 , Ordering } ;
4343use std:: sync:: { Arc , Barrier , OnceLock } ;
@@ -60,6 +60,49 @@ pub const NO_TIMESTAMP: i64 = 0;
6060// magnitude for the capacity.
6161const UPLOAD_CHANNEL_CAPACITY : usize = 8 ;
6262
63+ /// A fast, non-cryptographic hasher optimized for pointer addresses.
64+ /// Since pointers are already well-distributed and typically aligned,
65+ /// we use a simple bit mixing approach instead of expensive hashing.
66+ #[ derive( Default ) ]
67+ struct PointerHasher ( u64 ) ;
68+
69+ impl Hasher for PointerHasher {
70+ #[ inline]
71+ fn write ( & mut self , _bytes : & [ u8 ] ) {
72+ unreachable ! ( "PointerHasher only supports write_usize" ) ;
73+ }
74+
75+ #[ inline]
76+ fn write_usize ( & mut self , ptr : usize ) {
77+ // Pointers are typically 8 or 16-byte aligned, so shift right to spread
78+ // the entropy across the lower bits. XOR with shifted value for mixing.
79+ let ptr = ptr as u64 ;
80+ self . 0 = ptr ^ ( ptr >> 4 ) ;
81+ }
82+
83+ #[ inline]
84+ fn finish ( & self ) -> u64 {
85+ self . 0
86+ }
87+ }
88+
89+ /// BuildHasher that creates PointerHasher instances.
90+ /// DashMap requires Clone for its internal sharding.
91+ #[ derive( Clone ) ]
92+ struct PointerHasherBuilder ;
93+
94+ impl BuildHasher for PointerHasherBuilder {
95+ type Hasher = PointerHasher ;
96+
97+ #[ inline]
98+ fn build_hasher ( & self ) -> Self :: Hasher {
99+ PointerHasher ( 0 )
100+ }
101+ }
102+
103+ /// Type alias for the heap tracker with our fast pointer hasher
104+ type HeapTracker = DashMap < usize , LiveHeapSample , PointerHasherBuilder > ;
105+
63106/// The global profiler. Profiler gets made during the first rinit after an
64107/// minit, and is destroyed on mshutdown.
65108static mut PROFILER : OnceLock < Profiler > = OnceLock :: new ( ) ;
@@ -284,7 +327,8 @@ pub struct Profiler {
284327 /// Tracks sampled allocations for live heap profiling.
285328 /// Maps allocation pointer -> sample data for batched emission at export time.
286329 /// Wrapped in Arc to share with TimeCollector for batched sample emission.
287- live_heap_tracker : Arc < DashMap < usize , LiveHeapSample > > ,
330+ /// Uses a fast pointer hasher since addresses are already well-distributed.
331+ live_heap_tracker : Arc < HeapTracker > ,
288332}
289333
290334struct TimeCollector {
@@ -294,7 +338,7 @@ struct TimeCollector {
294338 upload_sender : Sender < UploadMessage > ,
295339 upload_period : Duration ,
296340 /// Shared tracker for batched heap-live sample emission at export time.
297- live_heap_tracker : Arc < DashMap < usize , LiveHeapSample > > ,
341+ live_heap_tracker : Arc < HeapTracker > ,
298342}
299343
300344impl TimeCollector {
@@ -788,7 +832,7 @@ impl Profiler {
788832 let interrupt_manager = Arc :: new ( InterruptManager :: new ( ) ) ;
789833 let ( message_sender, message_receiver) = crossbeam_channel:: bounded ( 100 ) ;
790834 let ( upload_sender, upload_receiver) = crossbeam_channel:: bounded ( UPLOAD_CHANNEL_CAPACITY ) ;
791- let live_heap_tracker = Arc :: new ( DashMap :: new ( ) ) ;
835+ let live_heap_tracker = Arc :: new ( DashMap :: with_hasher ( PointerHasherBuilder ) ) ;
792836 let time_collector = TimeCollector {
793837 fork_barrier : fork_barrier. clone ( ) ,
794838 interrupt_manager : interrupt_manager. clone ( ) ,
0 commit comments