Skip to content

Commit d932bbd

Browse files
committed
Auto merge of rust-lang#137354 - FractalFir:intern_with_cap, r=<try>
[perf experiment] Changed interners to start preallocated with an increased capacity Inspired by rust-lang#137005. *Not meant to be merged in its current form* Added a `with_capacity` function to `InternedSet`. Changed the `CtxtInterners` to start with `InternedSets` preallocated with a capacity. This *does* increase memory usage at very slightly(by 1 MB at the start), altough that increase quickly disaperars for larger crates(since they require such capacity anyway). A local perf run indicates this improves compiletimes for small crates(like `ripgrep`), without a negative effect on larger ones: ![image](https://github.com/user-attachments/assets/4a7f3317-7e61-4b28-a651-cc79ee990689) The current default capacities are choosen somewhat arbitrarily, and are relatively low. Depending on what kind of memory usage is acceptable, it may be beneficial to increase that capacity for some interners. From a second local perf run(with capacity of `_type` increased to `131072`), it looks like increasing the size of the preallocated type interner has the biggest impact: ![image](https://github.com/user-attachments/assets/08ac324a-b03c-4fe9-b779-4dd35e7970d9) What would be the maximum acceptable memory usage increase? I think most people would not mind sacrificing 1-2MB for an improvement in compile speed, but I am curious what is the general opinion here.
2 parents b6d3be4 + cf73fd6 commit d932bbd

File tree

2 files changed

+32
-24
lines changed

2 files changed

+32
-24
lines changed

compiler/rustc_data_structures/src/sharded.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ pub fn shards() -> usize {
143143
pub type ShardedHashMap<K, V> = Sharded<FxHashMap<K, V>>;
144144

145145
impl<K: Eq, V> ShardedHashMap<K, V> {
146+
pub fn with_capacity(cap: usize) -> Self {
147+
Self::new(|| FxHashMap::with_capacity_and_hasher(cap, rustc_hash::FxBuildHasher::default()))
148+
}
146149
pub fn len(&self) -> usize {
147150
self.lock_shards().map(|shard| shard.len()).sum()
148151
}

compiler/rustc_middle/src/ty/context.rs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -812,32 +812,35 @@ pub struct CtxtInterners<'tcx> {
812812

813813
impl<'tcx> CtxtInterners<'tcx> {
814814
fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
815+
// Default interner size - this value has been chosen empirically, and may need to be adjusted
816+
// as the compiler evolves.
817+
const DEF_INTERN_SIZE:usize = 2048;
815818
CtxtInterners {
816819
arena,
817-
type_: Default::default(),
818-
const_lists: Default::default(),
819-
args: Default::default(),
820-
type_lists: Default::default(),
821-
region: Default::default(),
822-
poly_existential_predicates: Default::default(),
823-
canonical_var_infos: Default::default(),
824-
predicate: Default::default(),
825-
clauses: Default::default(),
826-
projs: Default::default(),
827-
place_elems: Default::default(),
828-
const_: Default::default(),
829-
pat: Default::default(),
830-
const_allocation: Default::default(),
831-
bound_variable_kinds: Default::default(),
832-
layout: Default::default(),
833-
adt_def: Default::default(),
834-
external_constraints: Default::default(),
835-
predefined_opaques_in_body: Default::default(),
836-
fields: Default::default(),
837-
local_def_ids: Default::default(),
838-
captures: Default::default(),
839-
offset_of: Default::default(),
840-
valtree: Default::default(),
820+
type_: InternedSet::with_capacity(DEF_INTERN_SIZE * 16),
821+
const_lists: InternedSet::with_capacity(DEF_INTERN_SIZE * 4),
822+
args: InternedSet::with_capacity(DEF_INTERN_SIZE * 4),
823+
type_lists: InternedSet::with_capacity(DEF_INTERN_SIZE * 4),
824+
region: InternedSet::with_capacity(DEF_INTERN_SIZE * 4),
825+
poly_existential_predicates: InternedSet::with_capacity(DEF_INTERN_SIZE/4),
826+
canonical_var_infos: InternedSet::with_capacity(DEF_INTERN_SIZE/2),
827+
predicate: InternedSet::with_capacity(DEF_INTERN_SIZE),
828+
clauses: InternedSet::with_capacity(DEF_INTERN_SIZE),
829+
projs: InternedSet::with_capacity(DEF_INTERN_SIZE*4),
830+
place_elems: InternedSet::with_capacity(DEF_INTERN_SIZE*2),
831+
const_: InternedSet::with_capacity(DEF_INTERN_SIZE*2),
832+
pat: InternedSet::with_capacity(DEF_INTERN_SIZE),
833+
const_allocation: InternedSet::with_capacity(DEF_INTERN_SIZE),
834+
bound_variable_kinds: InternedSet::with_capacity(DEF_INTERN_SIZE*2),
835+
layout: InternedSet::with_capacity(DEF_INTERN_SIZE),
836+
adt_def: InternedSet::with_capacity(DEF_INTERN_SIZE),
837+
external_constraints: InternedSet::with_capacity(DEF_INTERN_SIZE),
838+
predefined_opaques_in_body: InternedSet::with_capacity(DEF_INTERN_SIZE),
839+
fields: InternedSet::with_capacity(DEF_INTERN_SIZE*4),
840+
local_def_ids: InternedSet::with_capacity(DEF_INTERN_SIZE),
841+
captures: InternedSet::with_capacity(DEF_INTERN_SIZE),
842+
offset_of: InternedSet::with_capacity(DEF_INTERN_SIZE),
843+
valtree: InternedSet::with_capacity(DEF_INTERN_SIZE),
841844
}
842845
}
843846

@@ -2547,6 +2550,7 @@ macro_rules! slice_interners {
25472550
($($field:ident: $vis:vis $method:ident($ty:ty)),+ $(,)?) => (
25482551
impl<'tcx> TyCtxt<'tcx> {
25492552
$($vis fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
2553+
//eprintln!("{} len:{}",stringify!($field), self.interners.$field.len());
25502554
if v.is_empty() {
25512555
List::empty()
25522556
} else {
@@ -2845,6 +2849,7 @@ impl<'tcx> TyCtxt<'tcx> {
28452849
// FIXME consider asking the input slice to be sorted to avoid
28462850
// re-interning permutations, in which case that would be asserted
28472851
// here.
2852+
28482853
self.intern_local_def_ids(clauses)
28492854
}
28502855

0 commit comments

Comments
 (0)