Skip to content

Commit 61760fb

Browse files
Rollup merge of #144308 - GuillaumeGomez:merged-doctest-times, r=lolbinarycat
[rustdoc] Display total time and compilation time of merged doctests Fixes#144270. Does it look good to you `@kpreid?` <img width="908" height="263" alt="image" src="https://github.com/user-attachments/assets/cd5d082d-c4e0-42ed-91dd-bd263b413dcd" />
2 parents b38ece9 + 64e3078 commit 61760fb

30 files changed

Lines changed: 212 additions & 114 deletions

‎src/librustdoc/doctest.rs‎

Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ use std::path::{Path, PathBuf};
1111
use std::process::{self,Command,Stdio};
1212
use std::sync::atomic::{AtomicUsize,Ordering};
1313
use std::sync::{Arc,Mutex};
14-
use std::{panic, str};
14+
use std::time::{Duration,Instant};
15+
use std::{fmt, panic, str};
1516

1617
pub(crate)use make::{BuildDocTestBuilder,DocTestBuilder};
1718
pub(crate)use markdown::test as test_markdown;
@@ -36,6 +37,50 @@ use crate::config::{Options as RustdocOptions, OutputFormat};
3637
usecrate::html::markdown::{ErrorCodes,Ignore,LangString,MdRelLine};
3738
usecrate::lint::init_lints;
3839

