Skip to content

Commit

Permalink
Auto merge of rust-lang#109399 - petrochenkov:rendersort, r=Guillaume…
Browse files Browse the repository at this point in the history
…Gomez

rustdoc: Optimize impl sorting during rendering

This should fix the perf regression on [bitmaps-3.1.0](https://github.com/rust-lang/rustc-perf/tree/master/collector/compile-benchmarks/bitmaps-3.1.0) from rust-lang#107765.

The bitmaps crate has a lot of impls:
```rust
impl Bits for BitsImpl<1> { ... }
impl Bits for BitsImpl<2> { ... }
// ...
impl Bits for BitsImpl<1023> { ... }
impl Bits for BitsImpl<1024> { ... }
```
and the logic in `fn print_item` sorts them in natural order.

Before rust-lang#107765 the impls came in source order, which happened to be already sorted in the necessary way.
So the comparison function was called fewer times.

After rust-lang#107765 the impls came in "stable" order (based on def path hash).
So the comparison function was called more times to sort them.

The comparison function was terribly inefficient, so it caused a large perf regression.
This PR attempts to make it more efficient by using cached keys during sorting.
  • Loading branch information
bors committed Mar 24, 2023
2 parents 8be3c2b + 4d55aff commit d012d2f
Showing 1 changed file with 20 additions and 7 deletions.
27 changes: 20 additions & 7 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -880,8 +880,8 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
let (mut synthetic, mut concrete): (Vec<&&Impl>, Vec<&&Impl>) =
local.iter().partition(|i| i.inner_impl().kind.is_auto());

synthetic.sort_by(|a, b| compare_impl(a, b, cx));
concrete.sort_by(|a, b| compare_impl(a, b, cx));
synthetic.sort_by_cached_key(|i| ImplString::new(i, cx));
concrete.sort_by_cached_key(|i| ImplString::new(i, cx));

if !foreign.is_empty() {
write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "");
Expand Down Expand Up @@ -1597,12 +1597,25 @@ where
w.write_str("</code></pre>");
}

fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cx: &Context<'_>) -> Ordering {
let lhss = format!("{}", lhs.inner_impl().print(false, cx));
let rhss = format!("{}", rhs.inner_impl().print(false, cx));
#[derive(PartialEq, Eq)]
struct ImplString(String);

// lhs and rhs are formatted as HTML, which may be unnecessary
compare_names(&lhss, &rhss)
impl ImplString {
fn new(i: &Impl, cx: &Context<'_>) -> ImplString {
ImplString(format!("{}", i.inner_impl().print(false, cx)))
}
}

impl PartialOrd for ImplString {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(Ord::cmp(self, other))
}
}

impl Ord for ImplString {
fn cmp(&self, other: &Self) -> Ordering {
compare_names(&self.0, &other.0)
}
}

fn render_implementor(
Expand Down

0 comments on commit d012d2f

Please sign in to comment.