mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 00:03:43 +00:00
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`
This commit is contained in:
commit
868c702d0c
@ -654,6 +654,7 @@ fn test_debugging_options_tracking_hash() {
|
|||||||
untracked!(perf_stats, true);
|
untracked!(perf_stats, true);
|
||||||
// `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
|
// `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
|
||||||
untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
|
untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
|
||||||
|
untracked!(profile_closures, true);
|
||||||
untracked!(print_link_args, true);
|
untracked!(print_link_args, true);
|
||||||
untracked!(print_llvm_passes, true);
|
untracked!(print_llvm_passes, true);
|
||||||
untracked!(print_mono_items, Some(String::from("abc")));
|
untracked!(print_mono_items, Some(String::from("abc")));
|
||||||
|
@ -19,11 +19,12 @@ use crate::ty::query::{self, OnDiskCache, TyCtxtAt};
|
|||||||
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
|
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
|
||||||
use crate::ty::TyKind::*;
|
use crate::ty::TyKind::*;
|
||||||
use crate::ty::{
|
use crate::ty::{
|
||||||
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
|
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
|
||||||
DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
|
ClosureSizeProfileData, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar,
|
||||||
InferTy, IntTy, IntVar, IntVid, List, MainDefinition, ParamConst, ParamTy, PolyFnSig,
|
FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
|
||||||
Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
|
MainDefinition, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
|
||||||
TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
|
ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
|
||||||
|
TyVid, TypeAndMut, UintTy, Visibility,
|
||||||
};
|
};
|
||||||
use rustc_ast as ast;
|
use rustc_ast as ast;
|
||||||
use rustc_attr as attr;
|
use rustc_attr as attr;
|
||||||
@ -483,6 +484,10 @@ pub struct TypeckResults<'tcx> {
|
|||||||
/// This hashset records all instances where we behave
|
/// This hashset records all instances where we behave
|
||||||
/// like this to allow `const_to_pat` to reliably handle this situation.
|
/// like this to allow `const_to_pat` to reliably handle this situation.
|
||||||
pub treat_byte_string_as_slice: ItemLocalSet,
|
pub treat_byte_string_as_slice: ItemLocalSet,
|
||||||
|
|
||||||
|
/// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
|
||||||
|
/// on closure size.
|
||||||
|
pub closure_size_eval: FxHashMap<DefId, ClosureSizeProfileData<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> TypeckResults<'tcx> {
|
impl<'tcx> TypeckResults<'tcx> {
|
||||||
@ -509,6 +514,7 @@ impl<'tcx> TypeckResults<'tcx> {
|
|||||||
closure_fake_reads: Default::default(),
|
closure_fake_reads: Default::default(),
|
||||||
generator_interior_types: ty::Binder::dummy(Default::default()),
|
generator_interior_types: ty::Binder::dummy(Default::default()),
|
||||||
treat_byte_string_as_slice: Default::default(),
|
treat_byte_string_as_slice: Default::default(),
|
||||||
|
closure_size_eval: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -753,6 +759,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
|
|||||||
ref closure_fake_reads,
|
ref closure_fake_reads,
|
||||||
ref generator_interior_types,
|
ref generator_interior_types,
|
||||||
ref treat_byte_string_as_slice,
|
ref treat_byte_string_as_slice,
|
||||||
|
ref closure_size_eval,
|
||||||
} = *self;
|
} = *self;
|
||||||
|
|
||||||
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
|
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
|
||||||
@ -779,6 +786,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
|
|||||||
closure_fake_reads.hash_stable(hcx, hasher);
|
closure_fake_reads.hash_stable(hcx, hasher);
|
||||||
generator_interior_types.hash_stable(hcx, hasher);
|
generator_interior_types.hash_stable(hcx, hasher);
|
||||||
treat_byte_string_as_slice.hash_stable(hcx, hasher);
|
treat_byte_string_as_slice.hash_stable(hcx, hasher);
|
||||||
|
closure_size_eval.hash_stable(hcx, hasher);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,25 @@ pub enum Visibility {
|
|||||||
Invisible,
|
Invisible,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Clone,
|
||||||
|
Debug,
|
||||||
|
PartialEq,
|
||||||
|
Eq,
|
||||||
|
Copy,
|
||||||
|
Hash,
|
||||||
|
TyEncodable,
|
||||||
|
TyDecodable,
|
||||||
|
HashStable,
|
||||||
|
TypeFoldable
|
||||||
|
)]
|
||||||
|
pub struct ClosureSizeProfileData<'tcx> {
|
||||||
|
/// Tuple containing the types of closure captures before the feature `capture_disjoint_fields`
|
||||||
|
pub before_feature_tys: Ty<'tcx>,
|
||||||
|
/// Tuple containing the types of closure captures after the feature `capture_disjoint_fields`
|
||||||
|
pub after_feature_tys: Ty<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait DefIdTree: Copy {
|
pub trait DefIdTree: Copy {
|
||||||
fn parent(self, id: DefId) -> Option<DefId>;
|
fn parent(self, id: DefId) -> Option<DefId>;
|
||||||
|
|
||||||
|
@ -1071,6 +1071,13 @@ fn create_fn_mono_item<'tcx>(
|
|||||||
source: Span,
|
source: Span,
|
||||||
) -> Spanned<MonoItem<'tcx>> {
|
) -> Spanned<MonoItem<'tcx>> {
|
||||||
debug!("create_fn_mono_item(instance={})", instance);
|
debug!("create_fn_mono_item(instance={})", instance);
|
||||||
|
|
||||||
|
let def_id = instance.def_id();
|
||||||
|
if tcx.sess.opts.debugging_opts.profile_closures && def_id.is_local() && tcx.is_closure(def_id)
|
||||||
|
{
|
||||||
|
monomorphize::util::dump_closure_profile(tcx, instance);
|
||||||
|
}
|
||||||
|
|
||||||
respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
|
respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ use rustc_hir::lang_items::LangItem;
|
|||||||
pub mod collector;
|
pub mod collector;
|
||||||
pub mod partitioning;
|
pub mod partitioning;
|
||||||
pub mod polymorphize;
|
pub mod polymorphize;
|
||||||
|
pub mod util;
|
||||||
|
|
||||||
fn custom_coerce_unsize_info<'tcx>(
|
fn custom_coerce_unsize_info<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
73
compiler/rustc_mir/src/monomorphize/util.rs
Normal file
73
compiler/rustc_mir/src/monomorphize/util.rs
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
use rustc_middle::ty::{self, ClosureSizeProfileData, Instance, TyCtxt};
|
||||||
|
use std::fs::OpenOptions;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
|
||||||
|
/// For a given closure, writes out the data for the profiling the impact of RFC 2229 on
|
||||||
|
/// closure size into a CSV.
|
||||||
|
///
|
||||||
|
/// During the same compile all closures dump the information in the same file
|
||||||
|
/// "closure_profile_XXXXX.csv", which is created in the directory where the compiler is invoked.
|
||||||
|
crate fn dump_closure_profile(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) {
|
||||||
|
let mut file = if let Ok(file) = OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.open(&format!("closure_profile_{}.csv", std::process::id()))
|
||||||
|
{
|
||||||
|
file
|
||||||
|
} else {
|
||||||
|
eprintln!("Cound't open file for writing closure profile");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let closure_def_id = closure_instance.def_id();
|
||||||
|
let typeck_results = tcx.typeck(closure_def_id.expect_local());
|
||||||
|
|
||||||
|
if typeck_results.closure_size_eval.contains_key(&closure_def_id) {
|
||||||
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
|
|
||||||
|
let ClosureSizeProfileData { before_feature_tys, after_feature_tys } =
|
||||||
|
typeck_results.closure_size_eval[&closure_def_id];
|
||||||
|
|
||||||
|
let before_feature_tys = tcx.subst_and_normalize_erasing_regions(
|
||||||
|
closure_instance.substs,
|
||||||
|
param_env,
|
||||||
|
before_feature_tys,
|
||||||
|
);
|
||||||
|
let after_feature_tys = tcx.subst_and_normalize_erasing_regions(
|
||||||
|
closure_instance.substs,
|
||||||
|
param_env,
|
||||||
|
after_feature_tys,
|
||||||
|
);
|
||||||
|
|
||||||
|
let new_size = tcx
|
||||||
|
.layout_of(param_env.and(after_feature_tys))
|
||||||
|
.map(|l| format!("{:?}", l.size.bytes()))
|
||||||
|
.unwrap_or_else(|e| format!("Failed {:?}", e));
|
||||||
|
|
||||||
|
let old_size = tcx
|
||||||
|
.layout_of(param_env.and(before_feature_tys))
|
||||||
|
.map(|l| format!("{:?}", l.size.bytes()))
|
||||||
|
.unwrap_or_else(|e| format!("Failed {:?}", e));
|
||||||
|
|
||||||
|
let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
|
||||||
|
let closure_span = tcx.hir().span(closure_hir_id);
|
||||||
|
let src_file = tcx.sess.source_map().span_to_filename(closure_span);
|
||||||
|
let line_nos = tcx
|
||||||
|
.sess
|
||||||
|
.source_map()
|
||||||
|
.span_to_lines(closure_span)
|
||||||
|
.map(|l| format!("{:?} {:?}", l.lines.first(), l.lines.last()))
|
||||||
|
.unwrap_or_else(|e| format!("{:?}", e));
|
||||||
|
|
||||||
|
if let Err(e) = writeln!(
|
||||||
|
file,
|
||||||
|
"{}, {}, {}, {:?}",
|
||||||
|
old_size,
|
||||||
|
new_size,
|
||||||
|
src_file.prefer_local(),
|
||||||
|
line_nos
|
||||||
|
) {
|
||||||
|
eprintln!("Error writting to file {}", e.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1209,6 +1209,8 @@ options! {
|
|||||||
"show backtraces for panics during proc-macro execution (default: no)"),
|
"show backtraces for panics during proc-macro execution (default: no)"),
|
||||||
profile: bool = (false, parse_bool, [TRACKED],
|
profile: bool = (false, parse_bool, [TRACKED],
|
||||||
"insert profiling code (default: no)"),
|
"insert profiling code (default: no)"),
|
||||||
|
profile_closures: bool = (false, parse_no_flag, [UNTRACKED],
|
||||||
|
"profile size of closures"),
|
||||||
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
profile_emit: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
|
||||||
"file path to emit profiling data at runtime when using 'profile' \
|
"file path to emit profiling data at runtime when using 'profile' \
|
||||||
(default based on relative source path)"),
|
(default based on relative source path)"),
|
||||||
|
@ -42,7 +42,9 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
|||||||
use rustc_infer::infer::UpvarRegion;
|
use rustc_infer::infer::UpvarRegion;
|
||||||
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
|
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
|
||||||
use rustc_middle::mir::FakeReadCause;
|
use rustc_middle::mir::FakeReadCause;
|
||||||
use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeckResults, UpvarSubsts};
|
use rustc_middle::ty::{
|
||||||
|
self, ClosureSizeProfileData, TraitRef, Ty, TyCtxt, TypeckResults, UpvarSubsts,
|
||||||
|
};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
use rustc_span::{MultiSpan, Span, Symbol};
|
use rustc_span::{MultiSpan, Span, Symbol};
|
||||||
@ -175,6 +177,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.perform_2229_migration_anaysis(closure_def_id, body_id, capture_clause, span);
|
self.perform_2229_migration_anaysis(closure_def_id, body_id, capture_clause, span);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let after_feature_tys = self.final_upvar_tys(closure_def_id);
|
||||||
|
|
||||||
// We now fake capture information for all variables that are mentioned within the closure
|
// We now fake capture information for all variables that are mentioned within the closure
|
||||||
// We do this after handling migrations so that min_captures computes before
|
// We do this after handling migrations so that min_captures computes before
|
||||||
if !enable_precise_capture(self.tcx, span) {
|
if !enable_precise_capture(self.tcx, span) {
|
||||||
@ -203,6 +207,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
self.compute_min_captures(closure_def_id, capture_clause, capture_information);
|
self.compute_min_captures(closure_def_id, capture_clause, capture_information);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let before_feature_tys = self.final_upvar_tys(closure_def_id);
|
||||||
|
|
||||||
if let Some(closure_substs) = infer_kind {
|
if let Some(closure_substs) = infer_kind {
|
||||||
// Unify the (as yet unbound) type variable in the closure
|
// Unify the (as yet unbound) type variable in the closure
|
||||||
// substs with the kind we inferred.
|
// substs with the kind we inferred.
|
||||||
@ -258,6 +264,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
.collect();
|
.collect();
|
||||||
self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads);
|
self.typeck_results.borrow_mut().closure_fake_reads.insert(closure_def_id, fake_reads);
|
||||||
|
|
||||||
|
if self.tcx.sess.opts.debugging_opts.profile_closures {
|
||||||
|
self.typeck_results.borrow_mut().closure_size_eval.insert(
|
||||||
|
closure_def_id,
|
||||||
|
ClosureSizeProfileData {
|
||||||
|
before_feature_tys: self.tcx.mk_tup(before_feature_tys.into_iter()),
|
||||||
|
after_feature_tys: self.tcx.mk_tup(after_feature_tys.into_iter()),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// If we are also inferred the closure kind here,
|
// If we are also inferred the closure kind here,
|
||||||
// process any deferred resolutions.
|
// process any deferred resolutions.
|
||||||
let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
|
let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
|
||||||
|
@ -15,7 +15,7 @@ use rustc_middle::hir::place::Place as HirPlace;
|
|||||||
use rustc_middle::mir::FakeReadCause;
|
use rustc_middle::mir::FakeReadCause;
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
|
||||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_trait_selection::opaque_types::InferCtxtExt;
|
use rustc_trait_selection::opaque_types::InferCtxtExt;
|
||||||
@ -60,6 +60,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
wbcx.visit_body(body);
|
wbcx.visit_body(body);
|
||||||
wbcx.visit_min_capture_map();
|
wbcx.visit_min_capture_map();
|
||||||
|
wbcx.eval_closure_size();
|
||||||
wbcx.visit_fake_reads_map();
|
wbcx.visit_fake_reads_map();
|
||||||
wbcx.visit_closures();
|
wbcx.visit_closures();
|
||||||
wbcx.visit_liberated_fn_sigs();
|
wbcx.visit_liberated_fn_sigs();
|
||||||
@ -333,6 +334,19 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
|
||||||
|
fn eval_closure_size(&mut self) {
|
||||||
|
let mut res: FxHashMap<DefId, ClosureSizeProfileData<'tcx>> = Default::default();
|
||||||
|
for (closure_def_id, data) in self.fcx.typeck_results.borrow().closure_size_eval.iter() {
|
||||||
|
let closure_hir_id =
|
||||||
|
self.tcx().hir().local_def_id_to_hir_id(closure_def_id.expect_local());
|
||||||
|
|
||||||
|
let data = self.resolve(*data, &closure_hir_id);
|
||||||
|
|
||||||
|
res.insert(*closure_def_id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.typeck_results.closure_size_eval = res;
|
||||||
|
}
|
||||||
fn visit_min_capture_map(&mut self) {
|
fn visit_min_capture_map(&mut self) {
|
||||||
let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher(
|
let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher(
|
||||||
self.fcx.typeck_results.borrow().closure_min_captures.len(),
|
self.fcx.typeck_results.borrow().closure_min_captures.len(),
|
||||||
|
Loading…
Reference in New Issue
Block a user