40+
/// Type used to display times (compilation and total) information for merged doctests.
41+
structMergedDoctestTimes{
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+
implMergedDoctestTimes{
50+
fnnew() -> Self{
51+
Self{
52+
total_time:Instant::now(),
53+
compilation_time:Duration::default(),
54+
added_compilation_times:0,
55+
}
56+
}
57+
58+
fnadd_compilation_time(&mutself,duration:Duration){
59+
self.compilation_time += duration;
60+
self.added_compilation_times += 1;
61+
}
62+
63+
fndisplay_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+
ifself.added_compilation_times > 0{
68+
println!("{self}");
69+
}
70+
}
71+
}
72+
73+
impl fmt::DisplayforMergedDoctestTimes{
74+
fnfmt(&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+
3984
/// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
4085
#[derive(Clone)]
4186
pub(crate)structGlobalTestOptions{
@@ -295,6 +340,7 @@ pub(crate) fn run_tests(
295340

296341
letmut nb_errors = 0;
297342
letmut ran_edition_tests = 0;
343+
letmut times = MergedDoctestTimes::new();
298344
let target_str = rustdoc_options.target.to_string();
299345

300346
for(MergeableTestKey{ edition, global_crate_attrs_hash },mut doctests)in mergeable_tests {
@@ -314,13 +360,15 @@ pub(crate) fn run_tests(
314360
for(doctest, scraped_test)in&doctests {
315361
tests_runner.add_test(doctest, scraped_test,&target_str);
316362
}
317-
ifletOk(success) = tests_runner.run_merged_tests(
363+
let(duration, ret) = tests_runner.run_merged_tests(
318364
rustdoc_test_options,
319365
edition,
320366
&opts,
321367
&test_args,
322368
rustdoc_options,
323-
){
369+
);
370+
times.add_compilation_time(duration);
371+
ifletOk(success) = ret {
324372
ran_edition_tests += 1;
325373
if !success {
326374
nb_errors += 1;
@@ -354,11 +402,13 @@ pub(crate) fn run_tests(
354402
test::test_main_with_exit_callback(&test_args, standalone_tests,None, || {
355403
// We ensure temp dir destructor is called.
356404
std::mem::drop(temp_dir.take());
405+
times.display_times();
357406
});
358407
}
359408
if nb_errors != 0{
360409
// We ensure temp dir destructor is called.
361410
std::mem::drop(temp_dir);
411+
times.display_times();
362412
// libtest::ERROR_EXIT_CODE is not public but it's the same value.
363413
std::process::exit(101);
364414
}
@@ -496,16 +546,19 @@ impl RunnableDocTest {
496546
///
497547
/// This is the function that calculates the compiler command line, invokes the compiler, then
498548
/// 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.
499551
fnrun_test(
500552
doctest:RunnableDocTest,
501553
rustdoc_options:&RustdocOptions,
502554
supports_color:bool,
503555
report_unused_externs:implFn(UnusedExterns),
504-
) -> Result<(),TestFailure>{
556+
) -> (Duration,Result<(),TestFailure>){
505557
let langstr = &doctest.langstr;
506558
// Make sure we emit well-formed executable names for our target.
507559
let rust_out = add_exe_suffix("rust_out".to_owned(),&rustdoc_options.target);
508560
let output_file = doctest.test_opts.outdir.path().join(rust_out);
561+
let instant = Instant::now();
509562

510563
// Common arguments used for compiling the doctest runner.
511564
// On merged doctests, the compiler is invoked twice: once for the test code itself,
@@ -589,7 +642,7 @@ fn run_test(
589642
if std::fs::write(&input_file,&doctest.full_test_code).is_err(){
590643
// If we cannot write this file for any reason, we leave. All combined tests will be
591644
// tested as standalone tests.
592-
returnErr(TestFailure::CompileError);
645+
return(Duration::default(),Err(TestFailure::CompileError));
593646
}
594647
if !rustdoc_options.nocapture{
595648
// If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -660,7 +713,7 @@ fn run_test(
660713
if std::fs::write(&runner_input_file, merged_test_code).is_err(){
661714
// If we cannot write this file for any reason, we leave. All combined tests will be
662715
// tested as standalone tests.
663-
returnErr(TestFailure::CompileError);
716+
return(instant.elapsed(),Err(TestFailure::CompileError));
664717
}
665718
if !rustdoc_options.nocapture{
666719
// If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -713,7 +766,7 @@ fn run_test(
713766
let _bomb = Bomb(&out);
714767
match(output.status.success(), langstr.compile_fail){
715768
(true,true) => {
716-
returnErr(TestFailure::UnexpectedCompilePass);
769+
return(instant.elapsed(),Err(TestFailure::UnexpectedCompilePass));
717770
}
718771
(true,false) => {}
719772
(false,true) => {
@@ -729,17 +782,18 @@ fn run_test(
729782
.collect();
730783

731784
if !missing_codes.is_empty(){
732-
returnErr(TestFailure::MissingErrorCodes(missing_codes));
785+
return(instant.elapsed(),Err(TestFailure::MissingErrorCodes(missing_codes)));
733786
}
734787
}
735788
}
736789
(false,false) => {
737-
returnErr(TestFailure::CompileError);
790+
return(instant.elapsed(),Err(TestFailure::CompileError));
738791
}
739792
}
740793

794+
let duration = instant.elapsed();
741795
if doctest.no_run{
742-
returnOk(());
796+
return(duration,Ok(()));
743797
}
744798

745799
// Run the code!
@@ -771,17 +825,17 @@ fn run_test(
771825
cmd.output()
772826
};
773827
match result {
774-
Err(e) => returnErr(TestFailure::ExecutionError(e)),
828+
Err(e) => return(duration,Err(TestFailure::ExecutionError(e))),
775829
Ok(out) => {
776830
if langstr.should_panic && out.status.success(){
777-
returnErr(TestFailure::UnexpectedRunPass);
831+
return(duration,Err(TestFailure::UnexpectedRunPass));
778832
}elseif !langstr.should_panic && !out.status.success(){
779-
returnErr(TestFailure::ExecutionFailure(out));
833+
return(duration,Err(TestFailure::ExecutionFailure(out)));
780834
}
781835
}
782836
}
783837

784-
Ok(())
838+
(duration,Ok(()))
785839
}
786840

787841
/// Converts a path intended to use as a command to absolute if it is
@@ -1071,7 +1125,7 @@ fn doctest_run_fn(
10711125
no_run: scraped_test.no_run(&rustdoc_options),
10721126
merged_test_code:None,
10731127
};
1074-
let res =
1128+
let(_,res) =
10751129
run_test(runnable_test,&rustdoc_options, doctest.supports_color, report_unused_externs);
10761130

10771131
ifletErr(err) = res {

‎src/librustdoc/doctest/runner.rs‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::fmt::Write;
2+
use std::time::Duration;
23

34
use rustc_data_structures::fx::FxIndexSet;
45
use rustc_span::edition::Edition;
@@ -67,14 +68,18 @@ impl DocTestRunner {
6768
self.nb_tests += 1;
6869
}
6970

71+
/// Returns a tuple containing the `Duration` of the compilation and the `Result` of the test.
72+
///
73+
/// If compilation failed, it will return `Err`, otherwise it will return `Ok` containing if
74+
/// the test ran successfully.
7075
pub(crate)fnrun_merged_tests(
7176
&mutself,
7277
test_options:IndividualTestOptions,
7378
edition:Edition,
7479
opts:&GlobalTestOptions,
7580
test_args:&[String],
7681
rustdoc_options:&RustdocOptions,
77-
) -> Result<bool,()>{
82+
) -> (Duration,Result<bool,()>){
7883
letmut code = "\
7984
#![allow(unused_extern_crates)]
8085
#![allow(internal_features)]
@@ -204,9 +209,9 @@ std::process::Termination::report(test::test_main(test_args, tests, None))
204209
no_run:false,
205210
merged_test_code:Some(code),
206211
};
207-
let ret =
212+
let(duration,ret) =
208213
run_test(runnable_test, rustdoc_options,self.supports_color, |_:UnusedExterns| {});
209-
ifletErr(TestFailure::CompileError) = ret {Err(())}else{Ok(ret.is_ok())}
214+
(duration,ifletErr(TestFailure::CompileError) = ret {Err(())}else{Ok(ret.is_ok())})
210215
}
211216
}
212217

‎tests/rustdoc-ui/2024-doctests-checks.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//@ compile-flags: --test --test-args=--test-threads=1
44
//@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR"
55
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
6+
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
7+
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
68
//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
79

810
/// ```
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11

22
running 1 test
3-
test $DIR/2024-doctests-checks.rs - Foo (line 8) ... ok
3+
test $DIR/2024-doctests-checks.rs - Foo (line 10) ... ok
44

55
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
66

77

88
running 1 test
9-
test $DIR/2024-doctests-checks.rs - Foo (line 15) ... ok
9+
test $DIR/2024-doctests-checks.rs - Foo (line 17) ... ok
1010

1111
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
1212

13+
all doctests ran in $TIME; merged doctests compilation took $TIME

‎tests/rustdoc-ui/2024-doctests-crate-attribute.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//@ normalize-stdout: "tests/rustdoc-ui" -> "$$DIR"
55
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
66
//@ normalize-stdout: ".rs:\d+:\d+" -> ".rs:$$LINE:$$COL"
7+
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
8+
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
79

810
/// This doctest is used to ensure that if a crate attribute is present,
911
/// it will not be part of the merged doctests.
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11

22
running 1 test
3-
test $DIR/2024-doctests-crate-attribute.rs - Foo (line 20) ... ok
3+
test $DIR/2024-doctests-crate-attribute.rs - Foo (line 22) ... ok
44

55
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
66

77

88
running 1 test
9-
test $DIR/2024-doctests-crate-attribute.rs - Foo (line 11) ... ok
9+
test $DIR/2024-doctests-crate-attribute.rs - Foo (line 13) ... ok
1010

1111
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
1212

13+
all doctests ran in $TIME; merged doctests compilation took $TIME

‎tests/rustdoc-ui/doctest/dead-code-2024.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//@ compile-flags:--test
55
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
66
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
7+
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
8+
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
79
//@ failure-status: 101
810

911
#![doc(test(attr(allow(unused_variables), deny(warnings))))]
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11

22
running 1 test
3-
test $DIR/dead-code-2024.rs - f (line 13) - compile ... FAILED
3+
test $DIR/dead-code-2024.rs - f (line 15) - compile ... FAILED
44

55
failures:
66

7-
---- $DIR/dead-code-2024.rs - f (line 13) stdout ----
7+
---- $DIR/dead-code-2024.rs - f (line 15) stdout ----
88
error: trait `T` is never used
9-
--> $DIR/dead-code-2024.rs:14:7
9+
--> $DIR/dead-code-2024.rs:16:7
1010
|
1111
LL | trait T { fn f(); }
1212
| ^
1313
|
1414
note: the lint level is defined here
15-
--> $DIR/dead-code-2024.rs:12:9
15+
--> $DIR/dead-code-2024.rs:14:9
1616
|
1717
LL | #![deny(warnings)]
1818
| ^^^^^^^^
@@ -23,7 +23,8 @@ error: aborting due to 1 previous error
2323
Couldn't compile the test.
2424

2525
failures:
26-
$DIR/dead-code-2024.rs - f (line 13)
26+
$DIR/dead-code-2024.rs - f (line 15)
2727

2828
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
2929

30+
all doctests ran in $TIME; merged doctests compilation took $TIME

‎tests/rustdoc-ui/doctest/dead-code-items.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//@ compile-flags:--test --test-args=--test-threads=1
55
//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR"
66
//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
7+
//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME"
8+
//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME"
79
//@ failure-status: 101
810

911
#![doc(test(attr(deny(warnings))))]

0 commit comments

Comments
 (0)