Skip to content

[Perf] Optimize documentation lints **a lot** (1/2) (18% -> 10%) #14693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

blyxyas
Copy link
Member

@blyxyas blyxyas commented Apr 25, 2025

Turns out that doc_markdown uses a non-cheap rustdoc function to convert from markdown ranges into source spans. And it was using it a lot (about once every 17 lines of documentation on tokio, which ends up being about 2000 times).

This ended up being about 18% of the total Clippy runtime as discovered by lintcheck --perf in docs-heavy crates. This PR optimizes one of the cases in which Clippy calls the function, and a future PR once pulldown-cmark/pulldown-cmark#1034 is merged will be opened. This PR lands the use of the function into the single-digit zone.

Note that not all crates were affected by this crate equally, those with more docs are affected far more than those light ones.

changelog:[clippy::doc_markdown] has been optimized by 50%

@blyxyas blyxyas added the performance-project For issues and PRs related to the Clippy Performance Project label Apr 25, 2025
@rustbot
Copy link
Collaborator

rustbot commented Apr 25, 2025

r? @Jarcho

rustbot has assigned @Jarcho.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties label Apr 25, 2025
@rustbot

This comment has been minimized.

Turns out that `doc_markdown` uses a non-cheap rustdoc function
to convert from markdown ranges into source spans. And it was using it
a lot (about once every 18 lines of documentation on `tokio`, which ends
up being about 1800 times).

This ended up being about 18% of the total Clippy runtime as discovered by
lintcheck --perf in docs-heavy crates. This PR optimizes one of the cases
in which Clippy calls the function, and a future PR once
pulldown-cmark/pulldown-cmark issue number 1034 is merged will be open.

Note that not all crates were affected by this crate equally, those with
more docs are affected far more than those light ones.
@blyxyas blyxyas force-pushed the optimize-doc-lints branch from fe7ec9b to 565cf5a Compare April 25, 2025 19:15
Comment on lines +137 to +147
let Some(fragment_span) = fragments.span(cx, range.clone()) else {
return ControlFlow::Break(());
};

let span = Span::new(
fragment_span.lo() + BytePos::from_usize(fragment_offset),
fragment_span.lo() + BytePos::from_usize(fragment_offset + word.len()),
fragment_span.ctxt(),
fragment_span.parent(),
);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you not be adjusting the range before creating the span? fragment_offset looks like it's an offset in the markdown text.

@@ -117,6 +134,17 @@ fn check_word(cx: &LateContext<'_>, word: &str, span: Span, code_level: isize, b
// try to get around the fact that `foo::bar` parses as a valid URL
&& !url.cannot_be_a_base()
{
let Some(fragment_span) = fragments.span(cx, range.clone()) else {
return ControlFlow::Break(());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems wrong. One spot failing to get a span doesn't mean all the others will.

Comment on lines +168 to +177
let Some(fragment_span) = fragments.span(cx, range.clone()) else {
return ControlFlow::Break(());
};

let span = Span::new(
fragment_span.lo() + BytePos::from_usize(fragment_offset),
fragment_span.lo() + BytePos::from_usize(fragment_offset + word.len()),
fragment_span.ctxt(),
fragment_span.parent(),
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as the previous two comments.

/// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
/// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
/// letter (`NASA` is ok).
/// letter (`NASA` is ok).[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accident?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
performance-project For issues and PRs related to the Clippy Performance Project S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants