Skip to content

Commit 868c702

Browse files
committed
Auto merge of #86695 - sexxi-goose:closure_size, r=nikomatsakis
Introduce -Zprofile-closures to evaluate the impact of 2229 This creates a CSV with name "closure_profile_XXXXX.csv", where the variable part is the process id of the compiler. To profile a cargo project you can run one of the following depending on if you're compiling a library or a binary: ``` cargo +nightly rustc --lib -- -Zprofile-closures cargo +nightly rustc --bin {binary_name} -- -Zprofile-closures ``` r? `@nikomatsakis`
2 parents 5d34076 + fc273e9 commit 868c702

File tree

9 files changed

+148
-7
lines changed

9 files changed

+148
-7
lines changed

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ fn test_debugging_options_tracking_hash() {
654654
untracked!(perf_stats, true);
655655
// `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
656656
untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
657+
untracked!(profile_closures, true);
657658
untracked!(print_link_args, true);
658659
untracked!(print_llvm_passes, true);
659660
untracked!(print_mono_items, Some(String::from("abc")));

compiler/rustc_middle/src/ty/context.rs

+13-5
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ use crate::ty::query::{self, OnDiskCache, TyCtxtAt};
1919
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
2020
use crate::ty::TyKind::*;
2121
use crate::ty::{
22-
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
23-
DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
24-
InferTy, IntTy, IntVar, IntVid, List, MainDefinition, ParamConst, ParamTy, PolyFnSig,
25-
Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
26-
TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
22+
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
23+
ClosureSizeProfileData, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar,
24+
FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
25+
MainDefinition, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
26+
ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
27+
TyVid, TypeAndMut, UintTy, Visibility,
2728
};
2829
use rustc_ast as ast;
2930
use rustc_attr as attr;
@@ -483,6 +484,10 @@ pub struct TypeckResults<'tcx> {
483484
/// This hashset records all instances where we behave
484485
/// like this to allow `const_to_pat` to reliably handle this situation.
485486
pub treat_byte_string_as_slice: ItemLocalSet,
487+
488+
/// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
489+
/// on closure size.
490+
pub closure_size_eval: FxHashMap<DefId, ClosureSizeProfileData<'tcx>>,
486491
}
487492

488493
impl<'tcx> TypeckResults<'tcx> {
@@ -509,6 +514,7 @@ impl<'tcx> TypeckResults<'tcx> {
509514
closure_fake_reads: Default::default(),
510515
generator_interior_types: ty::Binder::dummy(Default::default()),
511516
treat_byte_string_as_slice: Default::default(),
517+
closure_size_eval: Default::default(),
512518
}
513519
}
514520

@@ -753,6 +759,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
753759
ref closure_fake_reads,
754760
ref generator_interior_types,
755761
ref treat_byte_string_as_slice,
762+
ref closure_size_eval,
756763
} = *self;
757764

758765
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
@@ -779,6 +786,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
779786
closure_fake_reads.hash_stable(hcx, hasher);
780787
generator_interior_types.hash_stable(hcx, hasher);
781788
treat_byte_string_as_slice.hash_stable(hcx, hasher);
789+
closure_size_eval.hash_stable(hcx, hasher);
782790
})
783791
}
784792
}

compiler/rustc_middle/src/ty/mod.rs

+19
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,25 @@ pub enum Visibility {
175175
Invisible,
176176
}
177177

