Skip to content

Commit c76ade8

Browse files
Display total time and compilation time of merged doctests
1 parent e05ab47 commit c76ade8

File tree

2 files changed

+68
-18
lines changed

2 files changed

+68
-18
lines changed

src/librustdoc/doctest.rs

Lines changed: 64 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,47 @@ use crate::config::{Options as RustdocOptions, OutputFormat};
3637
use crate::html::markdown::{ErrorCodes, Ignore, LangString, MdRelLine};
3738
use crate::lint::init_lints;
3839

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+
3981
/// Options that apply to all doctests in a crate or Markdown file (for `rustdoc foo.md`).
4082
#[derive(Clone)]
4183
pub(crate) struct GlobalTestOptions {
@@ -295,6 +337,7 @@ pub(crate) fn run_tests(
295337

296338
let mut nb_errors = 0;
297339
let mut ran_edition_tests = 0;
340+
let mut times = MergedDoctestTimes::new();
298341
let target_str = rustdoc_options.target.to_string();
299342

300343
for (MergeableTestKey { edition, global_crate_attrs_hash }, mut doctests) in mergeable_tests {
@@ -314,13 +357,15 @@ pub(crate) fn run_tests(
314357
for (doctest, scraped_test) in &doctests {
315358
tests_runner.add_test(doctest, scraped_test, &target_str);
316359
}
317-
if let Ok(success) = tests_runner.run_merged_tests(
360+
let (duration, ret) = tests_runner.run_merged_tests(
318361
rustdoc_test_options,
319362
edition,
320363
&opts,
321364
&test_args,
322365
rustdoc_options,
323-
) {
366+
);
367+
times.add_compilation_time(duration);
368+
if let Ok(success) = ret {
324369
ran_edition_tests += 1;
325370
if !success {
326371
nb_errors += 1;
@@ -354,11 +399,13 @@ pub(crate) fn run_tests(
354399
test::test_main_with_exit_callback(&test_args, standalone_tests, None, || {
355400
// We ensure temp dir destructor is called.
356401
std::mem::drop(temp_dir.take());
402+
times.display_times();
357403
});
358404
}
359405
if nb_errors != 0 {
360406
// We ensure temp dir destructor is called.
361407
std::mem::drop(temp_dir);
408+
times.display_times();
362409
// libtest::ERROR_EXIT_CODE is not public but it's the same value.
363410
std::process::exit(101);
364411
}
@@ -501,11 +548,12 @@ fn run_test(
501548
rustdoc_options: &RustdocOptions,
502549
supports_color: bool,
503550
report_unused_externs: impl Fn(UnusedExterns),
504-
) -> Result<(), TestFailure> {
551+
) -> (Duration, Result<(), TestFailure>) {
505552
let langstr = &doctest.langstr;
506553
// Make sure we emit well-formed executable names for our target.
507554
let rust_out = add_exe_suffix("rust_out".to_owned(), &rustdoc_options.target);
508555
let output_file = doctest.test_opts.outdir.path().join(rust_out);
556+
let instant = Instant::now();
509557

510558
// Common arguments used for compiling the doctest runner.
511559
// On merged doctests, the compiler is invoked twice: once for the test code itself,
@@ -589,7 +637,7 @@ fn run_test(
589637
if std::fs::write(&input_file, &doctest.full_test_code).is_err() {
590638
// If we cannot write this file for any reason, we leave. All combined tests will be
591639
// tested as standalone tests.
592-
return Err(TestFailure::CompileError);
640+
return (Duration::default(), Err(TestFailure::CompileError));
593641
}
594642
if !rustdoc_options.nocapture {
595643
// If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -660,7 +708,7 @@ fn run_test(
660708
if std::fs::write(&runner_input_file, merged_test_code).is_err() {
661709
// If we cannot write this file for any reason, we leave. All combined tests will be
662710
// tested as standalone tests.
663-
return Err(TestFailure::CompileError);
711+
return (instant.elapsed(), Err(TestFailure::CompileError));
664712
}
665713
if !rustdoc_options.nocapture {
666714
// If `nocapture` is disabled, then we don't display rustc's output when compiling
@@ -713,7 +761,7 @@ fn run_test(
713761
let _bomb = Bomb(&out);
714762
match (output.status.success(), langstr.compile_fail) {
715763
(true, true) => {
716-
return Err(TestFailure::UnexpectedCompilePass);
764+
return (instant.elapsed(), Err(TestFailure::UnexpectedCompilePass));
717765
}
718766
(true, false) => {}
719767
(false, true) => {
@@ -729,17 +777,18 @@ fn run_test(
729777
.collect();
730778

731779
if !missing_codes.is_empty() {
732-
return Err(TestFailure::MissingErrorCodes(missing_codes));
780+
return (instant.elapsed(), Err(TestFailure::MissingErrorCodes(missing_codes)));
733781
}
734782
}
735783
}
736784
(false, false) => {
737-
return Err(TestFailure::CompileError);
785+
return (instant.elapsed(), Err(TestFailure::CompileError));
738786
}
739787
}
740788

789+
let duration = instant.elapsed();
741790
if doctest.no_run {
742-
return Ok(());
791+
return (duration, Ok(()));
743792
}
744793

745794
// Run the code!
@@ -771,17 +820,17 @@ fn run_test(
771820
cmd.output()
772821
};
773822
match result {
774-
Err(e) => return Err(TestFailure::ExecutionError(e)),
823+
Err(e) => return (duration, Err(TestFailure::ExecutionError(e))),
775824
Ok(out) => {
776825
if langstr.should_panic && out.status.success() {
777-
return Err(TestFailure::UnexpectedRunPass);
826+
return (duration, Err(TestFailure::UnexpectedRunPass));
778827
} else if !langstr.should_panic && !out.status.success() {
779-
return Err(TestFailure::ExecutionFailure(out));
828+
return (duration, Err(TestFailure::ExecutionFailure(out)));
780829
}
781830
}
782831
}
783832

784-
Ok(())
833+
(duration, Ok(()))
785834
}
786835

787836
/// Converts a path intended to use as a command to absolute if it is
@@ -1071,7 +1120,7 @@ fn doctest_run_fn(
10711120
no_run: scraped_test.no_run(&rustdoc_options),
10721121
merged_test_code: None,
10731122
};
1074-
let res =
1123+
let (_, res) =
10751124
run_test(runnable_test, &rustdoc_options, doctest.supports_color, report_unused_externs);
10761125

10771126
if let Err(err) = res {

src/librustdoc/doctest/runner.rs

Lines changed: 4 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;
@@ -74,7 +75,7 @@ impl DocTestRunner {
7475
opts: &GlobalTestOptions,
7576
test_args: &[String],
7677
rustdoc_options: &RustdocOptions,
77-
) -> Result<bool, ()> {
78+
) -> (Duration, Result<bool, ()>) {
7879
let mut code = "\
7980
#![allow(unused_extern_crates)]
8081
#![allow(internal_features)]
@@ -204,9 +205,9 @@ std::process::Termination::report(test::test_main(test_args, tests, None))
204205
no_run: false,
205206
merged_test_code: Some(code),
206207
};
207-
let ret =
208+
let (duration, ret) =
208209
run_test(runnable_test, rustdoc_options, self.supports_color, |_: UnusedExterns| {});
209-
if let Err(TestFailure::CompileError) = ret { Err(()) } else { Ok(ret.is_ok()) }
210+
(duration, if let Err(TestFailure::CompileError) = ret { Err(()) } else { Ok(ret.is_ok()) })
210211
}
211212
}
212213

0 commit comments

Comments
 (0)