Skip to content

Commit 5a1073f

Browse files
committed
auto merge of #9722 : alexcrichton/rust/less-mem, r=sanxiyn
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.
2 parents 1a3141b + 19e9766 commit 5a1073f

File tree

3 files changed

+126
-115
lines changed

3 files changed

+126
-115
lines changed

src/etc/get-snapshot.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ def unpack_snapshot(triple, dl_path):
2626
print("extracting " + p)
2727
tar.extract(p, download_unpack_base)
2828
tp = os.path.join(download_unpack_base, p)
29+
if os.path.isdir(tp) and os.path.exists(fp):
30+
continue
2931
shutil.move(tp, fp)
3032
tar.close()
3133
shutil.rmtree(download_unpack_base)

src/librustc/middle/const_eval.rs

Lines changed: 116 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ pub enum constness {
6060
non_const
6161
}
6262

63+
type constness_cache = HashMap<ast::DefId, constness>;
64+
6365
pub fn join(a: constness, b: constness) -> constness {
6466
match (a, b) {
6567
(integral_const, integral_const) => integral_const,
@@ -74,102 +76,12 @@ pub fn join_all<It: Iterator<constness>>(mut cs: It) -> constness {
7476
cs.fold(integral_const, |a, b| join(a, b))
7577
}
7678

77-
pub fn classify(e: &Expr,
78-
tcx: ty::ctxt)
79-
-> constness {
80-
let did = ast_util::local_def(e.id);
81-
match tcx.ccache.find(&did) {
82-
Some(&x) => x,
83-
None => {
84-
let cn =
85-
match e.node {
86-
ast::ExprLit(lit) => {
87-
match lit.node {
88-
ast::lit_str(*) |
89-
ast::lit_float(*) => general_const,
90-
_ => integral_const
91-
}
92-
}
93-
94-
ast::ExprUnary(_, _, inner) |
95-
ast::ExprParen(inner) => {
96-
classify(inner, tcx)
97-
}
98-
99-
ast::ExprBinary(_, _, a, b) => {
100-
join(classify(a, tcx),
101-
classify(b, tcx))
102-
}
103-
104-
ast::ExprTup(ref es) |
105-
ast::ExprVec(ref es, ast::MutImmutable) => {
106-
join_all(es.iter().map(|e| classify(*e, tcx)))
107-
}
108-
109-
ast::ExprVstore(e, vstore) => {
110-
match vstore {
111-
ast::ExprVstoreSlice => classify(e, tcx),
112-
ast::ExprVstoreUniq |
113-
ast::ExprVstoreBox |
114-
ast::ExprVstoreMutBox |
115-
ast::ExprVstoreMutSlice => non_const
116-
}
117-
}
118-
119-
ast::ExprStruct(_, ref fs, None) => {
120-
let cs = do fs.iter().map |f| {
121-
classify(f.expr, tcx)
122-
};
123-
join_all(cs)
124-
}
125-
126-
ast::ExprCast(base, _) => {
127-
let ty = ty::expr_ty(tcx, e);
128-
let base = classify(base, tcx);
129-
if ty::type_is_integral(ty) {
130-
join(integral_const, base)
131-
} else if ty::type_is_fp(ty) {
132-
join(general_const, base)
133-
} else {
134-
non_const
135-
}
136-
}
137-
138-
ast::ExprField(base, _, _) => {
139-
classify(base, tcx)
140-
}
141-
142-
ast::ExprIndex(_, base, idx) => {
143-
join(classify(base, tcx),
144-
classify(idx, tcx))
145-
}
146-
147-
ast::ExprAddrOf(ast::MutImmutable, base) => {
148-
classify(base, tcx)
149-
}
150-
151-
// FIXME: (#3728) we can probably do something CCI-ish
152-
// surrounding nonlocal constants. But we don't yet.
153-
ast::ExprPath(_) => {
154-
lookup_constness(tcx, e)
155-
}
156-
157-
ast::ExprRepeat(*) => general_const,
158-
159-
_ => non_const
160-
};
161-
tcx.ccache.insert(did, cn);
162-
cn
163-
}
164-
}
165-
}
166-
16779
pub fn lookup_const(tcx: ty::ctxt, e: &Expr) -> Option<@Expr> {
16880
match tcx.def_map.find(&e.id) {
169-
Some(&ast::DefStatic(def_id, false)) => lookup_const_by_id(tcx, def_id),
170-
Some(&ast::DefVariant(enum_def, variant_def, _)) => lookup_variant_by_id(tcx,
171-
enum_def,
172-
variant_def),
81+
Some(&ast::DefStatic(def_id, false)) =>
82+
lookup_const_by_id(tcx, def_id),
83+
Some(&ast::DefVariant(enum_def, variant_def, _)) =>
84+
lookup_variant_by_id(tcx, enum_def, variant_def),
17385
_ => None
17486
}
17587
}
@@ -199,14 +111,18 @@ pub fn lookup_variant_by_id(tcx: ty::ctxt,
199111
Some(_) => None
200112
}
201113
} else {
114+
match tcx.extern_const_variants.find(&variant_def) {
115+
Some(&e) => return e,
116+
None => {}
117+
}
202118
let maps = astencode::Maps {
203119
root_map: @mut HashMap::new(),
204120
method_map: @mut HashMap::new(),
205121
vtable_map: @mut HashMap::new(),
206122
write_guard_map: @mut HashSet::new(),
207123
capture_map: @mut HashMap::new()
208124
};
209-
match csearch::maybe_get_item_ast(tcx, enum_def,
125+
let e = match csearch::maybe_get_item_ast(tcx, enum_def,
210126
|a, b, c, d| astencode::decode_inlined_item(a,
211127
b,
212128
maps,
@@ -219,7 +135,9 @@ pub fn lookup_variant_by_id(tcx: ty::ctxt,
219135
_ => None
220136
},
221137
_ => None
222-
}
138+
};
139+
tcx.extern_const_variants.insert(variant_def, e);
140+
return e;
223141
}
224142
}
225143

@@ -236,49 +154,136 @@ pub fn lookup_const_by_id(tcx: ty::ctxt,
236154
Some(_) => None
237155
}
238156
} else {
157+
match tcx.extern_const_statics.find(&def_id) {
158+
Some(&e) => return e,
159+
None => {}
160+
}
239161
let maps = astencode::Maps {
240162
root_map: @mut HashMap::new(),
241163
method_map: @mut HashMap::new(),
242164
vtable_map: @mut HashMap::new(),
243165
write_guard_map: @mut HashSet::new(),
244166
capture_map: @mut HashMap::new()
245167
};
246-
match csearch::maybe_get_item_ast(tcx, def_id,
168+
let e = match csearch::maybe_get_item_ast(tcx, def_id,
247169
|a, b, c, d| astencode::decode_inlined_item(a, b, maps, c, d)) {
248170
csearch::found(ast::ii_item(item)) => match item.node {
249171
item_static(_, ast::MutImmutable, const_expr) => Some(const_expr),
250172
_ => None
251173
},
252174
_ => None
253-
}
175+
};
176+
tcx.extern_const_statics.insert(def_id, e);
177+
return e;
254178
}
255179
}
256180

