44use std:: {
55 ffi:: { c_char, CStr , CString } ,
66 path:: Path ,
7+ ptr:: { self , addr_of} ,
78 sync:: Arc ,
89} ;
910
@@ -32,12 +33,65 @@ impl AsProfBuilder {
3233 }
3334}
3435
36+ #[ derive( Copy , Clone , Debug ) ]
37+ pub struct UserJfrKey {
38+ key : i32 ,
39+ }
40+
3541pub struct AsProf { }
3642
3743impl AsProf {
3844 pub fn builder ( ) -> AsProfBuilder {
3945 AsProfBuilder :: default ( )
4046 }
47+
48+ /// Return the async-profiler's sample counter
49+ pub fn get_sample_counter ( ) -> Option < u64 > {
50+ unsafe {
51+ let prof = raw:: async_profiler ( ) . ok ( ) ?;
52+ let thread_local_data = prof. asprof_get_thread_local_data . as_ref ( ) ?( ) ;
53+ if thread_local_data. is_null ( ) {
54+ None
55+ } else {
56+ Some ( ptr:: read_volatile ( addr_of ! (
57+ ( * thread_local_data) . sample_counter
58+ ) ) )
59+ }
60+ }
61+ }
62+
63+ /// Create a user JFR key from a given key
64+ pub fn create_user_jfr_key ( key : & CStr ) -> Result < UserJfrKey , AsProfError > {
65+ unsafe {
66+ let prof = raw:: async_profiler ( ) ?;
67+ let asprof_register_jfr_event =
68+ prof. asprof_register_jfr_event . as_ref ( ) . ok_or_else ( || {
69+ AsProfError :: AsyncProfilerError (
70+ "async-profiler does not support user JFR events" . into ( ) ,
71+ )
72+ } ) ?;
73+ let res = asprof_register_jfr_event ( key. as_ptr ( ) ) ;
74+ if res < 0 {
75+ Err ( AsProfError :: AsyncProfilerError (
76+ "unable to register JFR event" . into ( ) ,
77+ ) )
78+ } else {
79+ Ok ( UserJfrKey { key : res } )
80+ }
81+ }
82+ }
83+
84+ pub fn emit_user_jfr ( key : UserJfrKey , jfr : & [ u8 ] ) -> Result < ( ) , AsProfError > {
85+ unsafe {
86+ let prof = raw:: async_profiler ( ) ?;
87+ let asprof_emit_jfr_event = prof. asprof_emit_jfr_event . as_ref ( ) . ok_or_else ( || {
88+ AsProfError :: AsyncProfilerError (
89+ "async-profiler does not support user JFR events" . into ( ) ,
90+ )
91+ } ) ?;
92+ Self :: asprof_error ( asprof_emit_jfr_event ( key. key , jfr. as_ptr ( ) , jfr. len ( ) ) )
93+ }
94+ }
4195}
4296
4397impl super :: profiler:: ProfilerEngine for AsProf {
@@ -69,6 +123,25 @@ impl super::profiler::ProfilerEngine for AsProf {
69123}
70124
71125impl AsProf {
126+ /// convert an asprof_error_t to a Result
127+ ///
128+ /// SAFETY: response must be a valid asprof_error_t
129+ unsafe fn asprof_error ( response : raw:: asprof_error_t ) -> Result < ( ) , AsProfError > {
130+ if !response. is_null ( ) {
131+ let response = ( raw:: async_profiler ( ) ?. asprof_error_str ) ( response) ;
132+ if response. is_null ( ) {
133+ return Ok ( ( ) ) ;
134+ }
135+ let response = unsafe { CStr :: from_ptr ( response) } ;
136+ let response_str = response. to_string_lossy ( ) ;
137+ tracing:: error!( "received error from async-profiler: {}" , response_str) ;
138+ Err ( AsProfError :: AsyncProfilerError ( response_str. to_string ( ) ) )
139+ // TODO: stop the background thread in case there is an error
140+ } else {
141+ Ok ( ( ) )
142+ }
143+ }
144+
72145 fn asprof_execute ( args : & str ) -> Result < ( ) , AsProfError > {
73146 unsafe extern "C" fn callback ( buf : * const c_char , size : usize ) {
74147 unsafe {
@@ -85,17 +158,11 @@ impl AsProf {
85158 }
86159
87160 let args_compatible = CString :: new ( args) . unwrap ( ) ;
88- let response = unsafe {
89- ( raw:: async_profiler ( ) ?. asprof_execute ) ( args_compatible. as_ptr ( ) , Some ( callback) )
90- } ;
91- if !response. is_null ( ) {
92- let response = unsafe { CStr :: from_ptr ( response) } ;
93- let response_str = response. to_string_lossy ( ) ;
94- tracing:: error!( "received error from async-profiler: {}" , response_str) ;
95- Err ( AsProfError :: AsyncProfilerError ( response_str. to_string ( ) ) )
96- // TODO: stop the background thread in case there is an error
97- } else {
98- Ok ( ( ) )
161+ unsafe {
162+ Self :: asprof_error ( ( raw:: async_profiler ( ) ?. asprof_execute ) (
163+ args_compatible. as_ptr ( ) ,
164+ Some ( callback) ,
165+ ) )
99166 }
100167 }
101168}
0 commit comments