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

Introduce FeatureValue type to represent features table values #5270

Merged
merged 3 commits into from
Apr 4, 2018

Conversation

djc
Copy link
Contributor

@djc djc commented Mar 31, 2018

This is the next step towards #1286 (after #5258). The goal here is to have a central place in the code where feature strings are interpreted as (a) a feature, (b) a dependency or (c) a dependency/feature combo, and anchor that interpretation in the type system as an enum.

I've spent quite a bit of effort avoiding extra string allocations, complicating the code a bit; notice in particular the use of Cow<str> in FeatureValue variants, and the slight workaround in Context::resolve_features() and build_requirements(). I hope this is all okay.

cc @Eh2406

@Eh2406
Copy link
Contributor

Eh2406 commented Apr 2, 2018

I am very looking forward to reviewing this. From the description it sounds like a good approach. With the holiday I have not yet had a chance to review it.

@Eh2406
Copy link
Contributor

Eh2406 commented Apr 2, 2018

I took a look at it and I think it looks correct. I think using InternedString would make the code easier to read then using Cow. I have tried to convert feature string to be interned before and the hardest part was the code you are rewriting now. I have wondered before what percentage of ram assigned to cargo is storing copies of the string "serde" :-P

@djc
Copy link
Contributor Author

djc commented Apr 3, 2018

@Eh2406 I've done another take using InternedString in FeatureValue instead of Cow<str>:

https://github.com/rust-lang/cargo/compare/master...djc:interned-feature-reqs?expand=1

You're right that FeatureValue itself becomes easier to read and more compact. Do we need to run any benchmarks to determine the effect of these changes, or can we just move forward with the InternedString version of my branch?

@Eh2406
Copy link
Contributor

Eh2406 commented Apr 3, 2018

That does look clearer! I'd be ok just moving forward, the only part that can be slow is InternedString::new and .to_string(). We can always use more InternedString's so that neither of those are in the resolver loop. We could do that now or later, for the resolver it is definitely Performance Third Priority.

@alexcrichton
Copy link
Member

@bors: delegate=Eh2406

@bors
Copy link
Contributor

bors commented Apr 3, 2018

✌️ @Eh2406 can now approve this pull request

@djc
Copy link
Contributor Author

djc commented Apr 3, 2018

Okay, I've pushed the InternedString-based branch into this PR. Note that this still calls InternedString::new() a number of times in Context::resolve_features(), which is part of the call chain in resolver::activate(). Not sure if that's part of the hot loop, though.

@Eh2406
Copy link
Contributor

Eh2406 commented Apr 3, 2018

Unfortunately it is in the hot loop, but let's get it correct and clear before we think about performance. What do you see as the next step? Do you want that step to be in this PR, or in a separate one? Do you want all things that are storing feature strings to get converted to use FeatureValue?

@bors
Copy link
Contributor

bors commented Apr 3, 2018

☔ The latest upstream changes (presumably #5287) made this pull request unmergeable. Please resolve the merge conflicts.

@djc
Copy link
Contributor Author

djc commented Apr 4, 2018

I'd prefer to land this and do next steps in the next PR. The next step will be to introduce the namespaced-features flag in the package section, which will change how package manifest feature values get interpreted. It's probably useful if you look over the design in #1286, in particular #1286 (comment).

What other areas of the code do you think are working with feature strings? The thing about FeatureValue is that it can only interpret feature strings in the context of a particular Summary, so some of the places feature strings get used (including the whole call chain from command-line arguments into the resolver) don't make sense to convert because they're not as specific to a particular Summary.

Copy link
Contributor

@Eh2406 Eh2406 left a comment

Choose a reason for hiding this comment

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

2 little nits.

}
}

unsafe impl Send for InternedString {}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this is a rebase error, it was recently removedin https://github.com/rust-lang/cargo/pull/5287/files#diff-fc6e9b7a46297a8f6d7851cce9978683L94 as a &'static str is already send and sync.

/// * A feature in a depedency
///
/// The selection between these 3 things happens as part of the construction of the FeatureValue.
/// It stores a `Cow<str>`, so both `String` and `&str` can be used; typically, the former will
Copy link
Contributor

Choose a reason for hiding this comment

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

