@@ -23,6 +23,8 @@ use std::io::BufReader;
23
23
use std:: path:: Path ;
24
24
25
25
use fxprof_processed_profile:: Profile ;
26
+ use shared:: ctrl_c:: CtrlC ;
27
+ use wholesym:: LibraryInfo ;
26
28
27
29
#[ cfg( any( target_os = "android" , target_os = "linux" ) ) ]
28
30
use linux:: profiler;
@@ -32,9 +34,10 @@ use mac::profiler;
32
34
use windows:: profiler;
33
35
34
36
use profile_json_preparse:: parse_libinfo_map_from_profile_file;
35
- use server:: start_server_main ;
36
- use shared:: prop_types:: ImportProps ;
37
+ use server:: { start_server , RunningServerInfo , ServerProps } ;
38
+ use shared:: prop_types:: { ImportProps , SymbolProps } ;
37
39
use shared:: save_profile:: save_profile_to_file;
40
+ use symbols:: create_symbol_manager_and_quota_manager;
38
41
39
42
fn main ( ) {
40
43
env_logger:: init ( ) ;
@@ -64,28 +67,10 @@ fn main() {
64
67
}
65
68
66
69
fn do_load_action ( load_args : cli:: LoadArgs ) {
67
- let profile_filename = & load_args. file ;
68
- let input_file = match File :: open ( profile_filename) {
69
- Ok ( file) => file,
70
- Err ( err) => {
71
- eprintln ! ( "Could not open file {:?}: {}" , profile_filename, err) ;
72
- std:: process:: exit ( 1 )
73
- }
74
- } ;
75
-
76
- let libinfo_map = match parse_libinfo_map_from_profile_file ( input_file, profile_filename) {
77
- Ok ( libinfo_map) => libinfo_map,
78
- Err ( err) => {
79
- eprintln ! ( "Could not parse the input file as JSON: {}" , err) ;
80
- eprintln ! ( "If this is a perf.data file, please use `samply import` instead." ) ;
81
- std:: process:: exit ( 1 )
82
- }
83
- } ;
84
- start_server_main (
85
- profile_filename,
70
+ run_server_serving_profile (
71
+ & load_args. file ,
86
72
load_args. server_props ( ) ,
87
73
load_args. symbol_props ( ) ,
88
- libinfo_map,
89
74
) ;
90
75
}
91
76
@@ -109,21 +94,18 @@ fn do_import_action(import_args: cli::ImportArgs) {
109
94
crate :: shared:: symbol_precog:: presymbolicate (
110
95
& profile,
111
96
& import_args. output . with_extension ( "syms.json" ) ,
97
+ import_args. symbol_props ( ) ,
112
98
) ;
113
99
}
114
100
101
+ // Drop the profile so that it doesn't take up memory while the server is running.
102
+ drop ( profile) ;
103
+
115
104
if let Some ( server_props) = import_args. server_props ( ) {
116
- let profile_filename = & import_args. output ;
117
- let libinfo_map = profile_json_preparse:: parse_libinfo_map_from_profile_file (
118
- File :: open ( profile_filename) . expect ( "Couldn't open file we just wrote" ) ,
119
- profile_filename,
120
- )
121
- . expect ( "Couldn't parse libinfo map from profile file" ) ;
122
- start_server_main (
123
- profile_filename,
105
+ run_server_serving_profile (
106
+ & import_args. output ,
124
107
server_props,
125
108
import_args. symbol_props ( ) ,
126
- libinfo_map,
127
109
) ;
128
110
}
129
111
}
@@ -155,22 +137,19 @@ fn do_record_action(record_args: cli::RecordArgs) {
155
137
crate :: shared:: symbol_precog:: presymbolicate (
156
138
& profile,
157
139
& record_args. output . with_extension ( "syms.json" ) ,
140
+ record_args. symbol_props ( ) ,
158
141
) ;
159
142
}
160
143
144
+ // Drop the profile so that it doesn't take up memory while the server is running.
145
+ drop ( profile) ;
146
+
161
147
// then fire up the server for the profiler front end, if not save-only
162
148
if let Some ( server_props) = record_args. server_props ( ) {
163
- let profile_filename = & record_args. output ;
164
- let libinfo_map = crate :: profile_json_preparse:: parse_libinfo_map_from_profile_file (
165
- File :: open ( profile_filename) . expect ( "Couldn't open file we just wrote" ) ,
166
- profile_filename,
167
- )
168
- . expect ( "Couldn't parse libinfo map from profile file" ) ;
169
- start_server_main (
170
- profile_filename,
149
+ run_server_serving_profile (
150
+ & record_args. output ,
171
151
server_props,
172
152
record_args. symbol_props ( ) ,
173
- libinfo_map,
174
153
) ;
175
154
}
176
155
@@ -227,3 +206,85 @@ fn convert_file_to_profile(
227
206
}
228
207
}
229
208
}
209
+
210
+ fn run_server_serving_profile (
211
+ profile_path : & Path ,
212
+ server_props : ServerProps ,
213
+ symbol_props : SymbolProps ,
214
+ ) {
215
+ let libinfo_map = {
216
+ let profile_file = match File :: open ( profile_path) {
217
+ Ok ( file) => file,
218
+ Err ( err) => {
219
+ eprintln ! ( "Could not open file {:?}: {}" , profile_path, err) ;
220
+ std:: process:: exit ( 1 )
221
+ }
222
+ } ;
223
+
224
+ parse_libinfo_map_from_profile_file ( profile_file, profile_path)
225
+ . expect ( "Couldn't parse libinfo map from profile file" )
226
+ } ;
227
+
228
+ let runtime = tokio:: runtime:: Builder :: new_multi_thread ( )
229
+ . enable_all ( )
230
+ . build ( )
231
+ . unwrap ( ) ;
232
+
233
+ runtime. block_on ( async {
234
+ let ( mut symbol_manager, quota_manager) =
235
+ create_symbol_manager_and_quota_manager ( symbol_props, server_props. verbose ) ;
236
+ for lib_info in libinfo_map. into_values ( ) {
237
+ symbol_manager. add_known_library ( lib_info) ;
238
+ }
239
+
240
+ let precog_path = profile_path. with_extension ( "syms.json" ) ;
241
+ if let Some ( precog_info) = shared:: symbol_precog:: PrecogSymbolInfo :: try_load ( & precog_path) {
242
+ for ( debug_id, syms) in precog_info. into_hash_map ( ) . into_iter ( ) {
243
+ let lib_info = LibraryInfo {
244
+ debug_id : Some ( debug_id) ,
245
+ ..LibraryInfo :: default ( )
246
+ } ;
247
+ symbol_manager. add_known_library_symbols ( lib_info, syms) ;
248
+ }
249
+ }
250
+
251
+ let ctrl_c_receiver = CtrlC :: observe_oneshot ( ) ;
252
+
253
+ let open_in_browser = server_props. open_in_browser ;
254
+
255
+ let RunningServerInfo {
256
+ server_join_handle,
257
+ server_origin,
258
+ profiler_url,
259
+ } = start_server (
260
+ Some ( profile_path) ,
261
+ server_props,
262
+ symbol_manager,
263
+ ctrl_c_receiver,
264
+ )
265
+ . await ;
266
+
267
+ eprintln ! ( "Local server listening at {server_origin}" ) ;
268
+ if !open_in_browser {
269
+ if let Some ( profiler_url) = & profiler_url {
270
+ println ! ( "{profiler_url}" ) ;
271
+ }
272
+ }
273
+ eprintln ! ( "Press Ctrl+C to stop." ) ;
274
+
275
+ if open_in_browser {
276
+ if let Some ( profiler_url) = & profiler_url {
277
+ let _ = opener:: open_browser ( profiler_url) ;
278
+ }
279
+ }
280
+
281
+ // Run this server until it stops.
282
+ if let Err ( e) = server_join_handle. await {
283
+ eprintln ! ( "server error: {e}" ) ;
284
+ }
285
+
286
+ if let Some ( quota_manager) = quota_manager {
287
+ quota_manager. finish ( ) . await ;
288
+ }
289
+ } ) ;
290
+ }
0 commit comments