Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce -Zprofile-closures to evaluate the impact of 2229 #86695

Merged
merged 1 commit into from
Jun 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,7 @@ fn test_debugging_options_tracking_hash() {
untracked!(perf_stats, true);
// `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!(profile_closures, true);
untracked!(print_link_args, true);
untracked!(print_llvm_passes, true);
untracked!(print_mono_items, Some(String::from("abc")));
Expand Down
18 changes: 13 additions & 5 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ use crate::ty::query::{self, OnDiskCache, TyCtxtAt};
use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts};
use crate::ty::TyKind::*;
use crate::ty::{
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
DefIdTree, ExistentialPredicate, FloatTy, FloatVar, FloatVid, GenericParamDefKind, InferConst,
InferTy, IntTy, IntVar, IntVid, List, MainDefinition, ParamConst, ParamTy, PolyFnSig,
Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind, ReprOptions,
TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
ClosureSizeProfileData, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar,
FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
MainDefinition, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
TyVid, TypeAndMut, UintTy, Visibility,
};
use rustc_ast as ast;
use rustc_ast::expand::allocator::AllocatorKind;
Expand Down Expand Up @@ -484,6 +485,10 @@ pub struct TypeckResults<'tcx> {
/// This hashset records all instances where we behave
/// like this to allow `const_to_pat` to reliably handle this situation.
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> {
Expand All @@ -510,6 +515,7 @@ impl<'tcx> TypeckResults<'tcx> {
closure_fake_reads: Default::default(),
generator_interior_types: ty::Binder::dummy(Default::default()),
treat_byte_string_as_slice: Default::default(),
closure_size_eval: Default::default(),
}
}

Expand Down Expand Up @@ -754,6 +760,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
ref closure_fake_reads,
ref generator_interior_types,
ref treat_byte_string_as_slice,
ref closure_size_eval,
} = *self;

hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
Expand All @@ -780,6 +787,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TypeckResults<'tcx> {
closure_fake_reads.hash_stable(hcx, hasher);
generator_interior_types.hash_stable(hcx, hasher);
treat_byte_string_as_slice.hash_stable(hcx, hasher);
closure_size_eval.hash_stable(hcx, hasher);
})
}
}
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,25 @@ pub enum Visibility {
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 {
fn parent(self, id: DefId) -> Option<DefId>;

Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_mir/src/monomorphize/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,13 @@ fn create_fn_mono_item<'tcx>(
source: Span,
) -> Spanned<MonoItem<'tcx>> {
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)))
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_mir/src/monomorphize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use rustc_hir::lang_items::LangItem;
pub mod collector;
pub mod partitioning;
pub mod polymorphize;
pub mod util;

fn custom_coerce_unsize_info<'tcx>(
tcx: TyCtxt<'tcx>,
Expand Down
73 changes: 73 additions & 0 deletions compiler/rustc_mir/src/monomorphize/util.rs
Original file line number Diff line number Diff line change
@@ -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())
}
}
}
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,8 @@ options! {
"show backtraces for panics during proc-macro execution (default: no)"),
profile: bool = (false, parse_bool, [TRACKED],
"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],
"file path to emit profiling data at runtime when using 'profile' \
(default based on relative source path)"),
Expand Down
18 changes: 17 additions & 1 deletion compiler/rustc_typeck/src/check/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
use rustc_infer::infer::UpvarRegion;
use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
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_span::sym;
use rustc_span::{MultiSpan, Span, Symbol};
Expand Down Expand Up @@ -175,6 +177,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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 do this after handling migrations so that min_captures computes before
if !enable_precise_capture(self.tcx, span) {
Expand Down Expand Up @@ -203,6 +207,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
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 {
// Unify the (as yet unbound) type variable in the closure
// substs with the kind we inferred.
Expand Down Expand Up @@ -258,6 +264,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.collect();
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,
// process any deferred resolutions.
let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id);
Expand Down
16 changes: 15 additions & 1 deletion compiler/rustc_typeck/src/check/writeback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
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::Span;
use rustc_trait_selection::opaque_types::InferCtxtExt;
Expand Down Expand Up @@ -60,6 +60,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
wbcx.visit_body(body);
wbcx.visit_min_capture_map();
wbcx.eval_closure_size();
wbcx.visit_fake_reads_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
Expand Down Expand Up @@ -333,6 +334,19 @@ impl<'cx, 'tcx> Visitor<'tcx> for 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) {
let mut min_captures_wb = ty::MinCaptureInformationMap::with_capacity_and_hasher(
self.fcx.typeck_results.borrow().closure_min_captures.len(),
Expand Down