Skip to content

Commit 7c64071

Browse files
committed
Auto merge of rust-lang#126245 - GuillaumeGomez:doctest-improvement-v2, r=t-rustdoc
Greatly speed up doctests by compiling compatible doctests in one file Fixes rust-lang#75341. Take 2 at rust-lang#123974. It should now be much simpler to review since it's based on rust-lang#125798. I split the changes as much as possible to make it as easy as possible to review (even though it's a huge lot of code changes...). The following tests are not included into the combined doctests: * `compile_fail` * If there are crate attributes (`deny`/`allow`/`warn` are ok) * have invalid AST * `test_harness` * no capture * `--show-output` (because the output is nicer without the extra code surrounding it) Everything else is merged into one file. If this one file fails to compile, we go back to the current strategy: compile each doctest separately. Because of the `edition` codeblock attribute, I couldn't make them all into one file directly so I grouped them by edition, but it should be pretty anecdotic. In case the users want a specific doctest to be opted-out from this doctest merge, I added the `standalone` codeblock attribute: ```rust /// ```rust,standalone /// // This doctest will be run in its own process! /// ``` ``` Now the interesting part, I ran it on a few crates and here are the results (with `cargo test --doc` to only include doctests): | crate | nb doctests | before this PR | with this PR | | - | - | - | - | | sysinfo | 227 | 4.6s | 1.11s | | geos | 157 | 3.95s | 0.45s | | core | 4604 | 54.08s | 13.5s (merged: 0.9s, standalone: 12.6s) | | std | 1147 | 12s | 3.56s (merged: 2.1s, standalone: 1.46s) | r? `@camelid` try-job: x86_64-msvc try-job: aarch64-apple
2 parents 91376f4 + fcaa14e commit 7c64071

33 files changed

+1636
-438
lines changed

library/core/src/panic/location.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl<'a> Location<'a> {
4444
///
4545
/// # Examples
4646
///
47-
/// ```
47+
/// ```standalone
4848
/// use std::panic::Location;
4949
///
5050
/// /// Returns the [`Location`] at which it is called.

library/test/src/types.rs

+34
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,37 @@ pub struct TestDescAndFn {
250250
pub desc: TestDesc,
251251
pub testfn: TestFn,
252252
}
253+
254+
impl TestDescAndFn {
255+
pub const fn new_doctest(
256+
test_name: &'static str,
257+
ignore: bool,
258+
source_file: &'static str,
259+
start_line: usize,
260+
no_run: bool,
261+
should_panic: bool,
262+
testfn: TestFn,
263+
) -> Self {
264+
Self {
265+
desc: TestDesc {
266+
name: StaticTestName(test_name),
267+
ignore,
268+
ignore_message: None,
269+
source_file,
270+
start_line,
271+
start_col: 0,
272+
end_line: 0,
273+
end_col: 0,
274+
compile_fail: false,
275+
no_run,
276+
should_panic: if should_panic {
277+
options::ShouldPanic::Yes
278+
} else {
279+
options::ShouldPanic::No
280+
},
281+
test_type: TestType::DocTest,
282+
},
283+
testfn,
284+
}
285+
}
286+
}

src/doc/rustdoc/src/write-documentation/documentation-tests.md

+51
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,57 @@ that the code sample should be compiled using the respective edition of Rust.
376376
# fn foo() {}
377377
```
378378

379+
Starting in the 2024 edition[^edition-note], compatible doctests are merged as one before being
380+
run. We combine doctests for performance reasons: the slowest part of doctests is to compile them.
381+
Merging all of them into one file and compiling this new file, then running the doctests is much
382+
faster. Whether doctests are merged or not, they are run in their own process.
383+
384+
An example of time spent when running doctests:
385+
386+
[sysinfo crate](https://crates.io/crates/sysinfo):
387+
388+
```text
389+
wall-time duration: 4.59s
390+
total compile time: 27.067s
391+
total runtime: 3.969s
392+
```
393+
394+
Rust core library:
395+
396+
```text
397+
wall-time duration: 102s
398+
total compile time: 775.204s
399+
total runtime: 15.487s
400+
```
401+
402+
[^edition-note]: This is based on the edition of the whole crate, not the edition of the individual
403+
test case that may be specified in its code attribute.
404+
405+
In some cases, doctests cannot be merged. For example, if you have:
406+
407+
```rust
408+
//! ```
409+
//! let location = std::panic::Location::caller();
410+
//! assert_eq!(location.line(), 4);
411+
//! ```
412+
```
413+
414+
The problem with this code is that, if you change any other doctests, it'll likely break when
415+
runing `rustdoc --test`, making it tricky to maintain.
416+
417+
This is where the `standalone` attribute comes in: it tells `rustdoc` that a doctest
418+
should not be merged with the others. So the previous code should use it:
419+
420+
```rust
421+
//! ```standalone
422+
//! let location = std::panic::Location::caller();
423+
//! assert_eq!(location.line(), 4);
424+
//! ```
425+
```
426+
427+
In this case, it means that the line information will not change if you add/remove other
428+
doctests.
429+
379430
### Custom CSS classes for code blocks
380431

381432
```rust

0 commit comments

Comments
 (0)