Skip to content

Commit

Permalink
Auto merge of rust-lang#126245 - GuillaumeGomez:doctest-improvement-v…
Browse files Browse the repository at this point in the history
…2, 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
  • Loading branch information
bors committed Aug 13, 2024
2 parents 80eb5a8 + 05fb8ff commit e5b3e68
Show file tree
Hide file tree
Showing 33 changed files with 1,635 additions and 438 deletions.
2 changes: 1 addition & 1 deletion library/core/src/panic/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl<'a> Location<'a> {
///
/// # Examples
///
/// ```
/// ```standalone
/// use std::panic::Location;
///
/// /// Returns the [`Location`] at which it is called.
Expand Down
34 changes: 34 additions & 0 deletions library/test/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,3 +250,37 @@ pub struct TestDescAndFn {
pub desc: TestDesc,
pub testfn: TestFn,
}

impl TestDescAndFn {
pub const fn new_doctest(
test_name: &'static str,
ignore: bool,
source_file: &'static str,
start_line: usize,
no_run: bool,
should_panic: bool,
testfn: TestFn,
) -> Self {
Self {
desc: TestDesc {
name: StaticTestName(test_name),
ignore,
ignore_message: None,
source_file,
start_line,
start_col: 0,
end_line: 0,
end_col: 0,
compile_fail: false,
no_run,
should_panic: if should_panic {
options::ShouldPanic::Yes
} else {
options::ShouldPanic::No
},
test_type: TestType::DocTest,
},
testfn,
}
}
}
51 changes: 51 additions & 0 deletions src/doc/rustdoc/src/write-documentation/documentation-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,57 @@ that the code sample should be compiled using the respective edition of Rust.
# fn foo() {}
```

Starting in the 2024 edition[^edition-note], compatible doctests are merged as one before being
run. We combine doctests for performance reasons: the slowest part of doctests is to compile them.
Merging all of them into one file and compiling this new file, then running the doctests is much
faster. Whether doctests are merged or not, they are run in their own process.

An example of time spent when running doctests:

[sysinfo crate](https://crates.io/crates/sysinfo):

```text
wall-time duration: 4.59s
total compile time: 27.067s
total runtime: 3.969s
```

Rust core library:

```text
wall-time duration: 102s
total compile time: 775.204s
total runtime: 15.487s
```

[^edition-note]: This is based on the edition of the whole crate, not the edition of the individual
test case that may be specified in its code attribute.

In some cases, doctests cannot be merged. For example, if you have:

```rust
//! ```
//! let location = std::panic::Location::caller();
//! assert_eq!(location.line(), 4);
//! ```
```

The problem with this code is that, if you change any other doctests, it'll likely break when
runing `rustdoc --test`, making it tricky to maintain.

This is where the `standalone` attribute comes in: it tells `rustdoc` that a doctest
should not be merged with the others. So the previous code should use it:

```rust
//! ```standalone
//! let location = std::panic::Location::caller();
//! assert_eq!(location.line(), 4);
//! ```
```

In this case, it means that the line information will not change if you add/remove other
doctests.

### Custom CSS classes for code blocks

```rust
Expand Down
Loading

0 comments on commit e5b3e68

Please sign in to comment.