@@ -609,54 +609,75 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
609
609
610
610
let total_codegen_time = Lock :: new ( Duration :: new ( 0 , 0 ) ) ;
611
611
612
- let cgu_reuse: Vec < _ > = tcx. sess . time ( "find cgu reuse" , || {
613
- codegen_units. iter ( ) . map ( |cgu| determine_cgu_reuse ( tcx, & cgu) ) . collect ( )
614
- } ) ;
615
-
616
- let mut cgus: FxHashMap < usize , _ > = if cfg ! ( parallel_compiler) {
617
- tcx. sess . time ( "compile first CGUs" , || {
618
- // Try to find one CGU to compile per thread.
619
- let cgus: Vec < _ > = cgu_reuse
620
- . iter ( )
621
- . enumerate ( )
622
- . filter ( |& ( _, reuse) | reuse == & CguReuse :: No )
623
- . take ( tcx. sess . threads ( ) )
624
- . collect ( ) ;
625
-
626
- // Compile the found CGUs in parallel.
627
- par_iter ( cgus)
628
- . map ( |( i, _) | {
629
- let start_time = Instant :: now ( ) ;
630
- let module = backend. compile_codegen_unit ( tcx, codegen_units[ i] . name ( ) ) ;
631
- let mut time = total_codegen_time. lock ( ) ;
632
- * time += start_time. elapsed ( ) ;
633
- ( i, module)
634
- } )
635
- . collect ( )
636
- } )
637
- } else {
638
- FxHashMap :: default ( )
612
+ // The non-parallel compiler can only translate codegen units to LLVM IR
613
+ // on a single thread, leading to a staircase effect where the N LLVM
614
+ // threads have to wait on the single codegen threads to generate work
615
+ // for them. The parallel compiler does not have this restriction, so
616
+ // we can pre-load the LLVM queue in parallel before handing off
617
+ // coordination to the OnGoingCodegen scheduler.
618
+ //
619
+ // This likely is a temporary measure. Once we don't have to support the
620
+ // non-parallel compiler anymore, we can compile CGUs end-to-end in
621
+ // parallel and get rid of the complicated scheduling logic.
622
+ let pre_compile_cgus = |cgu_reuse : & [ CguReuse ] | {
623
+ if cfg ! ( parallel_compiler) {
624
+ tcx. sess . time ( "compile_first_CGU_batch" , || {
625
+ // Try to find one CGU to compile per thread.
626
+ let cgus: Vec < _ > = cgu_reuse
627
+ . iter ( )
628
+ . enumerate ( )
629
+ . filter ( |& ( _, reuse) | reuse == & CguReuse :: No )
630
+ . take ( tcx. sess . threads ( ) )
631
+ . collect ( ) ;
632
+
633
+ // Compile the found CGUs in parallel.
634
+ par_iter ( cgus)
635
+ . map ( |( i, _) | {
636
+ let start_time = Instant :: now ( ) ;
637
+ let module = backend. compile_codegen_unit ( tcx, codegen_units[ i] . name ( ) ) ;
638
+ let mut time = total_codegen_time. lock ( ) ;
639
+ * time += start_time. elapsed ( ) ;
640
+ ( i, module)
641
+ } )
642
+ . collect ( )
643
+ } )
644
+ } else {
645
+ FxHashMap :: default ( )
646
+ }
639
647
} ;
640
648
641
- let mut total_codegen_time = total_codegen_time. into_inner ( ) ;
649
+ let mut cgu_reuse = Vec :: new ( ) ;
650
+ let mut pre_compiled_cgus: Option < FxHashMap < usize , _ > > = None ;
642
651
643
- for ( i, cgu) in codegen_units. into_iter ( ) . enumerate ( ) {
652
+ for ( i, cgu) in codegen_units. iter ( ) . enumerate ( ) {
644
653
ongoing_codegen. wait_for_signal_to_codegen_item ( ) ;
645
654
ongoing_codegen. check_for_errors ( tcx. sess ) ;
646
655
656
+ // Do some setup work in the first iteration
657
+ if pre_compiled_cgus. is_none ( ) {
658
+ // Calculate the CGU reuse
659
+ cgu_reuse = tcx. sess . time ( "find_cgu_reuse" , || {
660
+ codegen_units. iter ( ) . map ( |cgu| determine_cgu_reuse ( tcx, & cgu) ) . collect ( )
661
+ } ) ;
662
+ // Pre compile some CGUs
663
+ pre_compiled_cgus = Some ( pre_compile_cgus ( & cgu_reuse) ) ;
664
+ }
665
+
647
666
let cgu_reuse = cgu_reuse[ i] ;
648
667
tcx. sess . cgu_reuse_tracker . set_actual_reuse ( & cgu. name ( ) . as_str ( ) , cgu_reuse) ;
649
668
650
669
match cgu_reuse {
651
670
CguReuse :: No => {
652
- let ( module, cost) = if let Some ( cgu) = cgus. remove ( & i) {
653
- cgu
654
- } else {
655
- let start_time = Instant :: now ( ) ;
656
- let module = backend. compile_codegen_unit ( tcx, cgu. name ( ) ) ;
657
- total_codegen_time += start_time. elapsed ( ) ;
658
- module
659
- } ;
671
+ let ( module, cost) =
672
+ if let Some ( cgu) = pre_compiled_cgus. as_mut ( ) . unwrap ( ) . remove ( & i) {
673
+ cgu
674
+ } else {
675
+ let start_time = Instant :: now ( ) ;
676
+ let module = backend. compile_codegen_unit ( tcx, cgu. name ( ) ) ;
677
+ let mut time = total_codegen_time. lock ( ) ;
678
+ * time += start_time. elapsed ( ) ;
679
+ module
680
+ } ;
660
681
submit_codegened_module_to_llvm (
661
682
& backend,
662
683
& ongoing_codegen. coordinator_send ,
@@ -695,7 +716,11 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
695
716
696
717
// Since the main thread is sometimes blocked during codegen, we keep track
697
718
// -Ztime-passes output manually.
698
- print_time_passes_entry ( tcx. sess . time_passes ( ) , "codegen_to_LLVM_IR" , total_codegen_time) ;
719
+ print_time_passes_entry (
720
+ tcx. sess . time_passes ( ) ,
721
+ "codegen_to_LLVM_IR" ,
722
+ total_codegen_time. into_inner ( ) ,
723
+ ) ;
699
724
700
725
:: rustc_incremental:: assert_module_sources:: assert_module_sources ( tcx) ;
701
726
0 commit comments