Skip to content

Commit 29d9960

Browse files
committed
Auto merge of #5293 - Eh2406:InternMoreStrings, r=alexcrichton
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?
2 parents 0729e06 + 5c9d34b commit 29d9960

File tree

7 files changed

+38
-33
lines changed

7 files changed

+38
-33
lines changed

src/cargo/core/dependency.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct Inner {
3232

3333
optional: bool,
3434
default_features: bool,
35-
features: Vec<String>,
35+
features: Vec<InternedString>,
3636

3737
// This dependency should be used only for this platform.
3838
// `None` means *all platforms*.
@@ -64,14 +64,15 @@ impl ser::Serialize for Dependency {
6464
where
6565
S: ser::Serializer,
6666
{
67+
let string_features: Vec<_> = self.features().iter().map(|s| s.to_string()).collect();
6768
SerializedDependency {
6869
name: &*self.name(),
6970
source: self.source_id(),
7071
req: self.version_req().to_string(),
7172
kind: self.kind(),
7273
optional: self.is_optional(),
7374
uses_default_features: self.uses_default_features(),
74-
features: self.features(),
75+
features: &string_features,
7576
target: self.platform(),
7677
rename: self.rename(),
7778
}.serialize(s)
@@ -250,7 +251,8 @@ impl Dependency {
250251

251252
/// Sets the list of features requested for the package.
252253
pub fn set_features(&mut self, features: Vec<String>) -> &mut Dependency {
253-
Rc::make_mut(&mut self.inner).features = features;
254+
Rc::make_mut(&mut self.inner).features =
255+
features.iter().map(|s| InternedString::new(s)).collect();
254256
self
255257
}
256258

@@ -334,7 +336,7 @@ impl Dependency {
334336
self.inner.default_features
335337
}
336338
/// Returns the list of features that are requested by the dependency.
337-
pub fn features(&self) -> &[String] {
339+
pub fn features(&self) -> &[InternedString] {
338340
&self.inner.features
339341
}
340342

src/cargo/core/resolver/context.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use std::collections::{HashMap, HashSet};
22
use std::rc::Rc;
33

4-
use core::{Dependency, FeatureValue, PackageId, SourceId, Summary};
54
use core::interning::InternedString;
6-
use util::Graph;
5+
use core::{Dependency, FeatureValue, PackageId, SourceId, Summary};
76
use util::CargoResult;
7+
use util::Graph;
88

9-
use super::types::{ActivateResult, ConflictReason, DepInfo, GraphNode, Method, RcList};
109
use super::types::RegistryQueryer;
10+
use super::types::{ActivateResult, ConflictReason, DepInfo, GraphNode, Method, RcList};
1111

1212
pub use super::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
1313
pub use super::encode::{Metadata, WorkspaceResolve};
@@ -160,7 +160,7 @@ impl Context {
160160
parent: Option<&Summary>,
161161
s: &'b Summary,
162162
method: &'b Method,
163-
) -> ActivateResult<Vec<(Dependency, Vec<String>)>> {
163+
) -> ActivateResult<Vec<(Dependency, Vec<InternedString>)>> {
164164
let dev_deps = match *method {
165165
Method::Everything => true,
166166
Method::Required { dev_deps, .. } => dev_deps,
@@ -182,7 +182,7 @@ impl Context {
182182
{
183183
requested
184184
.iter()
185-
.map(|f| FeatureValue::new(f, s))
185+
.map(|&f| FeatureValue::new(f, s))
186186
.collect::<Vec<FeatureValue>>()
187187
} else {
188188
vec![]
@@ -210,7 +210,7 @@ impl Context {
210210
));
211211
}
212212
let mut base = base.1;
213-
base.extend(dep.features().iter().cloned());
213+
base.extend(dep.features().iter());
214214
for feature in base.iter() {
215215
if feature.contains('/') {
216216
return Err(
@@ -331,7 +331,7 @@ struct Requirements<'a> {
331331
// specified set of features enabled. The boolean indicates whether this
332332
// package was specifically requested (rather than just requesting features
333333
// *within* this package).
334-
deps: HashMap<&'a str, (bool, Vec<String>)>,
334+
deps: HashMap<&'a str, (bool, Vec<InternedString>)>,
335335
// The used features set is the set of features which this local package had
336336
// enabled, which is later used when compiling to instruct the code what
337337
// features were enabled.
@@ -349,13 +349,13 @@ impl<'r> Requirements<'r> {
349349
}
350350
}
351351

352-
fn require_crate_feature(&mut self, package: &'r str, feat: &'r str) {
352+
fn require_crate_feature(&mut self, package: &'r str, feat: InternedString) {
353353
self.used.insert(package);
354354
self.deps
355355
.entry(package)
356356
.or_insert((false, Vec::new()))
357357
.1
358-
.push(feat.to_string());
358+
.push(feat);
359359
}
360360

361361
fn seen(&mut self, feat: &'r str) -> bool {
@@ -399,7 +399,7 @@ impl<'r> Requirements<'r> {
399399
match *fv {
400400
FeatureValue::Feature(ref feat) => self.require_feature(feat),
401401
FeatureValue::Crate(ref dep) => Ok(self.require_dependency(dep)),
402-
FeatureValue::CrateFeature(ref dep, ref dep_feat) => {
402+
FeatureValue::CrateFeature(ref dep, dep_feat) => {
403403
Ok(self.require_crate_feature(dep, dep_feat))
404404
}
405405
}

src/cargo/core/resolver/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ use semver;
5656

5757
use core::{Dependency, PackageId, Registry, Summary};
5858
use core::PackageIdSpec;
59+
use core::interning::InternedString;
5960
use util::config::Config;
6061
use util::Graph;
6162
use util::errors::{CargoError, CargoResult};
@@ -670,7 +671,7 @@ struct BacktrackFrame {
670671
remaining_candidates: RemainingCandidates,
671672
parent: Summary,
672673
dep: Dependency,
673-
features: Rc<Vec<String>>,
674+
features: Rc<Vec<InternedString>>,
674675
conflicting_activations: HashMap<PackageId, ConflictReason>,
675676
}
676677

src/cargo/core/resolver/types.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::ops::Range;
44
use std::rc::Rc;
55

66
use core::{Dependency, PackageId, PackageIdSpec, Registry, Summary};
7+
use core::interning::InternedString;
78
use util::{CargoError, CargoResult};
89

910
pub struct RegistryQueryer<'a> {
@@ -159,21 +160,21 @@ pub enum Method<'a> {
159160
Everything, // equivalent to Required { dev_deps: true, all_features: true, .. }
160161
Required {
161162
dev_deps: bool,
162-
features: &'a [String],
163+
features: &'a [InternedString],
163164
all_features: bool,
164165
uses_default_features: bool,
165166
},
166167
}
167168

168169
impl<'r> Method<'r> {
169-
pub fn split_features(features: &[String]) -> Vec<String> {
170+
pub fn split_features(features: &[String]) -> Vec<InternedString> {
170171
features
171172
.iter()
172173
.flat_map(|s| s.split_whitespace())
173174
.flat_map(|s| s.split(','))
174175
.filter(|s| !s.is_empty())
175-
.map(|s| s.to_string())
176-
.collect::<Vec<String>>()
176+
.map(|s| InternedString::new(s))
177+
.collect::<Vec<InternedString>>()
177178
}
178179
}
179180

@@ -245,7 +246,7 @@ impl Ord for DepsFrame {
245246
// Information about the dependencies for a crate, a tuple of:
246247
//
247248
// (dependency info, candidates, features activated)
248-
pub type DepInfo = (Dependency, Rc<Vec<Candidate>>, Rc<Vec<String>>);
249+
pub type DepInfo = (Dependency, Rc<Vec<Candidate>>, Rc<Vec<InternedString>>);
249250

250251
pub type ActivateResult<T> = Result<T, ActivateError>;
251252

src/cargo/core/summary.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ use std::collections::BTreeMap;
22
use std::mem;
33
use std::rc::Rc;
44

5-
use semver::Version;
6-
75
use serde::{Serialize, Serializer};
86

9-
use core::{Dependency, PackageId, SourceId};
107
use core::interning::InternedString;
8+
use core::{Dependency, PackageId, SourceId};
9+
use semver::Version;
1110

1211
use util::CargoResult;
1312

@@ -138,7 +137,7 @@ fn build_feature_map(
138137
for (feature, list) in features.iter() {
139138
let mut values = vec![];
140139
for dep in list {
141-
let val = FeatureValue::build(dep, |fs| (&features).get(fs).is_some());
140+
let val = FeatureValue::build(InternedString::new(dep), |fs| features.contains_key(fs));
142141
if let &Feature(_) = &val {
143142
values.push(val);
144143
continue;
@@ -201,7 +200,7 @@ pub enum FeatureValue {
201200
}
202201

203202
impl FeatureValue {
204-
fn build<T>(feature: &str, is_feature: T) -> FeatureValue
203+
fn build<T>(feature: InternedString, is_feature: T) -> FeatureValue
205204
where
206205
T: Fn(&str) -> bool,
207206
{
@@ -211,13 +210,13 @@ impl FeatureValue {
211210
let dep_feat = &dep_feat[1..];
212211
FeatureValue::CrateFeature(InternedString::new(dep), InternedString::new(dep_feat))
213212
}
214-
None if is_feature(&feature) => FeatureValue::Feature(InternedString::new(feature)),
215-
None => FeatureValue::Crate(InternedString::new(feature)),
213+
None if is_feature(&feature) => FeatureValue::Feature(feature),
214+
None => FeatureValue::Crate(feature),
216215
}
217216
}
218217

219-
pub fn new(feature: &str, s: &Summary) -> FeatureValue {
220-
Self::build(feature, |fs| s.features().get(fs).is_some())
218+
pub fn new(feature: InternedString, s: &Summary) -> FeatureValue {
219+
Self::build(feature, |fs| s.features().contains_key(fs))
221220
}
222221

223222
pub fn to_string(&self) -> String {

src/cargo/ops/registry.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ fn transmit(
171171
optional: dep.is_optional(),
172172
default_features: dep.uses_default_features(),
173173
name: dep.name().to_string(),
174-
features: dep.features().to_vec(),
174+
features: dep.features().iter().map(|s| s.to_string()).collect(),
175175
version_req: dep.version_req().to_string(),
176176
target: dep.platform().map(|s| s.to_string()),
177177
kind: match dep.kind() {

src/cargo/ops/resolve.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -472,9 +472,11 @@ fn register_previous_locks<'a>(
472472
// dependency on that crate to enable the feature. For now
473473
// this bug is better than the always updating registry
474474
// though...
475-
if !ws.members().any(|pkg| pkg.package_id() == member.package_id()) &&
476-
(dep.is_optional() || !dep.is_transitive()) {
477-
continue
475+
if !ws.members()
476+
.any(|pkg| pkg.package_id() == member.package_id())
477+
&& (dep.is_optional() || !dep.is_transitive())
478+
{
479+
continue;
478480
}
479481

480482
// Ok if nothing matches, then we poison the source of this

0 commit comments

Comments
 (0)