From b0f3003a3595f488062318a47bb5ef09622b3591 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 7 May 2018 11:57:49 +1000 Subject: [PATCH] Use LazyBTreeMap for region constraints. Because a lot of these BTreeMaps don't get anything inserted into them. In the most extreme case, this halves the number of total bytes allocated for a debug build of tuple-stress, from 2.2GB to 1.1GB. That reduction in turn speeds up runs of many benchmarks, the best by 3%. --- .../infer/lexical_region_resolve/graphviz.rs | 6 +-- src/librustc/infer/region_constraints/mod.rs | 6 +-- .../lazy_btree_map.rs | 43 +++++++++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/librustc/infer/lexical_region_resolve/graphviz.rs b/src/librustc/infer/lexical_region_resolve/graphviz.rs index d9d08294334db..28e11b4c49e27 100644 --- a/src/librustc/infer/lexical_region_resolve/graphviz.rs +++ b/src/librustc/infer/lexical_region_resolve/graphviz.rs @@ -25,11 +25,11 @@ use middle::region; use super::Constraint; use infer::SubregionOrigin; use infer::region_constraints::RegionConstraintData; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use util::nodemap::{FxHashMap, FxHashSet}; use std::borrow::Cow; use std::collections::hash_map::Entry::Vacant; -use std::collections::btree_map::BTreeMap; use std::env; use std::fs::File; use std::io; @@ -124,7 +124,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { graph_name: String, region_rels: &'a RegionRelations<'a, 'gcx, 'tcx>, - map: &'a BTreeMap, SubregionOrigin<'tcx>>, + map: &'a LazyBTreeMap, SubregionOrigin<'tcx>>, node_ids: FxHashMap, } @@ -264,7 +264,7 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { } } -pub type ConstraintMap<'tcx> = BTreeMap, SubregionOrigin<'tcx>>; +pub type ConstraintMap<'tcx> = LazyBTreeMap, SubregionOrigin<'tcx>>; fn dump_region_data_to<'a, 'gcx, 'tcx>(region_rels: &RegionRelations<'a, 'gcx, 'tcx>, map: &ConstraintMap<'tcx>, diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index c388fa2137192..c045dbb2684a9 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -16,15 +16,15 @@ use self::CombineMapType::*; use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin}; use super::unify_key; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use rustc_data_structures::unify as ut; use ty::{self, Ty, TyCtxt}; use ty::{Region, RegionVid}; use ty::ReStatic; use ty::{BrFresh, ReLateBound, ReVar}; -use std::collections::BTreeMap; use std::{cmp, fmt, mem, u32}; mod taint; @@ -81,7 +81,7 @@ pub type VarInfos = IndexVec; pub struct RegionConstraintData<'tcx> { /// Constraints of the form `A <= B`, where either `A` or `B` can /// be a region variable (or neither, as it happens). - pub constraints: BTreeMap, SubregionOrigin<'tcx>>, + pub constraints: LazyBTreeMap, SubregionOrigin<'tcx>>, /// A "verify" is something that we need to verify after inference /// is done, but which does not directly affect inference in any diff --git a/src/librustc_data_structures/lazy_btree_map.rs b/src/librustc_data_structures/lazy_btree_map.rs index 74f91af10fe63..fd38125b78100 100644 --- a/src/librustc_data_structures/lazy_btree_map.rs +++ b/src/librustc_data_structures/lazy_btree_map.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::borrow::Borrow; use std::collections::btree_map; use std::collections::BTreeMap; @@ -37,6 +38,10 @@ impl LazyBTreeMap { pub fn is_empty(&self) -> bool { self.0.as_ref().map_or(true, |btm| btm.is_empty()) } + + pub fn len(&self) -> usize { + self.0.as_ref().map_or(0, |btm| btm.len()) + } } impl LazyBTreeMap { @@ -50,19 +55,43 @@ impl LazyBTreeMap { } } + pub fn get(&self, key: &Q) -> Option<&V> + where K: Borrow, + Q: Ord + { + self.0.as_ref().and_then(|btm| btm.get(key)) + } + pub fn insert(&mut self, key: K, value: V) -> Option { self.instantiate().insert(key, value) } + pub fn remove(&mut self, key: &Q) -> Option + where K: Borrow, + Q: Ord + { + self.0.as_mut().and_then(|btm| btm.remove(key)) + } + pub fn entry(&mut self, key: K) -> btree_map::Entry { self.instantiate().entry(key) } + pub fn keys<'a>(&'a self) -> Keys<'a, K, V> { + Keys(self.0.as_ref().map(|btm| btm.keys())) + } + pub fn values<'a>(&'a self) -> Values<'a, K, V> { Values(self.0.as_ref().map(|btm| btm.values())) } } +impl Clone for LazyBTreeMap { + fn clone(&self) -> Self { + LazyBTreeMap(self.0.as_ref().map(|map| map.clone())) + } +} + impl Default for LazyBTreeMap { fn default() -> LazyBTreeMap { LazyBTreeMap::new() @@ -92,6 +121,20 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { } } +pub struct Keys<'a, K: 'a, V: 'a>(Option>); + +impl<'a, K, V> Iterator for Keys<'a, K, V> { + type Item = &'a K; + + fn next(&mut self) -> Option<&'a K> { + self.0.as_mut().and_then(|keys| keys.next()) + } + + fn size_hint(&self) -> (usize, Option) { + self.0.as_ref().map_or_else(|| (0, Some(0)), |keys| keys.size_hint()) + } +} + pub struct Values<'a, K: 'a, V: 'a>(Option>); impl<'a, K, V> Iterator for Values<'a, K, V> {