Skip to content
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

use more Rc in the part of resolver that gets cloned a lot #5118

Merged
merged 1 commit into from
Mar 4, 2018

Conversation

Eh2406
Copy link
Contributor

@Eh2406 Eh2406 commented Mar 4, 2018

In a test on #4810 (comment)
Before we got to 1700000 ticks in ~(82 to 97) sec
After we got to 1700000 ticks in ~(63 to 67) sec

In a test on rust-lang#4810 (comment)
Before we got to 1700000 ticks in ~(82 to 97) sec
After we got to 1700000 ticks in ~(63 to 67) sec
@rust-highfive
Copy link

r? @alexcrichton

(rust_highfive has picked a reviewer for you, use r? to override)

prev.push(summary.clone());
let mut inner: Vec<_> = (**prev).clone();
inner.push(summary.clone());
*prev = Rc::new(inner);
Copy link
Member

Choose a reason for hiding this comment

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

If we're optimizing for clones here, I wonder if this'd be better managed through an RcList perhaps?

Copy link
Contributor Author

@Eh2406 Eh2406 Mar 4, 2018

Choose a reason for hiding this comment

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

I was thinking of that, but we very often iter over the activated items. Specifically is_active, prev_active, and flag_activated. So it would be a pretty invasive change. I can give it a try if you want.

Also before we cloned every vec for every clone of Context for # clone vecs = O(# activated * ticks). Now we are cloning a vec each time we activate for # clone vecs = O(# activated). If I am miss reading it please correct me.

Copy link
Member

Choose a reason for hiding this comment

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

Ah an excellent point!

@alexcrichton
Copy link
Member

@bors: r+

@bors
Copy link
Contributor

bors commented Mar 4, 2018

📌 Commit af60861 has been approved by alexcrichton

@bors
Copy link
Contributor

bors commented Mar 4, 2018

⌛ Testing commit af60861 with merge 30f5f6d7a383cfab54f8d48dd4bec0598d694840...

@bors
Copy link
Contributor

bors commented Mar 4, 2018

💔 Test failed - status-travis

@alexcrichton
Copy link
Member

@bors: retry

@bors
Copy link
Contributor

bors commented Mar 4, 2018

⌛ Testing commit af60861 with merge cd230ad...

bors added a commit that referenced this pull request Mar 4, 2018
use more Rc in the part of resolver that gets cloned a lot

In a test on #4810 (comment)
Before we got to 1700000 ticks in ~(82 to 97) sec
After we got to 1700000 ticks in ~(63 to 67) sec
@bors
Copy link
Contributor

bors commented Mar 4, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: alexcrichton
Pushing cd230ad to master...

@bors bors merged commit af60861 into rust-lang:master Mar 4, 2018
@Eh2406 Eh2406 mentioned this pull request Mar 5, 2018
@Eh2406 Eh2406 deleted the more_rc branch March 6, 2018 20:53
bors added a commit that referenced this pull request Mar 7, 2018
String interning

This builds on the work from #5118. This interns the strings in the part of resolver that gets cloned a lot.

In a test on #4810 (comment)
Before we got to 1700000 ticks in ~(63 to 67) sec from #5118
After we got to 1700000 ticks in ~(42 to 45) sec

The interning code itself would be much better with a `leak` function that converts a `String` to a `&'static str`. Something like:
```rust
pub fn leek(s: String) -> &'static str {
    let ptr = s.as_ptr();
    let len = s.len();
    mem::forget(s);
    unsafe {
        let slice = slice::from_raw_parts(ptr, len);
        str::from_utf8(slice).unwrap()
    }
}
```
but "there is no unsafe in Cargo", and I am not the best at unsafe. So I just `to_string` and lived with the extra copy. Is there a better way to hand out references?

I assumed that `InternedString::new` world start appearing in profile result, and that we would want `PackageId`, and `Summary`, Et Al. to store the `InternedString`. That is why I put the interner in a shared folder. So far it is just used in the resolver. It may make sense for a lot more of the Strings to be interned, but with the extra copy... I have not explored it yet.
bors added a commit that referenced this pull request Apr 6, 2018
use more Rc in the part of resolver that gets cloned a lot 2

This is the same idea as #5118, I was looking at a profile and noted that ~5% of our time was sent dropping `HashMap<PackageId, HashSet<InternedString>>`. A quick rg and I found the culprit, we are cloning the set of features for every new `Context`. With some Rc we are now just cloning for each time we insert.

To benchmark I commented out line https://github.com/rust-lang/cargo/blob/b9aa315158fe4d8d63672a49200401922ef7385d/src/cargo/core/resolver/mod.rs#L453
the smallest change to get #4810 (comment) not to solve instantly.
Before 17000000 ticks, 90s, 188.889 ticks/ms
After 17000000 ticks, 73s, 232.877 ticks/ms
@ehuss ehuss added this to the 1.26.0 milestone Feb 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants