@@ -11,24 +11,28 @@ use crate::bindings::{self as zend};
1111use crate :: profiling:: Profiler ;
1212use crate :: { RefCellExt , REQUEST_LOCALS } ;
1313use libc:: size_t;
14- use log:: { debug, error , trace} ;
14+ use log:: { debug, trace} ;
1515use rand_distr:: { Distribution , Poisson } ;
1616use std:: ffi:: c_void;
17+ use std:: num:: { NonZero , NonZeroU32 , NonZeroU64 } ;
1718use std:: sync:: atomic:: { AtomicU64 , Ordering } ;
1819
20+ use crate :: config:: SystemSettings ;
1921#[ cfg( not( php_zts) ) ]
2022use rand:: rngs:: StdRng ;
2123#[ cfg( php_zts) ]
2224use rand:: rngs:: ThreadRng ;
2325#[ cfg( not( php_zts) ) ]
2426use rand:: SeedableRng ;
2527
26- /// Default sampling interval in bytes (4MB)
27- pub const DEFAULT_ALLOCATION_SAMPLING_INTERVAL : u64 = 1024 * 4096 ;
28+ /// Default sampling interval in bytes (4 MiB).
29+ // SAFETY: value is > 0.
30+ pub const DEFAULT_ALLOCATION_SAMPLING_INTERVAL : NonZeroU32 =
31+ unsafe { NonZero :: new_unchecked ( 1024 * 4096 ) } ;
2832
29- /// Sampling distance feed into poison sampling algo
33+ /// Sampling distance feed into poison sampling algo. This must be > 0.
3034pub static ALLOCATION_PROFILING_INTERVAL : AtomicU64 =
31- AtomicU64 :: new ( DEFAULT_ALLOCATION_SAMPLING_INTERVAL ) ;
35+ AtomicU64 :: new ( DEFAULT_ALLOCATION_SAMPLING_INTERVAL . get ( ) as u64 ) ;
3236
3337/// This will store the count of allocations (including reallocations) during
3438/// a profiling period. This will overflow when doing more than u64::MAX
@@ -53,10 +57,9 @@ pub struct AllocationProfilingStats {
5357}
5458
5559impl AllocationProfilingStats {
56- fn new ( ) -> AllocationProfilingStats {
57- // Safety: this will only error if lambda <= 0
58- let poisson =
59- Poisson :: new ( ALLOCATION_PROFILING_INTERVAL . load ( Ordering :: Relaxed ) as f64 ) . unwrap ( ) ;
60+ fn new ( sampling_distance : NonZeroU64 ) -> AllocationProfilingStats {
61+ // SAFETY: this will only error if lambda <= 0, and it's NonZeroU64.
62+ let poisson = unsafe { Poisson :: new ( sampling_distance. get ( ) as f64 ) . unwrap_unchecked ( ) } ;
6063 let mut stats = AllocationProfilingStats {
6164 next_sample : 0 ,
6265 poisson,
@@ -105,30 +108,35 @@ pub fn alloc_prof_startup() {
105108 allocation_le83:: alloc_prof_startup ( ) ;
106109}
107110
108- pub fn alloc_prof_first_rinit ( ) {
109- let ( allocation_enabled, sampling_distance) = REQUEST_LOCALS
110- . try_with_borrow ( |locals| {
111- let settings = locals. system_settings ( ) ;
112- ( settings. profiling_allocation_enabled , settings. profiling_allocation_sampling_distance )
113- } )
114- . unwrap_or_else ( |err| {
115- error ! ( "Allocation profiling first rinit failed because it failed to borrow the request locals. Please report this to Datadog: {err}" ) ;
116- ( false , DEFAULT_ALLOCATION_SAMPLING_INTERVAL as u32 )
117- } ) ;
111+ pub fn first_rinit ( settings : & SystemSettings ) {
112+ if !settings. profiling_allocation_enabled {
113+ return ;
114+ }
118115
119- if !allocation_enabled {
116+ let sampling_distance = settings. profiling_allocation_sampling_distance ;
117+ ALLOCATION_PROFILING_INTERVAL . store ( sampling_distance. get ( ) as u64 , Ordering :: Relaxed ) ;
118+
119+ trace ! ( "Memory allocation profiling initialized with a sampling distance of {sampling_distance} bytes." ) ;
120+ }
121+
122+ /// # Safety
123+ ///
124+ /// Must be called exactly once per extension minit.
125+ pub unsafe fn minit ( settings : & SystemSettings ) {
126+ if !settings. profiling_allocation_enabled {
120127 return ;
121128 }
122129
123- ALLOCATION_PROFILING_INTERVAL . store ( sampling_distance as u64 , Ordering :: Relaxed ) ;
130+ let sampling_distance = settings. profiling_allocation_sampling_distance ;
131+ ALLOCATION_PROFILING_INTERVAL . store ( sampling_distance. get ( ) as u64 , Ordering :: Relaxed ) ;
132+
133+ // SAFETY: called in minit.
134+ unsafe { profiling_stats:: minit ( sampling_distance. into ( ) ) } ;
124135
125- trace ! (
126- "Memory allocation profiling initialized with a sampling distance of {} bytes." ,
127- ALLOCATION_PROFILING_INTERVAL . load( Ordering :: Relaxed )
128- ) ;
136+ trace ! ( "Memory allocation profiling initialized with a sampling distance of {sampling_distance} bytes." ) ;
129137}
130138
131- pub fn alloc_prof_rinit ( ) {
139+ pub fn rinit ( ) {
132140 let allocation_enabled = REQUEST_LOCALS
133141 . try_with_borrow ( |locals| locals. system_settings ( ) . profiling_allocation_enabled )
134142 . unwrap_or_else ( |err| {
0 commit comments