@@ -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,50 @@ 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
+ /// Total time spent compiling all merged doctests.
44
+ compilation_time : Duration ,
45
+ /// This field is used to keep track of how many merged doctests we (tried to) compile.
46
+ added_compilation_times : usize ,
47
+ }
48
+
49
+ impl MergedDoctestTimes {
50
+ fn new ( ) -> Self {
51
+ Self {
52
+ total_time : Instant :: now ( ) ,
53
+ compilation_time : Duration :: default ( ) ,
54
+ added_compilation_times : 0 ,
55
+ }
56
+ }
57
+
58
+ fn add_compilation_time ( & mut self , duration : Duration ) {
59
+ self . compilation_time += duration;
60
+ self . added_compilation_times += 1 ;
61
+ }
62
+
63
+ fn display_times ( & self ) {
64
+ // If no merged doctest was compiled, then there is nothing to display since the numbers
65
+ // displayed by `libtest` for standalone tests are already accurate (they include both
66
+ // compilation and runtime).
67
+ if self . added_compilation_times > 0 {
68
+ println ! ( "{self}" ) ;
69
+ }
70
+ }
71
+ }
72
+
73
+ impl fmt:: Display for MergedDoctestTimes {
74
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
75
+ write ! (
76
+ f,
77
+ "all doctests ran in {:.2}s; merged doctests compilation took {:.2}s" ,
78
+ self . total_time. elapsed( ) . as_secs_f64( ) ,
79
+ self . compilation_time. as_secs_f64( ) ,
80
+ )
81
+ }
82
+ }
83
+
39
84
/// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
40
85
#[ derive( Clone ) ]
41
86
pub ( crate ) struct GlobalTestOptions {
@@ -295,6 +340,7 @@ pub(crate) fn run_tests(
295
340
296
341
let mut nb_errors = 0 ;
297
342
let mut ran_edition_tests = 0 ;
343
+ let mut times = MergedDoctestTimes :: new ( ) ;
298
344
let target_str = rustdoc_options. target . to_string ( ) ;
299
345
300
346
for ( MergeableTestKey { edition, global_crate_attrs_hash } , mut doctests) in mergeable_tests {
@@ -314,13 +360,15 @@ pub(crate) fn run_tests(
314
360
for ( doctest, scraped_test) in & doctests {
315
361
tests_runner. add_test ( doctest, scraped_test, & target_str) ;
316
362
}
317
- if let Ok ( success ) = tests_runner. run_merged_tests (
363
+ let ( duration , ret ) = tests_runner. run_merged_tests (
318
364
rustdoc_test_options,
319
365
edition,
320
366
& opts,
321
367
& test_args,
322
368
rustdoc_options,
323
- ) {
369
+ ) ;
370
+ times. add_compilation_time ( duration) ;
371
+ if let Ok ( success) = ret {
324
372
ran_edition_tests += 1 ;
325
373
if !success {
326
374
nb_errors += 1 ;
@@ -354,11 +402,13 @@ pub(crate) fn run_tests(
354
402
test:: test_main_with_exit_callback ( & test_args, standalone_tests, None , || {
355
403
// We ensure temp dir destructor is called.
356
404
std:: mem:: drop ( temp_dir. take ( ) ) ;
405
+ times. display_times ( ) ;
357
406
} ) ;
358
407
}
359
408
if nb_errors != 0 {
360
409
// We ensure temp dir destructor is called.
361
410
std:: mem:: drop ( temp_dir) ;
411
+ times. display_times ( ) ;
362
412
// libtest::ERROR_EXIT_CODE is not public but it's the same value.
363
413
std:: process:: exit ( 101 ) ;
364
414
}
@@ -496,16 +546,19 @@ impl RunnableDocTest {
496
546
///
497
547
/// This is the function that calculates the compiler command line, invokes the compiler, then
498
548
/// invokes the test or tests in a separate executable (if applicable).
549
+ ///
550
+ /// Returns a tuple containing the `Duration` of the compilation and the `Result` of the test.
499
551
fn run_test (
500
552
doctest : RunnableDocTest ,
501
553
rustdoc_options : & RustdocOptions ,
502
554
supports_color : bool ,
503
555
report_unused_externs : impl Fn ( UnusedExterns ) ,
504
- ) -> Result < ( ) , TestFailure > {
556
+ ) -> ( Duration , Result < ( ) , TestFailure > ) {
505
557
let langstr = & doctest. langstr ;
506
558
// Make sure we emit well-formed executable names for our target.
507
559
let rust_out = add_exe_suffix ( "rust_out" . to_owned ( ) , & rustdoc_options. target ) ;
508
560
let output_file = doctest. test_opts . outdir . path ( ) . join ( rust_out) ;
561
+ let instant = Instant :: now ( ) ;
509
562
510
563
// Common arguments used for compiling the doctest runner.
511
564
// On merged doctests, the compiler is invoked twice: once for the test code itself,
@@ -589,7 +642,7 @@ fn run_test(
589
642
if std:: fs:: write ( & input_file, & doctest. full_test_code ) . is_err ( ) {
590
643
// If we cannot write this file for any reason, we leave. All combined tests will be
591
644
// tested as standalone tests.
592
- return Err ( TestFailure :: CompileError ) ;
645
+ return ( Duration :: default ( ) , Err ( TestFailure :: CompileError ) ) ;
593
646
}
594
647
if !rustdoc_options. nocapture {
595
648
// If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -660,7 +713,7 @@ fn run_test(
660
713
if std:: fs:: write ( & runner_input_file, merged_test_code) . is_err ( ) {
661
714
// If we cannot write this file for any reason, we leave. All combined tests will be
662
715
// tested as standalone tests.
663
- return Err ( TestFailure :: CompileError ) ;
716
+ return ( instant . elapsed ( ) , Err ( TestFailure :: CompileError ) ) ;
664
717
}
665
718
if !rustdoc_options. nocapture {
666
719
// If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -713,7 +766,7 @@ fn run_test(
713
766
let _bomb = Bomb ( & out) ;
714
767
match ( output. status . success ( ) , langstr. compile_fail ) {
715
768
( true , true ) => {
716
- return Err ( TestFailure :: UnexpectedCompilePass ) ;
769
+ return ( instant . elapsed ( ) , Err ( TestFailure :: UnexpectedCompilePass ) ) ;
717
770
}
718
771
( true , false ) => { }
719
772
( false , true ) => {
@@ -729,17 +782,18 @@ fn run_test(
729
782
. collect ( ) ;
730
783
731
784
if !missing_codes. is_empty ( ) {
732
- return Err ( TestFailure :: MissingErrorCodes ( missing_codes) ) ;
785
+ return ( instant . elapsed ( ) , Err ( TestFailure :: MissingErrorCodes ( missing_codes) ) ) ;
733
786
}
734
787
}
735
788
}
736
789
( false , false ) => {
737
- return Err ( TestFailure :: CompileError ) ;
790
+ return ( instant . elapsed ( ) , Err ( TestFailure :: CompileError ) ) ;
738
791
}
739
792
}
740
793
794
+ let duration = instant. elapsed ( ) ;
741
795
if doctest. no_run {
742
- return Ok ( ( ) ) ;
796
+ return ( duration , Ok ( ( ) ) ) ;
743
797
}
744
798
745
799
// Run the code!
@@ -771,17 +825,17 @@ fn run_test(
771
825
cmd. output ( )
772
826
} ;
773
827
match result {
774
- Err ( e) => return Err ( TestFailure :: ExecutionError ( e) ) ,
828
+ Err ( e) => return ( duration , Err ( TestFailure :: ExecutionError ( e) ) ) ,
775
829
Ok ( out) => {
776
830
if langstr. should_panic && out. status . success ( ) {
777
- return Err ( TestFailure :: UnexpectedRunPass ) ;
831
+ return ( duration , Err ( TestFailure :: UnexpectedRunPass ) ) ;
778
832
} else if !langstr. should_panic && !out. status . success ( ) {
779
- return Err ( TestFailure :: ExecutionFailure ( out) ) ;
833
+ return ( duration , Err ( TestFailure :: ExecutionFailure ( out) ) ) ;
780
834
}
781
835
}
782
836
}
783
837
784
- Ok ( ( ) )
838
+ ( duration , Ok ( ( ) ) )
785
839
}
786
840
787
841
/// Converts a path intended to use as a command to absolute if it is
@@ -1071,7 +1125,7 @@ fn doctest_run_fn(
1071
1125
no_run : scraped_test. no_run ( & rustdoc_options) ,
1072
1126
merged_test_code : None ,
1073
1127
} ;
1074
- let res =
1128
+ let ( _ , res) =
1075
1129
run_test ( runnable_test, & rustdoc_options, doctest. supports_color , report_unused_externs) ;
1076
1130
1077
1131
if let Err ( err) = res {
0 commit comments