@@ -11,7 +11,8 @@ use std::path::{Path, PathBuf};
11
11
use std:: process:: { self , Command , Stdio } ;
12
12
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
13
13
use std:: sync:: { Arc , Mutex } ;
14
- use std:: { panic, str} ;
14
+ use std:: time:: { Duration , Instant } ;
15
+ use std:: { fmt, panic, str} ;
15
16
16
17
pub ( crate ) use make:: { BuildDocTestBuilder , DocTestBuilder } ;
17
18
pub ( crate ) use markdown:: test as test_markdown;
@@ -36,6 +37,47 @@ use crate::config::{Options as RustdocOptions, OutputFormat};
36
37
use crate :: html:: markdown:: { ErrorCodes , Ignore , LangString , MdRelLine } ;
37
38
use crate :: lint:: init_lints;
38
39
40
+ /// Type used to display times (compilation and total) information for merged doctests.
41
+ struct MergedDoctestTimes {
42
+ total_time : Instant ,
43
+ compilation_time : Duration ,
44
+ /// This field is used to keep track of how many merged doctests we (tried to) compile.
45
+ added_compilation_times : usize ,
46
+ }
47
+
48
+ impl MergedDoctestTimes {
49
+ fn new ( ) -> Self {
50
+ Self {
51
+ total_time : Instant :: now ( ) ,
52
+ compilation_time : Duration :: default ( ) ,
53
+ added_compilation_times : 0 ,
54
+ }
55
+ }
56
+
57
+ fn add_compilation_time ( & mut self , duration : Duration ) {
58
+ self . compilation_time += duration;
59
+ self . added_compilation_times += 1 ;
60
+ }
61
+
62
+ fn display_times ( & self ) {
63
+ // If no merged doctest was compiled, then there is nothing to display.
64
+ if self . added_compilation_times > 0 {
65
+ println ! ( "{self}" ) ;
66
+ }
67
+ }
68
+ }
69
+
70
+ impl fmt:: Display for MergedDoctestTimes {
71
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
72
+ write ! (
73
+ f,
74
+ "all doctests ran in {:.2}s; merged doctests compilation took {:.2}s" ,
75
+ self . total_time. elapsed( ) . as_secs_f64( ) ,
76
+ self . compilation_time. as_secs_f64( ) ,
77
+ )
78
+ }
79
+ }
80
+
39
81
/// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
40
82
#[ derive( Clone ) ]
41
83
pub ( crate ) struct GlobalTestOptions {
@@ -295,6 +337,7 @@ pub(crate) fn run_tests(
295
337
296
338
let mut nb_errors = 0 ;
297
339
let mut ran_edition_tests = 0 ;
340
+ let mut times = MergedDoctestTimes :: new ( ) ;
298
341
let target_str = rustdoc_options. target . to_string ( ) ;
299
342
300
343
for ( MergeableTestKey { edition, global_crate_attrs_hash } , mut doctests) in mergeable_tests {
@@ -314,13 +357,15 @@ pub(crate) fn run_tests(
314
357
for ( doctest, scraped_test) in & doctests {
315
358
tests_runner. add_test ( doctest, scraped_test, & target_str) ;
316
359
}
317
- if let Ok ( success ) = tests_runner. run_merged_tests (
360
+ let ( duration , ret ) = tests_runner. run_merged_tests (
318
361
rustdoc_test_options,
319
362
edition,
320
363
& opts,
321
364
& test_args,
322
365
rustdoc_options,
323
- ) {
366
+ ) ;
367
+ times. add_compilation_time ( duration) ;
368
+ if let Ok ( success) = ret {
324
369
ran_edition_tests += 1 ;
325
370
if !success {
326
371
nb_errors += 1 ;
@@ -354,11 +399,13 @@ pub(crate) fn run_tests(
354
399
test:: test_main_with_exit_callback ( & test_args, standalone_tests, None , || {
355
400
// We ensure temp dir destructor is called.
356
401
std:: mem:: drop ( temp_dir. take ( ) ) ;
402
+ times. display_times ( ) ;
357
403
} ) ;
358
404
}
359
405
if nb_errors != 0 {
360
406
// We ensure temp dir destructor is called.
361
407
std:: mem:: drop ( temp_dir) ;
408
+ times. display_times ( ) ;
362
409
// libtest::ERROR_EXIT_CODE is not public but it's the same value.
363
410
std:: process:: exit ( 101 ) ;
364
411
}
@@ -501,11 +548,12 @@ fn run_test(
501
548
rustdoc_options : & RustdocOptions ,
502
549
supports_color : bool ,
503
550
report_unused_externs : impl Fn ( UnusedExterns ) ,
504
- ) -> Result < ( ) , TestFailure > {
551
+ ) -> ( Duration , Result < ( ) , TestFailure > ) {
505
552
let langstr = & doctest. langstr ;
506
553
// Make sure we emit well-formed executable names for our target.
507
554
let rust_out = add_exe_suffix ( "rust_out" . to_owned ( ) , & rustdoc_options. target ) ;
508
555
let output_file = doctest. test_opts . outdir . path ( ) . join ( rust_out) ;
556
+ let instant = Instant :: now ( ) ;
509
557
510
558
// Common arguments used for compiling the doctest runner.
511
559
// On merged doctests, the compiler is invoked twice: once for the test code itself,
@@ -589,7 +637,7 @@ fn run_test(
589
637
if std:: fs:: write ( & input_file, & doctest. full_test_code ) . is_err ( ) {
590
638
// If we cannot write this file for any reason, we leave. All combined tests will be
591
639
// tested as standalone tests.
592
- return Err ( TestFailure :: CompileError ) ;
640
+ return ( Duration :: default ( ) , Err ( TestFailure :: CompileError ) ) ;
593
641
}
594
642
if !rustdoc_options. nocapture {
595
643
// If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -660,7 +708,7 @@ fn run_test(
660
708
if std:: fs:: write ( & runner_input_file, merged_test_code) . is_err ( ) {
661
709
// If we cannot write this file for any reason, we leave. All combined tests will be
662
710
// tested as standalone tests.
663
- return Err ( TestFailure :: CompileError ) ;
711
+ return ( instant . elapsed ( ) , Err ( TestFailure :: CompileError ) ) ;
664
712
}
665
713
if !rustdoc_options. nocapture {
666
714
// If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -713,7 +761,7 @@ fn run_test(
713
761
let _bomb = Bomb ( & out) ;
714
762
match ( output. status . success ( ) , langstr. compile_fail ) {
715
763
( true , true ) => {
716
- return Err ( TestFailure :: UnexpectedCompilePass ) ;
764
+ return ( instant . elapsed ( ) , Err ( TestFailure :: UnexpectedCompilePass ) ) ;
717
765
}
718
766
( true , false ) => { }
719
767
( false , true ) => {
@@ -729,17 +777,18 @@ fn run_test(
729
777
. collect ( ) ;
730
778
731
779
if !missing_codes. is_empty ( ) {
732
- return Err ( TestFailure :: MissingErrorCodes ( missing_codes) ) ;
780
+ return ( instant . elapsed ( ) , Err ( TestFailure :: MissingErrorCodes ( missing_codes) ) ) ;
733
781
}
734
782
}
735
783
}
736
784
( false , false ) => {
737
- return Err ( TestFailure :: CompileError ) ;
785
+ return ( instant . elapsed ( ) , Err ( TestFailure :: CompileError ) ) ;
738
786
}
739
787
}
740
788
789
+ let duration = instant. elapsed ( ) ;
741
790
if doctest. no_run {
742
- return Ok ( ( ) ) ;
791
+ return ( duration , Ok ( ( ) ) ) ;
743
792
}
744
793
745
794
// Run the code!
@@ -771,17 +820,17 @@ fn run_test(
771
820
cmd. output ( )
772
821
} ;
773
822
match result {
774
- Err ( e) => return Err ( TestFailure :: ExecutionError ( e) ) ,
823
+ Err ( e) => return ( duration , Err ( TestFailure :: ExecutionError ( e) ) ) ,
775
824
Ok ( out) => {
776
825
if langstr. should_panic && out. status . success ( ) {
777
- return Err ( TestFailure :: UnexpectedRunPass ) ;
826
+ return ( duration , Err ( TestFailure :: UnexpectedRunPass ) ) ;
778
827
} else if !langstr. should_panic && !out. status . success ( ) {
779
- return Err ( TestFailure :: ExecutionFailure ( out) ) ;
828
+ return ( duration , Err ( TestFailure :: ExecutionFailure ( out) ) ) ;
780
829
}
781
830
}
782
831
}
783
832
784
- Ok ( ( ) )
833
+ ( duration , Ok ( ( ) ) )
785
834
}
786
835
787
836
/// Converts a path intended to use as a command to absolute if it is
@@ -1071,7 +1120,7 @@ fn doctest_run_fn(
1071
1120
no_run : scraped_test. no_run ( & rustdoc_options) ,
1072
1121
merged_test_code : None ,
1073
1122
} ;
1074
- let res =
1123
+ let ( _ , res) =
1075
1124
run_test ( runnable_test, & rustdoc_options, doctest. supports_color , report_unused_externs) ;
1076
1125
1077
1126
if let Err ( err) = res {
0 commit comments