1414use once_cell:: sync:: OnceCell ;
1515use std:: ffi:: { CStr , CString } ;
1616use std:: mem;
17- use std:: sync:: atomic:: { AtomicUsize , Ordering :: SeqCst } ;
17+ use std:: sync:: atomic:: { AtomicUsize , Ordering :: Relaxed } ;
1818
1919/// Equivalent of the `COZ_PROGRESS` and `COZ_PROGRESS_NAMED` macros
2020///
@@ -158,7 +158,8 @@ impl Counter {
158158 mem:: size_of_val( & counter. count) ,
159159 mem:: size_of:: <libc:: size_t>( )
160160 ) ;
161- counter. count . fetch_add ( 1 , SeqCst ) ;
161+ counter. count . fetch_add ( 1 , Relaxed ) ;
162+ coz_add_delays ( ) ;
162163 }
163164 }
164165
@@ -203,6 +204,11 @@ struct coz_counter_t {
203204/// `typedef coz_counter_t* (*coz_get_counter_t)(int, const char*);`
204205type GetCounterFn = unsafe extern "C" fn ( libc:: c_int , * const libc:: c_char ) -> * mut coz_counter_t ;
205206
207+ /// The type of `_coz_add_delays` as defined in `include/coz.h`
208+ ///
209+ /// `typedef void (*coz_add_delays_t)(void);`
210+ type AddDelaysFn = unsafe extern "C" fn ( ) ;
211+
206212#[ cfg( target_os = "linux" ) ]
207213fn coz_get_counter ( ty : libc:: c_int , name : & CStr ) -> Option < * mut coz_counter_t > {
208214 static GET_COUNTER : OnceCell < Option < GetCounterFn > > = OnceCell :: new ( ) ;
@@ -226,7 +232,34 @@ fn coz_get_counter(ty: libc::c_int, name: &CStr) -> Option<*mut coz_counter_t> {
226232 func. map ( |f| unsafe { f ( ty, name. as_ptr ( ) ) } )
227233}
228234
235+ /// Calls `_coz_add_delays()` from libcoz.
236+ ///
237+ /// This must be called after every counter increment to allow the profiler to
238+ /// inject virtual delays for causal profiling experiments. Without this call,
239+ /// the profiler cannot detect progress points and will report 0 experiments.
240+ #[ cfg( target_os = "linux" ) ]
241+ fn coz_add_delays ( ) {
242+ static ADD_DELAYS : OnceCell < Option < AddDelaysFn > > = OnceCell :: new ( ) ;
243+ let func = ADD_DELAYS . get_or_init ( || {
244+ let name = CStr :: from_bytes_with_nul ( b"_coz_add_delays\0 " ) . unwrap ( ) ;
245+ let func = unsafe { libc:: dlsym ( libc:: RTLD_DEFAULT , name. as_ptr ( ) ) } ;
246+ if func. is_null ( ) {
247+ None
248+ } else {
249+ Some ( unsafe { mem:: transmute ( func) } )
250+ }
251+ } ) ;
252+
253+ if let Some ( f) = func {
254+ // SAFETY: _coz_add_delays is a void->void function with no invariants.
255+ unsafe { f ( ) } ;
256+ }
257+ }
258+
229259#[ cfg( not( target_os = "linux" ) ) ]
230260fn coz_get_counter ( _ty : libc:: c_int , _name : & CStr ) -> Option < * mut coz_counter_t > {
231261 None
232262}
263+
264+ #[ cfg( not( target_os = "linux" ) ) ]
265+ fn coz_add_delays ( ) { }
0 commit comments