33
44use criterion:: { black_box, criterion_group, BenchmarkId , Criterion } ;
55use datadog_crashtracker:: benchmark:: receiver_entry_point;
6+ use libc:: c_void;
7+ use std:: ffi:: CString ;
8+ use std:: fmt:: Write ;
9+ use std:: path:: Path ;
10+ use std:: path:: PathBuf ;
611use std:: time:: Duration ;
712use tokio:: io:: BufReader ;
813
9- fn create_dummy_crash_report ( ) -> String {
10- r#"DD_CRASHTRACK_BEGIN_STACKTRACE
11- { "ip": "0x42", "module_address": "0x21", "sp": "0x11", "symbol_address": "0x73" }
12- DD_CRASHTRACK_END_STACKTRACE
13- DD_CRASHTRACK_DONE"#
14- . to_string ( )
14+ struct SharedLibrary {
15+ handle : * mut c_void ,
16+ }
17+
18+ impl SharedLibrary {
19+ fn open ( lib_path : & str ) -> Result < Self , String > {
20+ let cstr = CString :: new ( lib_path) . map_err ( |e| e. to_string ( ) ) ?;
21+ // Use RTLD_NOW or another flag
22+ let handle = unsafe { libc:: dlopen ( cstr. as_ptr ( ) , libc:: RTLD_NOW ) } ;
23+ if handle. is_null ( ) {
24+ Err ( "Failed to open library" . to_string ( ) )
25+ } else {
26+ Ok ( Self { handle } )
27+ }
28+ }
29+
30+ fn get_symbol_address ( & self , symbol : & str ) -> Result < String , String > {
31+ let cstr = CString :: new ( symbol) . map_err ( |e| e. to_string ( ) ) ?;
32+ let sym = unsafe { libc:: dlsym ( self . handle , cstr. as_ptr ( ) ) } ;
33+ if sym. is_null ( ) {
34+ Err ( format ! ( "Failed to find symbol: {}" , symbol) )
35+ } else {
36+ Ok ( format ! ( "{:p}" , sym) )
37+ }
38+ }
39+ }
40+
41+ impl Drop for SharedLibrary {
42+ fn drop ( & mut self ) {
43+ if !self . handle . is_null ( ) {
44+ unsafe { libc:: dlclose ( self . handle ) } ;
45+ }
46+ }
47+ }
48+
49+ fn get_data_folder_path ( ) -> PathBuf {
50+ Path :: new ( & env ! ( "CARGO_MANIFEST_DIR" ) )
51+ . join ( "data" )
52+ . canonicalize ( )
53+ . expect ( "Failed to canonicalize base path for libtest" )
54+ }
55+
56+ macro_rules! add_frame {
57+ ( $report: expr, $fn: expr, $lib: expr) => {
58+ add_frame!( $report, $lib. get_symbol_address( $fn) . unwrap( ) . as_str( ) ) ;
59+ } ;
60+ ( $report: expr, $address: expr) => {
61+ writeln!(
62+ $report,
63+ "{{ \" ip\" : \" {}\" , \" module_address\" : \" 0x21\" , \" sp\" : \" 0x11\" }}" ,
64+ $address
65+ )
66+ . expect( "Failed to write frame" ) ;
67+ } ;
68+ }
69+
70+ fn add_proc_info ( report : & mut String ) {
71+ report. push_str ( "DD_CRASHTRACK_BEGIN_PROCESSINFO\n " ) ;
72+ writeln ! ( report, "{{ \" pid\" : {} }}" , std:: process:: id( ) ) . expect ( "Failed to write PID" ) ;
73+ report. push_str ( "DD_CRASHTRACK_END_PROCESSINFO\n " ) ;
74+ }
75+
76+ fn add_config ( report : & mut String ) {
77+ report. push_str ( "DD_CRASHTRACK_BEGIN_CONFIG\n " ) ;
78+ report. push_str ( "{\" additional_files\" :[],\" create_alt_stack\" :true,\" demangle_names\" :true,\" endpoint\" :null,\" resolve_frames\" :\" EnabledWithSymbolsInReceiver\" ,\" signals\" :[4,6,7,11],\" timeout\" :{\" secs\" :10,\" nanos\" :0},\" unix_socket_path\" :\" \" ,\" use_alt_stack\" :true}\n " ) ;
79+ report. push_str ( "DD_CRASHTRACK_END_CONFIG\n " ) ;
80+ }
81+
82+ fn add_stacktrace ( report : & mut String , test_cpp_so : & SharedLibrary , test_c_so : & SharedLibrary ) {
83+ report. push_str ( "DD_CRASHTRACK_BEGIN_STACKTRACE\n " ) ;
84+
85+ add_frame ! ( report, "my_function" , test_c_so) ;
86+ add_frame ! ( report, "func1" , test_c_so) ;
87+ add_frame ! ( report, "func2" , test_c_so) ;
88+ add_frame ! ( report, "0x01" ) ;
89+ add_frame ! ( report, "0x02" ) ;
90+ add_frame ! ( report, "_Z12cpp_functionv" , test_cpp_so) ;
91+ add_frame ! (
92+ report,
93+ "_ZN10FirstClass10InnerClass12InnerMethod1Ev" ,
94+ test_cpp_so
95+ ) ;
96+ add_frame ! (
97+ report,
98+ "_ZN10FirstClass10InnerClass12InnerMethod2Ev" ,
99+ test_cpp_so
100+ ) ;
101+ add_frame ! ( report, "0x03" ) ;
102+ add_frame ! ( report, "0x03" ) ;
103+ add_frame ! ( report, "0x05" ) ;
104+ add_frame ! ( report, "func3" , test_c_so) ;
105+ add_frame ! ( report, "_ZN10FirstClass7Method1Ev" , test_cpp_so) ;
106+ add_frame ! ( report, "func4" , test_c_so) ;
107+ add_frame ! (
108+ report,
109+ "_ZN10FirstClass7Method2EibNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE" ,
110+ test_cpp_so
111+ ) ;
112+ add_frame ! ( report, "0x06" ) ;
113+ add_frame ! ( report, "func5" , test_c_so) ;
114+ add_frame ! ( report, "func6" , test_c_so) ;
115+ add_frame ! (
116+ report,
117+ "_ZN11MyNamespace16ClassInNamespace18MethodInNamespace1Efx" ,
118+ test_cpp_so
119+ ) ;
120+ add_frame ! ( report, "0x07" ) ;
121+ add_frame ! (
122+ report,
123+ "_ZN11MyNamespace16ClassInNamespace18MethodInNamespace2Edc" ,
124+ test_cpp_so
125+ ) ;
126+ add_frame ! ( report, "0x08" ) ;
127+ add_frame ! ( report, "func6" , test_c_so) ;
128+ add_frame ! ( report, "0x09" ) ;
129+ add_frame ! (
130+ report,
131+ "_ZN11MyNamespace16ClassInNamespace21InnerClassInNamespace12InnerMethod1Ev" ,
132+ test_cpp_so
133+ ) ;
134+ add_frame ! ( report, "0x0A" ) ;
135+ add_frame ! (
136+ report,
137+ "_ZN11MyNamespace16ClassInNamespace21InnerClassInNamespace12InnerMethod2Eiix" ,
138+ test_cpp_so
139+ ) ;
140+ add_frame ! ( report, "0x0B" ) ;
141+ add_frame ! ( report, "func7" , test_c_so) ;
142+ add_frame ! ( report, "func8" , test_c_so) ;
143+ add_frame ! (
144+ report,
145+ "_ZN11MyNamespace16ClassInNamespace21InnerClassInNamespace12InnerMethod2Eiix" ,
146+ test_cpp_so
147+ ) ;
148+ add_frame ! ( report, "func9" , test_c_so) ;
149+ add_frame ! ( report, "func10" , test_c_so) ;
150+ add_frame ! ( report, "0x00" ) ;
151+
152+ report. push_str ( "DD_CRASHTRACK_END_STACKTRACE\n " ) ;
153+ }
154+
155+ fn create_crash_report ( test_cpp_so : & SharedLibrary , test_c_so : & SharedLibrary ) -> String {
156+ // Manual test revealed that the report size was arount 3000 bytes
157+ let mut report = String :: with_capacity ( 3000 ) ;
158+ add_proc_info ( & mut report) ;
159+ add_config ( & mut report) ;
160+ add_stacktrace ( & mut report, test_cpp_so, test_c_so) ;
161+ report. push_str ( "DD_CRASHTRACK_DONE\n " ) ;
162+ report
15163}
16164
17165async fn bench_receiver_entry_point_from_str ( data : & str ) {
@@ -22,10 +170,29 @@ async fn bench_receiver_entry_point_from_str(data: &str) {
22170 let _ = receiver_entry_point ( timeout, reader) . await ;
23171}
24172
173+ fn load_test_libraries ( ) -> ( SharedLibrary , SharedLibrary ) {
174+ let sofile_c_path = get_data_folder_path ( )
175+ . join ( "libtest.so" )
176+ . canonicalize ( )
177+ . unwrap ( ) ;
178+
179+ let sofile_cpp_path = get_data_folder_path ( )
180+ . join ( "libtest_cpp.so" )
181+ . canonicalize ( )
182+ . unwrap ( ) ;
183+
184+ let test_c_so = SharedLibrary :: open ( sofile_c_path. to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
185+ let test_cpp_so = SharedLibrary :: open ( sofile_cpp_path. to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
186+ ( test_cpp_so, test_c_so)
187+ }
188+
25189pub fn receiver_entry_point_benchmarks ( c : & mut Criterion ) {
26190 let mut group = c. benchmark_group ( "receiver_entry_point" ) ;
27191
28- let report = create_dummy_crash_report ( ) ;
192+ // the libraries must be opened as long as the benchmark is running
193+ // That why we pass them as references
194+ let ( sofile_cpp, sofile_c) = load_test_libraries ( ) ;
195+ let report = create_crash_report ( & sofile_cpp, & sofile_c) ;
29196 group. bench_with_input (
30197 BenchmarkId :: new ( "report" , report. len ( ) ) ,
31198 & report,
0 commit comments