@@ -136,24 +136,9 @@ struct CSwitch {
136
136
cpu : u8 ,
137
137
}
138
138
139
- #[ derive( Debug , Eq , PartialEq ) ]
140
- enum Event {
141
- Pmc ( Pmc ) ,
142
- CSwitch ( CSwitch ) ,
143
- }
144
-
145
- impl Event {
146
- fn timestamp ( & self ) -> u64 {
147
- match self {
148
- Event :: Pmc ( info) => info. timestamp ,
149
- Event :: CSwitch ( info) => info. timestamp ,
150
- }
151
- }
152
- }
153
-
154
139
#[ derive( Debug , Eq , PartialEq ) ]
155
140
struct EventData {
156
- events : Vec < Event > ,
141
+ events : Vec < ( Pmc , CSwitch ) > ,
157
142
watched_processes : HashSet < u64 > ,
158
143
}
159
144
@@ -188,6 +173,7 @@ fn parse_events(r: &mut dyn BufRead, headers: Vec<EventHeader>) -> anyhow::Resul
188
173
189
174
let mut events = Vec :: new ( ) ;
190
175
let mut rustc_process = None ;
176
+ let mut last_pmc = None ;
191
177
let mut currently_watched_processes = HashSet :: new ( ) ;
192
178
let mut all_watched_processes = HashSet :: new ( ) ;
193
179
@@ -206,7 +192,7 @@ fn parse_events(r: &mut dyn BufRead, headers: Vec<EventHeader>) -> anyhow::Resul
206
192
let line = String :: from_utf8_lossy ( & buffer[ ..] ) ;
207
193
let columns: Vec < _ > = line. trim ( ) . split ( ',' ) . collect ( ) ;
208
194
209
- events . push ( match columns[ 0 ] . trim ( ) {
195
+ match columns[ 0 ] . trim ( ) {
210
196
PROCESS_START => {
211
197
let process_name = columns[ pstart_process_name] . trim ( ) ;
212
198
@@ -236,8 +222,6 @@ fn parse_events(r: &mut dyn BufRead, headers: Vec<EventHeader>) -> anyhow::Resul
236
222
}
237
223
}
238
224
}
239
-
240
- continue ;
241
225
}
242
226
PROCESS_END => {
243
227
let process_name = columns[ pend_process_name] . trim ( ) ;
@@ -252,16 +236,14 @@ fn parse_events(r: &mut dyn BufRead, headers: Vec<EventHeader>) -> anyhow::Resul
252
236
break ;
253
237
}
254
238
}
255
-
256
- continue ;
257
239
}
258
240
PMC => {
259
- Event :: Pmc ( Pmc {
241
+ last_pmc = Some ( Pmc {
260
242
timestamp : columns[ pmc_timestamp] . trim ( ) . parse ( ) ?,
261
243
thread_id : columns[ pmc_thread_id] . trim ( ) . parse ( ) ?,
262
244
instructions_retired : columns[ pmc_instructions_retired] . trim ( ) . parse ( ) ?,
263
245
total_cycles : columns[ pmc_total_cycles] . trim ( ) . parse ( ) ?,
264
- } )
246
+ } ) ;
265
247
}
266
248
CSWITCH => {
267
249
let timestamp = columns[ cswitch_timestamp] . trim ( ) . parse ( ) ?;
@@ -274,23 +256,23 @@ fn parse_events(r: &mut dyn BufRead, headers: Vec<EventHeader>) -> anyhow::Resul
274
256
// In this case, the previous Pmc event at this same timestamp isn't relevant.
275
257
// There might not be a previous event if the CSwitch event occurs before the
276
258
// Pmc events start recording.
277
- if let Some ( previous_event ) = events . pop ( ) {
278
- assert ! ( matches! ( previous_event , Event :: Pmc ( _ ) ) ) ;
279
- assert_eq ! ( timestamp , previous_event . timestamp ( ) ) ;
259
+ if let Some ( pmc ) = & last_pmc {
260
+ assert_eq ! ( timestamp , pmc . timestamp ) ;
261
+ last_pmc = None ;
280
262
}
281
263
282
264
continue ;
283
265
}
284
266
285
- Event :: CSwitch ( CSwitch {
267
+ events . push ( ( std :: mem :: take ( & mut last_pmc ) . unwrap ( ) , CSwitch {
286
268
timestamp,
287
269
old_process_pid : old_pid,
288
270
new_process_pid : new_pid,
289
271
cpu : columns[ cswitch_cpu] . trim ( ) . parse ( ) ?,
290
- } )
272
+ } ) ) ;
291
273
}
292
- _ => continue
293
- } ) ;
274
+ _ => { }
275
+ }
294
276
}
295
277
296
278
Ok ( EventData {
@@ -360,24 +342,14 @@ impl From<&Pmc> for Counters {
360
342
361
343
fn process_events ( event_data : EventData ) -> anyhow:: Result < Counters > {
362
344
let EventData { events, watched_processes } = event_data;
363
- anyhow:: ensure!( events. len( ) % 2 == 0 , "events must have an even count" ) ;
364
-
365
- let pmc_and_cswitch_events =
366
- events. chunks ( 2 ) . map ( |s| {
367
- match s {
368
- [ Event :: Pmc ( pmc) , Event :: CSwitch ( cswitch) ] => Ok ( ( pmc, cswitch) ) ,
369
- other => anyhow:: bail!( "unexpected events: {:?}" , other) ,
370
- }
371
- } ) ;
372
345
373
346
// We need to keep track of when the rustc process is running on a given CPU or not.
374
347
// The basic algorithm here is to note the counters when rustc is moved onto the CPU and
375
348
// then when it is moved off, add the delta to the running total.
376
349
let mut total = Counters :: default ( ) ;
377
350
let mut cpus = HashMap :: new ( ) ;
378
351
379
- for result in pmc_and_cswitch_events {
380
- let ( pmc, cswitch) = result?;
352
+ for ( pmc, cswitch) in events {
381
353
anyhow:: ensure!( pmc. timestamp == cswitch. timestamp, "event timestamps did not match" ) ;
382
354
383
355
// Handle if the rustc process (or a sub process) is moving on the cpu or off the CPU.
@@ -387,14 +359,14 @@ fn process_events(event_data: EventData) -> anyhow::Result<Counters> {
387
359
if watched_processes. contains ( & cswitch. old_process_pid ) {
388
360
if let Some ( last_counters) = cpus. remove ( & cswitch. cpu ) {
389
361
// record the delta between the starting and ending counters in the overall total
390
- total = total + ( Counters :: from ( pmc) - last_counters) ;
362
+ total = total + ( Counters :: from ( & pmc) - last_counters) ;
391
363
} else {
392
364
anyhow:: bail!( "no existing record when rustc moved off CPU" )
393
365
}
394
366
}
395
367
396
368
if watched_processes. contains ( & cswitch. new_process_pid ) {
397
- anyhow:: ensure!( cpus. insert( cswitch. cpu, Counters :: from( pmc) ) . is_none( ) , "existing record when rustc moved onto CPU" ) ;
369
+ anyhow:: ensure!( cpus. insert( cswitch. cpu, Counters :: from( & pmc) ) . is_none( ) , "existing record when rustc moved onto CPU" ) ;
398
370
}
399
371
}
400
372
@@ -404,7 +376,6 @@ fn process_events(event_data: EventData) -> anyhow::Result<Counters> {
404
376
/// Given the path to the ETW results file, process it and calculate the
405
377
/// hardware performance counter totals for the rustc process.
406
378
pub fn parse_etw_file ( path : & str ) -> anyhow:: Result < Counters > {
407
- log:: trace!( "path = {}" , path) ;
408
379
let mut file = std:: io:: BufReader :: new ( std:: fs:: File :: open ( path) . unwrap ( ) ) ;
409
380
410
381
let headers = parse_header ( & mut file) . unwrap ( ) ;
@@ -419,7 +390,7 @@ pub fn parse_etw_file(path: &str) -> anyhow::Result<Counters> {
419
390
#[ cfg( test) ]
420
391
mod tests {
421
392
use std:: io:: BufReader ;
422
- use super :: { Counters , CSwitch , Event , EventData , EventHeader , Pmc } ;
393
+ use super :: { Counters , CSwitch , EventData , EventHeader , Pmc } ;
423
394
424
395
#[ test]
425
396
fn parse_header ( ) -> anyhow:: Result < ( ) > {
@@ -517,25 +488,26 @@ FirstReliableCSwitchEventTimeStamp, 6016
517
488
518
489
let expected = EventData {
519
490
events : vec ! [
520
- Event :: Pmc ( Pmc {
491
+ ( Pmc {
521
492
timestamp: 106082 ,
522
493
thread_id: 15340 ,
523
494
instructions_retired: 3184489 ,
524
495
total_cycles: 3416818 ,
525
- } ) ,
526
- Event :: CSwitch ( CSwitch {
496
+ } ,
497
+ CSwitch {
527
498
timestamp: 106082 ,
528
499
new_process_pid: 10612 , // rustc.exe
529
500
old_process_pid: 0 , // Idle
530
501
cpu: 0 ,
531
502
} ) ,
532
- Event :: Pmc ( Pmc {
503
+
504
+ ( Pmc {
533
505
timestamp: 107179 ,
534
506
thread_id: 15340 ,
535
507
instructions_retired: 4205942 ,
536
508
total_cycles: 3779655 ,
537
- } ) ,
538
- Event :: CSwitch ( CSwitch {
509
+ } ,
510
+ CSwitch {
539
511
timestamp: 107179 ,
540
512
new_process_pid: 0 , // Idle
541
513
old_process_pid: 10612 , // rustc.exe
@@ -554,49 +526,52 @@ FirstReliableCSwitchEventTimeStamp, 6016
554
526
fn process_events ( ) -> anyhow:: Result < ( ) > {
555
527
let events = EventData {
556
528
events : vec ! [
557
- Event :: Pmc ( Pmc {
529
+ ( Pmc {
558
530
timestamp: 106082 ,
559
531
thread_id: 15340 ,
560
532
instructions_retired: 3184489 ,
561
533
total_cycles: 3416818 ,
562
- } ) ,
563
- Event :: CSwitch ( CSwitch {
534
+ } ,
535
+ CSwitch {
564
536
timestamp: 106082 ,
565
537
old_process_pid: 0 , // Idle
566
538
new_process_pid: 10612 , // rustc.exe
567
539
cpu: 0 ,
568
540
} ) ,
569
- Event :: Pmc ( Pmc {
541
+
542
+ ( Pmc {
570
543
timestamp: 106085 ,
571
544
thread_id: 99999 ,
572
545
instructions_retired: 1000000 ,
573
546
total_cycles: 20000 ,
574
- } ) ,
575
- Event :: CSwitch ( CSwitch {
547
+ } ,
548
+ CSwitch {
576
549
timestamp: 106085 ,
577
550
old_process_pid: 1234 , // foobar.exe
578
551
new_process_pid: 10612 , // rustc.exe
579
552
cpu: 3 ,
580
553
} ) ,
581
- Event :: Pmc ( Pmc {
554
+
555
+ ( Pmc {
582
556
timestamp: 107179 ,
583
557
thread_id: 15340 ,
584
558
instructions_retired: 4205942 ,
585
559
total_cycles: 3779655 ,
586
- } ) ,
587
- Event :: CSwitch ( CSwitch {
560
+ } ,
561
+ CSwitch {
588
562
timestamp: 107179 ,
589
563
old_process_pid: 10612 , // rustc.exe
590
564
new_process_pid: 0 , // Idle
591
565
cpu: 0 ,
592
566
} ) ,
593
- Event :: Pmc ( Pmc {
567
+
568
+ ( Pmc {
594
569
timestamp: 1259540 ,
595
570
thread_id: 99999 ,
596
571
instructions_retired: 1540000 ,
597
572
total_cycles: 23400 ,
598
- } ) ,
599
- Event :: CSwitch ( CSwitch {
573
+ } ,
574
+ CSwitch {
600
575
timestamp: 1259540 ,
601
576
old_process_pid: 10612 , // rustc.exe
602
577
new_process_pid: 0 , // Idle
@@ -621,65 +596,65 @@ FirstReliableCSwitchEventTimeStamp, 6016
621
596
fn process_events_child_process ( ) -> anyhow:: Result < ( ) > {
622
597
let events = EventData {
623
598
events : vec ! [
624
- Event :: Pmc ( Pmc {
599
+ ( Pmc {
625
600
timestamp: 100 ,
626
601
thread_id: 15340 ,
627
602
instructions_retired: 1000 ,
628
603
total_cycles: 5000 ,
629
- } ) ,
630
- Event :: CSwitch ( CSwitch {
604
+ } ,
605
+ CSwitch {
631
606
timestamp: 100 ,
632
607
old_process_pid: 0 , // Idle
633
608
new_process_pid: 10612 , // rustc.exe
634
609
cpu: 0 ,
635
610
} ) ,
636
611
637
- Event :: Pmc ( Pmc {
612
+ ( Pmc {
638
613
timestamp: 200 ,
639
614
thread_id: 99999 ,
640
615
instructions_retired: 100_000 ,
641
616
total_cycles: 300_000 ,
642
- } ) ,
643
- Event :: CSwitch ( CSwitch {
617
+ } ,
618
+ CSwitch {
644
619
timestamp: 200 ,
645
620
old_process_pid: 0 , // Idle
646
621
new_process_pid: 12345 , // rustc.exe -> link.exe
647
622
cpu: 3 ,
648
623
} ) ,
649
624
650
- Event :: Pmc ( Pmc {
625
+ ( Pmc {
651
626
timestamp: 300 ,
652
627
thread_id: 99999 ,
653
628
instructions_retired: 200_000 ,
654
629
total_cycles: 600_000 ,
655
- } ) ,
656
- Event :: CSwitch ( CSwitch {
630
+ } ,
631
+ CSwitch {
657
632
timestamp: 300 ,
658
633
old_process_pid: 12345 , // rustc.exe -> link.exe
659
634
new_process_pid: 10612 , // rustc.exe
660
635
cpu: 3 ,
661
636
} ) ,
662
637
663
- Event :: Pmc ( Pmc {
638
+ ( Pmc {
664
639
timestamp: 400 ,
665
640
thread_id: 15340 ,
666
641
instructions_retired: 2500 ,
667
642
total_cycles: 20000 ,
668
- } ) ,
669
- Event :: CSwitch ( CSwitch {
643
+ } ,
644
+ CSwitch {
670
645
timestamp: 400 ,
671
646
old_process_pid: 10612 , // rustc.exe
672
647
new_process_pid: 0 , // Idle
673
648
cpu: 0
674
649
} ) ,
675
650
676
- Event :: Pmc ( Pmc {
651
+ ( Pmc {
677
652
timestamp: 500 ,
678
653
thread_id: 15341 ,
679
654
instructions_retired: 300_000 ,
680
655
total_cycles: 700_000 ,
681
- } ) ,
682
- Event :: CSwitch ( CSwitch {
656
+ } ,
657
+ CSwitch {
683
658
timestamp: 500 ,
684
659
old_process_pid: 10612 , // rustc.exe
685
660
new_process_pid: 0 , // Idle
0 commit comments