178+
#[derive(
179+
Clone,
180+
Debug,
181+
PartialEq,
182+
Eq,
183+
Copy,
184+
Hash,
185+
TyEncodable,
186+
TyDecodable,
187+
HashStable,
188+
TypeFoldable
189+
)]
190+
pub struct ClosureSizeProfileData<'tcx> {
191+
/// Tuple containing the types of closure captures before the feature `capture_disjoint_fields`
192+
pub before_feature_tys: Ty<'tcx>,
193+
/// Tuple containing the types of closure captures after the feature `capture_disjoint_fields`
194+
pub after_feature_tys: Ty<'tcx>,
195+
}
196+
178197
pub trait DefIdTree: Copy {
179198
fn parent(self, id: DefId) -> Option<DefId>;
180199

compiler/rustc_mir/src/monomorphize/collector.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,13 @@ fn create_fn_mono_item<'tcx>(
10711071
source: Span,
10721072
) -> Spanned<MonoItem<'tcx>> {
10731073
debug!("create_fn_mono_item(instance={})", instance);
1074+
1075+
let def_id = instance.def_id();
1076+
if tcx.sess.opts.debugging_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id)
1077+
{
1078+
monomorphize::util::dump_closure_profile(tcx, instance);
1079+
}
1080+
10741081
respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
10751082
}
10761083

compiler/rustc_mir/src/monomorphize/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use rustc_hir::lang_items::LangItem;
77
pub mod collector;
88
pub mod partitioning;
99
pub mod polymorphize;
10+
pub mod util;
1011

1112
fn custom_coerce_unsize_info<'tcx>(
1213
tcx: TyCtxt<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use rustc_middle::ty::{self, ClosureSizeProfileData, Instance, TyCtxt};
2+
use std::fs::OpenOptions;
3+
use std::io::prelude::*;
4+
5+
/// For a given closure, writes out the data for the profiling the impact of RFC 2229 on
6+
/// closure size into a CSV.
7+
///
8+
/// During the same compile all closures dump the information in the same file
9+
/// "closure_profile_XXXXX.csv", which is created in the directory where the compiler is invoked.
10+
crate fn dump_closure_profile(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) {
11+
let mut file = if let Ok(file) = OpenOptions::new()
12+
.create(true)
13+
.append(true)
14+
.open(&format!("closure_profile_{}.csv", std::process::id()))
15+
{
16+
file
17+
} else {
18+
eprintln!("Cound't open file for writing closure profile");
19+
return;
20+
};
21+
22+
let closure_def_id = closure_instance.def_id();
23+
let typeck_results = tcx.typeck(closure_def_id.expect_local());
24+
25+
if typeck_results.closure_size_eval.contains_key(&closure_def_id) {
26+
let param_env = ty::ParamEnv::reveal_all();
27+
28+
let ClosureSizeProfileData { before_feature_tys, after_feature_tys } =
29+
typeck_results.closure_size_eval[&closure_def_id];
30+
31+
let before_feature_tys = tcx.subst_and_normalize_erasing_regions(
32+
closure_instance.substs,
33+
param_env,
34+
before_feature_tys,
35+
);
36+
let after_feature_tys = tcx.subst_and_normalize_erasing_regions(
37+
closure_instance.substs,
38+
param_env,
39+
after_feature_tys,
40+
);
41+
42+
let new_size = tcx
43+
.layout_of(param_env.and(after_feature_tys))
44+
.map(|l| format!("{:?}", l.size.bytes()))
45+
.unwrap_or_else(|e| format!("Failed {:?}", e));
46+
47+
let old_size = tcx
48+
.layout_of(param_env.and(before_feature_tys))
49+
.map(|l| format!("{:?}", l.size.bytes()))
50+
.unwrap_or_else(|e| format!("Failed {:?}", e));
51+
52+
let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
53+
let closure_span = tcx.hir().span(closure_hir_id);
54+
let src_file = tcx.sess.source_map().span_to_filename(closure_span);
55+
let line_nos = tcx
56+
.sess
57+
.source_map()
58+
.span_to_lines(closure_span)
59+
.map(|l| format!("{:?} {:?}", l.lines.first(), l.lines.last()))
60+
.unwrap_or_else(|e| format!("{:?}", e));
61+
62+
if let Err(e) = writeln!(
63+
file,
64+
"{}, {}, {}, {:?}",
65+
old_size,
66+
new_size,
67+
src_file.prefer_local(),
68+
line_nos
69+
) {
70+
eprintln!("Error writting to file {}", e.to_string())
71+
}
72+
}
73+
}