"It stores a Cow<str>" this is a little out of date

@Eh2406
Copy link
Contributor

Eh2406 commented Apr 4, 2018

Edit: Just notes that you had already changed a bunch of places to use FeatureValue that I was going to suggest you change. Sorry for the confusion.

I will happily r+ when the nits are addressed. I wanted to ask, instead of guessing, as I have seen this go wrong in both directions. I have seen PR's merged while I was still adding the rest of the big picture, and I have seen PR's waiting for approval because the PR was only for the first step.

Thank you for adding abstraction to some of the most "stringly typed" parts of the resolver. It was desperately needed.

@djc
Copy link
Contributor Author

djc commented Apr 4, 2018

Nits fixed, thanks for the review!

@Eh2406
Copy link
Contributor

Eh2406 commented Apr 4, 2018

@bors r+

@bors
Copy link
Contributor

bors commented Apr 4, 2018

📌 Commit 7621108 has been approved by Eh2406

@bors
Copy link
Contributor

bors commented Apr 4, 2018

⌛ Testing commit 7621108 with merge 61787c7a6733d5bf3dfd84c4865d0ca5d1f1b04b...

@bors
Copy link
Contributor

bors commented Apr 4, 2018

💔 Test failed - status-travis

@Eh2406
Copy link
Contributor

Eh2406 commented Apr 4, 2018

@bors retry

@bors
Copy link
Contributor

bors commented Apr 4, 2018

⌛ Testing commit 7621108 with merge 75f77fc...

bors added a commit that referenced this pull request Apr 4, 2018
Introduce FeatureValue type to represent features table values

This is the next step towards #1286 (after #5258). The goal here is to have a central place in the code where feature strings are interpreted as (a) a feature, (b) a dependency or (c) a dependency/feature combo, and anchor that interpretation in the type system as an enum.

I've spent quite a bit of effort avoiding extra string allocations, complicating the code a bit; notice in particular the use of `Cow<str>` in `FeatureValue` variants, and the slight workaround in `Context::resolve_features()` and `build_requirements()`. I hope this is all okay.

cc @Eh2406
@bors
Copy link
Contributor

bors commented Apr 4, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: Eh2406
Pushing 75f77fc to master...

@bors bors merged commit 7621108 into rust-lang:master Apr 4, 2018
"default_feat"
{
"Feature": "default_feat"
}
],
Copy link
Contributor

Choose a reason for hiding this comment

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

I only just notest that this change, after the merge. I don't know why/if this change in structures is ok. Will this break things using metadata?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, this definitely will break consumers that look at the features field. Could we preserve the old format here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oops -- sorry, I thought that was only used for testing. Will follow up with a fix.

@Eh2406 Eh2406 mentioned this pull request Apr 4, 2018
bors added a commit that referenced this pull request Apr 4, 2018
Revert serialization of features to string type

Accidentally broken during #5270 and only noticed after merge.

cc @matklad @Eh2406
bors added a commit that referenced this pull request Apr 4, 2018
Intern more strings

As pointed out in #5270 (comment), that clean up adds the mildly expensive `InternedString::new` to the hot path in the resolver.

The process of this PR is:
1. Find a `InternedString::new` in the hot path.
2. replace the argument of type `&str` that is passed along to `InternedString::new` with the type `InternedString`
3. add an `InternedString::new` to the callers until it type checked.
4. Repeat from step 1.

This stop if:
- It was traced back to something that was already an `InternedString`
- It was traced back to a `.to_string()` call
- It was in a persistent object creation

cc:
- @djc this is building on your work, I don't want to get in your way.
- @alexcrichton is this making things clearer and do you want to see a performance check?
Eh2406 added a commit to Eh2406/cargo that referenced this pull request May 10, 2018
use InternedString's ability to be a &'static str to appease the borrow checker

This "slight workaround" was added in rust-lang#5270. So @djc dose this still look correct?
bors added a commit that referenced this pull request May 10, 2018
simplify build_requirements

use InternedString's ability to be a &'static str to appease the borrow checker

This "slight workaround" was added in #5270. So @djc does this still look correct and an improvement?
@ehuss ehuss added this to the 1.27.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.

6 participants