257-
pub fn lookup_constness(tcx: ty::ctxt, e: &Expr) -> constness {
258-
match lookup_const(tcx, e) {
259-
Some(rhs) => {
260-
let ty = ty::expr_ty(tcx, rhs);
261-
if ty::type_is_integral(ty) {
262-
integral_const
263-
} else {
264-
general_const
181+
struct ConstEvalVisitor {
182+
tcx: ty::ctxt,
183+
ccache: constness_cache,
184+
}
185+
186+
impl ConstEvalVisitor {
187+
fn classify(&mut self, e: &Expr) -> constness {
188+
let did = ast_util::local_def(e.id);
189+
match self.ccache.find(&did) {
190+
Some(&x) => return x,
191+
None => {}
192+
}
193+
let cn = match e.node {
194+
ast::ExprLit(lit) => {
195+
match lit.node {
196+
ast::lit_str(*) | ast::lit_float(*) => general_const,
197+
_ => integral_const
198+
}
199+
}
200+
201+
ast::ExprUnary(_, _, inner) | ast::ExprParen(inner) =>
202+
self.classify(inner),
203+
204+
ast::ExprBinary(_, _, a, b) =>
205+
join(self.classify(a), self.classify(b)),
206+
207+
ast::ExprTup(ref es) |
208+
ast::ExprVec(ref es, ast::MutImmutable) =>
209+
join_all(es.iter().map(|e| self.classify(*e))),
210+
211+
ast::ExprVstore(e, vstore) => {
212+
match vstore {
213+
ast::ExprVstoreSlice => self.classify(e),
214+
ast::ExprVstoreUniq |
215+
ast::ExprVstoreBox |
216+
ast::ExprVstoreMutBox |
217+
ast::ExprVstoreMutSlice => non_const
218+
}
219+
}
220+
221+
ast::ExprStruct(_, ref fs, None) => {
222+
let cs = do fs.iter().map |f| {
223+
self.classify(f.expr)
224+
};
225+
join_all(cs)
226+
}
227+
228+
ast::ExprCast(base, _) => {
229+
let ty = ty::expr_ty(self.tcx, e);
230+
let base = self.classify(base);
231+
if ty::type_is_integral(ty) {
232+
join(integral_const, base)
233+
} else if ty::type_is_fp(ty) {
234+
join(general_const, base)
235+
} else {
236+
non_const
237+
}
238+
}
239+
240+
ast::ExprField(base, _, _) => self.classify(base),
241+
242+
ast::ExprIndex(_, base, idx) =>
243+
join(self.classify(base), self.classify(idx)),
244+
245+
ast::ExprAddrOf(ast::MutImmutable, base) => self.classify(base),
246+
247+
// FIXME: (#3728) we can probably do something CCI-ish
248+
// surrounding nonlocal constants. But we don't yet.
249+
ast::ExprPath(_) => self.lookup_constness(e),
250+
251+
ast::ExprRepeat(*) => general_const,
252+
253+
_ => non_const
254+
};
255+
self.ccache.insert(did, cn);
256+
cn
257+
}
258+
259+
fn lookup_constness(&self, e: &Expr) -> constness {
260+
match lookup_const(self.tcx, e) {
261+
Some(rhs) => {
262+
let ty = ty::expr_ty(self.tcx, rhs);
263+
if ty::type_is_integral(ty) {
264+
integral_const
265+
} else {
266+
general_const
267+
}
265268
}
269+
None => non_const
266270
}
267-
None => non_const
268271
}
269-
}
270272

271-
struct ConstEvalVisitor { tcx: ty::ctxt }
273+
}
272274

273275
impl Visitor<()> for ConstEvalVisitor {
274276
fn visit_expr_post(&mut self, e:@Expr, _:()) {
275-
classify(e, self.tcx);
277+
self.classify(e);
276278
}
277279
}
278280

279281
pub fn process_crate(crate: &ast::Crate,
280282
tcx: ty::ctxt) {
281-
let mut v = ConstEvalVisitor { tcx: tcx };
283+
let mut v = ConstEvalVisitor {
284+
tcx: tcx,
285+
ccache: HashMap::new(),
286+
};
282287
visit::walk_crate(&mut v, crate, ());
283288
tcx.sess.abort_if_errors();
284289
}

src/librustc/middle/ty.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,6 @@ struct ctxt_ {
290290
freevars: freevars::freevar_map,
291291
tcache: type_cache,
292292
rcache: creader_cache,
293-
ccache: constness_cache,
294293
short_names_cache: @mut HashMap<t, @str>,
295294
needs_unwind_cleanup_cache: @mut HashMap<t, bool>,
296295
tc_cache: @mut HashMap<uint, TypeContents>,
@@ -346,6 +345,11 @@ struct ctxt_ {
346345
// The set of external traits whose implementations have been read. This
347346
// is used for lazy resolution of traits.
348347
populated_external_traits: @mut HashSet<ast::DefId>,
348+
349+
// These two caches are used by const_eval when decoding external statics
350+
// and variants that are found.
351+
extern_const_statics: @mut HashMap<ast::DefId, Option<@ast::Expr>>,
352+
extern_const_variants: @mut HashMap<ast::DefId, Option<@ast::Expr>>,
349353
}
350354

351355
pub enum tbox_flag {
@@ -897,8 +901,6 @@ pub struct ty_param_substs_and_ty {
897901

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

900-
type constness_cache = @mut HashMap<ast::DefId, const_eval::constness>;
901-
902904
pub type node_type_table = @mut HashMap<uint,t>;
903905

904906
fn mk_rcache() -> creader_cache {
@@ -935,7 +937,6 @@ pub fn mk_ctxt(s: session::Session,
935937
freevars: freevars,
936938
tcache: @mut HashMap::new(),
937939
rcache: mk_rcache(),
938-
ccache: @mut HashMap::new(),
939940
short_names_cache: new_ty_hash(),
940941
needs_unwind_cleanup_cache: new_ty_hash(),
941942
tc_cache: @mut HashMap::new(),
@@ -961,6 +962,9 @@ pub fn mk_ctxt(s: session::Session,
961962
impl_vtables: @mut HashMap::new(),
962963
populated_external_types: @mut HashSet::new(),
963964
populated_external_traits: @mut HashSet::new(),
965+
966+
extern_const_statics: @mut HashMap::new(),
967+
extern_const_variants: @mut HashMap::new(),
964968
}
965969
}
966970

0 commit comments

Comments
 (0)