compiler/rustc_session/src/options.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1209,6 +1209,8 @@ options! {
12091209
"show backtraces for panics during proc-macro execution (default: no)"),
12101210
profile: bool = (false, parse_bool, [TRACKED],
12111211
"insert profiling code (default: no)"),
1212+
profile_closures: bool = (false, parse_no_flag, [UNTRACKED],
1213+
"profile size of closures"),
12121214
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
12131215
"file path to emit profiling data at runtime when using 'profile' \
12141216
(default based on relative source path)"),

compiler/rustc_typeck/src/check/upvar.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
4242
use rustc_infer::infer::UpvarRegion;
4343
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
4444
use rustc_middle::mir::FakeReadCause;
45-
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeckResults, UpvarSubsts};
45+
use rustc_middle::ty::{
46+
self, ClosureSizeProfileData, TraitRef, Ty, TyCtxt, TypeckResults, UpvarSubsts,
47+
};
4648
use rustc_session::lint;
4749
use rustc_span::sym;
4850
use rustc_span::{MultiSpan, Span, Symbol};
@@ -175,6 +177,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
175177
self.perform_2229_migration_anaysis(closure_def_id, body_id, capture_clause, span);
176178
}
177179

180+
let after_feature_tys = self.final_upvar_tys(closure_def_id);
181+
178182
// We now fake capture information for all variables that are mentioned within the closure
179183
// We do this after handling migrations so that min_captures computes before
180184
if !enable_precise_capture(self.tcx, span) {
@@ -203,6 +207,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
203207
self.compute_min_captures(closure_def_id, capture_clause, capture_information);
204208
}
205209

210+
let before_feature_tys = self.final_upvar_tys(closure_def_id);
211+
206212
if let Some(closure_substs) = infer_kind {
207213
// Unify the (as yet unbound) type variable in the closure
208214
// substs with the kind we inferred.
@@ -258,6 +264,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
258264
.collect();
259265
self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads);
260266

267+
if self.tcx.sess.opts.debugging_opts.profile_closures {
268+
self.typeck_results.borrow_mut().closure_size_eval.insert(
269+
closure_def_id,
270+
ClosureSizeProfileData {
271+
before_feature_tys: self.tcx.mk_tup(before_feature_tys.into_iter()),
272+
after_feature_tys: self.tcx.mk_tup(after_feature_tys.into_iter()),
273+
},
274+
);
275+
}
276+
261277
// If we are also inferred the closure kind here,
262278
// process any deferred resolutions.
263279
let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);

compiler/rustc_typeck/src/check/writeback.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::hir::place::Place as HirPlace;
1515
use rustc_middle::mir::FakeReadCause;
1616
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
1717
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
18-
use rustc_middle::ty::{self, Ty, TyCtxt};
18+
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
1919
use rustc_span::symbol::sym;
2020
use rustc_span::Span;
2121
use rustc_trait_selection::opaque_types::InferCtxtExt;
@@ -60,6 +60,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
6060
}
6161
wbcx.visit_body(body);
6262
wbcx.visit_min_capture_map();
63+
wbcx.eval_closure_size();
6364
wbcx.visit_fake_reads_map();
6465
wbcx.visit_closures();
6566
wbcx.visit_liberated_fn_sigs();
@@ -333,6 +334,19 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
333334
}
334335

335336
impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
337+
fn eval_closure_size(&mut self) {
338+
let mut res: FxHashMap<DefId, ClosureSizeProfileData<'tcx>> = Default::default();
339+
for (closure_def_id, data) in self.fcx.typeck_results.borrow().closure_size_eval.iter() {
340+
let closure_hir_id =
341+
self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local());
342+
343+
let data = self.resolve(*data, &closure_hir_id);
344+
345+
res.insert(*closure_def_id, data);
346+
}
347+
348+
self.typeck_results.closure_size_eval = res;
349+
}
336350
fn visit_min_capture_map(&mut self) {
337351
let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher(
338352
self.fcx.typeck_results.borrow().closure_min_captures.len(),

0 commit comments

Comments
 (0)