1
1
//! This module handles self-profile "rich" APIs (e.g., chrome profiler JSON)
2
2
//! generation from the raw artifacts on demand.
3
3
4
+ use crate :: api:: detail:: CompilationSection ;
4
5
use crate :: api:: self_profile:: ArtifactSize ;
5
6
use crate :: api:: { self_profile, ServerResult } ;
6
7
use crate :: load:: SiteCtxt ;
8
+ use analyzeme:: ProfilingData ;
7
9
use anyhow:: Context ;
8
10
use bytes:: Buf ;
9
11
use database:: ArtifactId ;
@@ -197,6 +199,7 @@ impl SelfProfileCache {
197
199
pub struct SelfProfileWithAnalysis {
198
200
pub profile : self_profile:: SelfProfile ,
199
201
pub profiling_data : analyzeme:: AnalysisResults ,
202
+ pub compilation_sections : Vec < CompilationSection > ,
200
203
}
201
204
202
205
pub ( crate ) async fn download_and_analyze_self_profile (
@@ -221,15 +224,74 @@ pub(crate) async fn download_and_analyze_self_profile(
221
224
. map_err ( |e| format ! ( "error extracting self profiling data: {}" , e) ) ?,
222
225
Err ( e) => return Err ( format ! ( "could not fetch raw profile data: {e:?}" ) ) ,
223
226
} ;
227
+
228
+ let compilation_sections = compute_compilation_sections ( & profiling_data) ;
224
229
let profiling_data = profiling_data. perform_analysis ( ) ;
225
230
let profile =
226
231
get_self_profile_data ( metric, & profiling_data) . map_err ( |e| format ! ( "{}: {}" , aid, e) ) ?;
227
232
Ok ( SelfProfileWithAnalysis {
228
233
profile,
229
234
profiling_data,
235
+ compilation_sections,
230
236
} )
231
237
}
232
238
239
+ /// Tries to categorize the duration of three high-level sections of compilation (frontend,
240
+ /// backend, linker) from the self-profile queries.
241
+ fn compute_compilation_sections ( profile : & ProfilingData ) -> Vec < CompilationSection > {
242
+ let mut first_event_start = None ;
243
+ let mut frontend_end = None ;
244
+ let mut backend_start = None ;
245
+ let mut backend_end = None ;
246
+ let mut linker_duration = None ;
247
+
248
+ for event in profile. iter_full ( ) {
249
+ if first_event_start. is_none ( ) {
250
+ first_event_start = event. payload . timestamp ( ) . map ( |t| t. start ( ) ) ;
251
+ }
252
+
253
+ if event. label == "analysis" {
254
+ // End of "analysis" => end of frontend
255
+ frontend_end = event. payload . timestamp ( ) . map ( |t| t. end ( ) ) ;
256
+ } else if event. label == "codegen_crate" {
257
+ // Start of "codegen_crate" => start of backend
258
+ backend_start = event. payload . timestamp ( ) . map ( |t| t. start ( ) ) ;
259
+ } else if event. label == "finish_ongoing_codegen" {
260
+ // End of "finish_ongoing_codegen" => end of backend
261
+ backend_end = event. payload . timestamp ( ) . map ( |t| t. end ( ) ) ;
262
+ } else if event. label == "link_crate" {
263
+ // The "link" query overlaps codegen, so we want to look at the "link_crate" query
264
+ // instead.
265
+ linker_duration = event. duration ( ) ;
266
+ }
267
+ }
268
+ let mut sections = vec ! [ ] ;
269
+ if let ( Some ( start) , Some ( end) ) = ( first_event_start, frontend_end) {
270
+ if let Ok ( duration) = end. duration_since ( start) {
271
+ sections. push ( CompilationSection {
272
+ name : "Frontend" . to_string ( ) ,
273
+ value : duration. as_nanos ( ) as u64 ,
274
+ } ) ;
275
+ }
276
+ }
277
+ if let ( Some ( start) , Some ( end) ) = ( backend_start, backend_end) {
278
+ if let Ok ( duration) = end. duration_since ( start) {
279
+ sections. push ( CompilationSection {
280
+ name : "Backend" . to_string ( ) ,
281
+ value : duration. as_nanos ( ) as u64 ,
282
+ } ) ;
283
+ }
284
+ }
285
+ if let Some ( duration) = linker_duration {
286
+ sections. push ( CompilationSection {
287
+ name : "Linker" . to_string ( ) ,
288
+ value : duration. as_nanos ( ) as u64 ,
289
+ } ) ;
290
+ }
291
+
292
+ sections
293
+ }
294
+
233
295
fn get_self_profile_data (
234
296
cpu_clock : Option < f64 > ,
235
297
profile : & analyzeme:: AnalysisResults ,
0 commit comments