Skip to content

Commit

Permalink
auto merge of #9722 : alexcrichton/rust/less-mem, r=sanxiyn
Browse files Browse the repository at this point in the history
According to http://huonw.github.io/isrustfastyet/mem/#012f909, the "const
marking" pass generates about 400MB of extra memory during compilation. It
appears that this is due to two different factors:

    1. There is a `ccache` map in the ty::ctxt which is only ever used in this
       pass, so this commit moves the map out of the ty::ctxt struct and into
       just this pass's visitor. This turned out to not benefit that much in
       memory (as indicated by http://i.imgur.com/Eo4iOzK.png), but it's helpful
       to do nonetheless.

    2. During const_eval, there are a lot of lookups into decoding inlined items
       from external crates. There is no caching involved here, so the same
       static or variant could be re-translated many times. After adding
       separate caches for variants and statics, the memory peak of compiling
       rustc decreased by 200MB (as evident by http://i.imgur.com/ULAUMtq.png)

The culmination of this is basically a slight reorganization of a caching map
for the const_eval pass along with a 200MB decrease in peak memory usage when
compiling librustc.
  • Loading branch information
bors committed Oct 5, 2013
2 parents 1a3141b + 19e9766 commit 5a1073f
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 115 deletions.
2 changes: 2 additions & 0 deletions src/etc/get-snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ def unpack_snapshot(triple, dl_path):
print("extracting " + p)
tar.extract(p, download_unpack_base)
tp = os.path.join(download_unpack_base, p)
if os.path.isdir(tp) and os.path.exists(fp):
continue
shutil.move(tp, fp)
tar.close()
shutil.rmtree(download_unpack_base)
Expand Down
227 changes: 116 additions & 111 deletions src/librustc/middle/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ pub enum constness {
non_const
}

type constness_cache = HashMap<ast::DefId, constness>;

pub fn join(a: constness, b: constness) -> constness {
match (a, b) {
(integral_const, integral_const) => integral_const,
Expand All @@ -74,102 +76,12 @@ pub fn join_all<It: Iterator<constness>>(mut cs: It) -> constness {
cs.fold(integral_const, |a, b| join(a, b))
}

pub fn classify(e: &Expr,
tcx: ty::ctxt)
-> constness {
let did = ast_util::local_def(e.id);
match tcx.ccache.find(&did) {
Some(&x) => x,
None => {
let cn =
match e.node {
ast::ExprLit(lit) => {
match lit.node {
ast::lit_str(*) |
ast::lit_float(*) => general_const,
_ => integral_const
}
}

ast::ExprUnary(_, _, inner) |
ast::ExprParen(inner) => {
classify(inner, tcx)
}

ast::ExprBinary(_, _, a, b) => {
join(classify(a, tcx),
classify(b, tcx))
}

ast::ExprTup(ref es) |
ast::ExprVec(ref es, ast::MutImmutable) => {
join_all(es.iter().map(|e| classify(*e, tcx)))
}

ast::ExprVstore(e, vstore) => {
match vstore {
ast::ExprVstoreSlice => classify(e, tcx),
ast::ExprVstoreUniq |
ast::ExprVstoreBox |
ast::ExprVstoreMutBox |
ast::ExprVstoreMutSlice => non_const
}
}

ast::ExprStruct(_, ref fs, None) => {
let cs = do fs.iter().map |f| {
classify(f.expr, tcx)
};
join_all(cs)
}

ast::ExprCast(base, _) => {
let ty = ty::expr_ty(tcx, e);
let base = classify(base, tcx);
if ty::type_is_integral(ty) {
join(integral_const, base)
} else if ty::type_is_fp(ty) {
join(general_const, base)
} else {
non_const
}
}

ast::ExprField(base, _, _) => {
classify(base, tcx)
}

ast::ExprIndex(_, base, idx) => {
join(classify(base, tcx),
classify(idx, tcx))
}

ast::ExprAddrOf(ast::MutImmutable, base) => {
classify(base, tcx)
}

// FIXME: (#3728) we can probably do something CCI-ish
// surrounding nonlocal constants. But we don't yet.
ast::ExprPath(_) => {
lookup_constness(tcx, e)
}

ast::ExprRepeat(*) => general_const,

_ => non_const
};
tcx.ccache.insert(did, cn);
cn
}
}
}

pub fn lookup_const(tcx: ty::ctxt, e: &Expr) -> Option<@Expr> {
match tcx.def_map.find(&e.id) {
Some(&ast::DefStatic(def_id, false)) => lookup_const_by_id(tcx, def_id),
Some(&ast::DefVariant(enum_def, variant_def, _)) => lookup_variant_by_id(tcx,
enum_def,
variant_def),
Some(&ast::DefStatic(def_id, false)) =>
lookup_const_by_id(tcx, def_id),
Some(&ast::DefVariant(enum_def, variant_def, _)) =>
lookup_variant_by_id(tcx, enum_def, variant_def),
_ => None
}
}
Expand Down Expand Up @@ -199,14 +111,18 @@ pub fn lookup_variant_by_id(tcx: ty::ctxt,
Some(_) => None
}
} else {
match tcx.extern_const_variants.find(&variant_def) {
Some(&e) => return e,
None => {}
}
let maps = astencode::Maps {
root_map: @mut HashMap::new(),
method_map: @mut HashMap::new(),
vtable_map: @mut HashMap::new(),
write_guard_map: @mut HashSet::new(),
capture_map: @mut HashMap::new()
};
match csearch::maybe_get_item_ast(tcx, enum_def,
let e = match csearch::maybe_get_item_ast(tcx, enum_def,
|a, b, c, d| astencode::decode_inlined_item(a,
b,
maps,
Expand All @@ -219,7 +135,9 @@ pub fn lookup_variant_by_id(tcx: ty::ctxt,
_ => None
},
_ => None
}
};
tcx.extern_const_variants.insert(variant_def, e);
return e;
}
}

Expand All @@ -236,49 +154,136 @@ pub fn lookup_const_by_id(tcx: ty::ctxt,
Some(_) => None
}
} else {
match tcx.extern_const_statics.find(&def_id) {
Some(&e) => return e,
None => {}
}
let maps = astencode::Maps {
root_map: @mut HashMap::new(),
method_map: @mut HashMap::new(),
vtable_map: @mut HashMap::new(),
write_guard_map: @mut HashSet::new(),
capture_map: @mut HashMap::new()
};
match csearch::maybe_get_item_ast(tcx, def_id,
let e = match csearch::maybe_get_item_ast(tcx, def_id,
|a, b, c, d| astencode::decode_inlined_item(a, b, maps, c, d)) {
csearch::found(ast::ii_item(item)) => match item.node {
item_static(_, ast::MutImmutable, const_expr) => Some(const_expr),
_ => None
},
_ => None
}
};
tcx.extern_const_statics.insert(def_id, e);
return e;
}
}

pub fn lookup_constness(tcx: ty::ctxt, e: &Expr) -> constness {
match lookup_const(tcx, e) {
Some(rhs) => {
let ty = ty::expr_ty(tcx, rhs);
if ty::type_is_integral(ty) {
integral_const
} else {
general_const
struct ConstEvalVisitor {
tcx: ty::ctxt,
ccache: constness_cache,
}

impl ConstEvalVisitor {
fn classify(&mut self, e: &Expr) -> constness {
let did = ast_util::local_def(e.id);
match self.ccache.find(&did) {
Some(&x) => return x,
None => {}
}
let cn = match e.node {
ast::ExprLit(lit) => {
match lit.node {
ast::lit_str(*) | ast::lit_float(*) => general_const,
_ => integral_const
}
}

ast::ExprUnary(_, _, inner) | ast::ExprParen(inner) =>
self.classify(inner),

ast::ExprBinary(_, _, a, b) =>
join(self.classify(a), self.classify(b)),

ast::ExprTup(ref es) |
ast::ExprVec(ref es, ast::MutImmutable) =>
join_all(es.iter().map(|e| self.classify(*e))),

ast::ExprVstore(e, vstore) => {
match vstore {
ast::ExprVstoreSlice => self.classify(e),
ast::ExprVstoreUniq |
ast::ExprVstoreBox |
ast::ExprVstoreMutBox |
ast::ExprVstoreMutSlice => non_const
}
}

ast::ExprStruct(_, ref fs, None) => {
let cs = do fs.iter().map |f| {
self.classify(f.expr)
};
join_all(cs)
}

ast::ExprCast(base, _) => {
let ty = ty::expr_ty(self.tcx, e);
let base = self.classify(base);
if ty::type_is_integral(ty) {
join(integral_const, base)
} else if ty::type_is_fp(ty) {
join(general_const, base)
} else {
non_const
}
}

ast::ExprField(base, _, _) => self.classify(base),

ast::ExprIndex(_, base, idx) =>
join(self.classify(base), self.classify(idx)),

ast::ExprAddrOf(ast::MutImmutable, base) => self.classify(base),

// FIXME: (#3728) we can probably do something CCI-ish
// surrounding nonlocal constants. But we don't yet.
ast::ExprPath(_) => self.lookup_constness(e),

ast::ExprRepeat(*) => general_const,

_ => non_const
};
self.ccache.insert(did, cn);
cn
}

fn lookup_constness(&self, e: &Expr) -> constness {
match lookup_const(self.tcx, e) {
Some(rhs) => {
let ty = ty::expr_ty(self.tcx, rhs);
if ty::type_is_integral(ty) {
integral_const
} else {
general_const
}
}
None => non_const
}
None => non_const
}
}

struct ConstEvalVisitor { tcx: ty::ctxt }
}

impl Visitor<()> for ConstEvalVisitor {
fn visit_expr_post(&mut self, e:@Expr, _:()) {
classify(e, self.tcx);
self.classify(e);
}
}

pub fn process_crate(crate: &ast::Crate,
tcx: ty::ctxt) {
let mut v = ConstEvalVisitor { tcx: tcx };
let mut v = ConstEvalVisitor {
tcx: tcx,
ccache: HashMap::new(),
};
visit::walk_crate(&mut v, crate, ());
tcx.sess.abort_if_errors();
}
Expand Down
12 changes: 8 additions & 4 deletions src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,6 @@ struct ctxt_ {
freevars: freevars::freevar_map,
tcache: type_cache,
rcache: creader_cache,
ccache: constness_cache,
short_names_cache: @mut HashMap<t, @str>,
needs_unwind_cleanup_cache: @mut HashMap<t, bool>,
tc_cache: @mut HashMap<uint, TypeContents>,
Expand Down Expand Up @@ -346,6 +345,11 @@ struct ctxt_ {
// The set of external traits whose implementations have been read. This
// is used for lazy resolution of traits.
populated_external_traits: @mut HashSet<ast::DefId>,

// These two caches are used by const_eval when decoding external statics
// and variants that are found.
extern_const_statics: @mut HashMap<ast::DefId, Option<@ast::Expr>>,
extern_const_variants: @mut HashMap<ast::DefId, Option<@ast::Expr>>,
}

pub enum tbox_flag {
Expand Down Expand Up @@ -897,8 +901,6 @@ pub struct ty_param_substs_and_ty {

type type_cache = @mut HashMap<ast::DefId, ty_param_bounds_and_ty>;

type constness_cache = @mut HashMap<ast::DefId, const_eval::constness>;

pub type node_type_table = @mut HashMap<uint,t>;

fn mk_rcache() -> creader_cache {
Expand Down Expand Up @@ -935,7 +937,6 @@ pub fn mk_ctxt(s: session::Session,
freevars: freevars,
tcache: @mut HashMap::new(),
rcache: mk_rcache(),
ccache: @mut HashMap::new(),
short_names_cache: new_ty_hash(),
needs_unwind_cleanup_cache: new_ty_hash(),
tc_cache: @mut HashMap::new(),
Expand All @@ -961,6 +962,9 @@ pub fn mk_ctxt(s: session::Session,
impl_vtables: @mut HashMap::new(),
populated_external_types: @mut HashSet::new(),
populated_external_traits: @mut HashSet::new(),

extern_const_statics: @mut HashMap::new(),
extern_const_variants: @mut HashMap::new(),
}
}

Expand Down

0 comments on commit 5a1073f

Please sign in to comment.