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

[nll] optimize tuple-stress benchmark by skipping visit of types that do not have regions #52027

Closed
nikomatsakis opened this Issue Jul 3, 2018 · 1 comment

Comments

Projects
None yet
3 participants
@nikomatsakis
Copy link
Contributor

nikomatsakis commented Jul 3, 2018

The tuple-stress benchmark appears to be ridiculously slow with NLL. Profiling suggests that the majority of costs come from the liveness constraint generation code:

pub(super) fn generate<'gcx, 'tcx>(
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
mir: &Mir<'tcx>,
liveness: &LivenessResults,
flow_inits: &mut FlowAtLocation<MaybeInitializedPlaces<'_, 'gcx, 'tcx>>,
move_data: &MoveData<'tcx>,
) {

Specifically, the vast majority of samples (50%) occur in the push_type_live_constraint function:

fn push_type_live_constraint<T>(
cx: &mut TypeChecker<'_, 'gcx, 'tcx>,
value: T,
location: Location,
) where
T: TypeFoldable<'tcx>,

This function primarily consists of a walk over all the free regions within a type:

cx.tcx().for_each_free_region(&value, |live_region| {
cx.constraints.liveness_set.push((live_region, location));
});

However, the types in question don't really involve regions (they are things like (u32, f64, u32) etc). It turns out that we have a "flags" mechanism that tracks the content of types, designed for just such a purpose. This should allow us to quickly skip. The flags are defined here, using the bitflags! macro:

rust/src/librustc/ty/mod.rs

Lines 418 to 419 in 860d169

bitflags! {
pub struct TypeFlags: u32 {

The flag we are interested in HAS_FREE_REGIONS:

rust/src/librustc/ty/mod.rs

Lines 432 to 434 in 860d169

/// Does this have any region that "appears free" in the type?
/// Basically anything but `ReLateBound` and `ReErased`.
const HAS_FREE_REGIONS = 1 << 6;

We should be able to optimize the for_each_free_region to consult this flag and quickly skip past types that do not contain any regions. for_each_free_region is defined here:

pub fn for_each_free_region<T,F>(self,
value: &T,
callback: F)
where F: FnMut(ty::Region<'tcx>),
T: TypeFoldable<'tcx>,

It uses a "type visitor" to do its work:

impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F>
where F : FnMut(ty::Region<'tcx>)

we want to add callback for the case of visiting types which will check this flag. Something like the following ought to do it:

fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
  if ty.flags.intersects(HAS_FREE_REGIONS) {
    self.super_ty(ty)
  } else {
    false // keep visiting
  }
}

@nikomatsakis nikomatsakis changed the title [nll] optimize tuple-stress benchmark [nll] optimize tuple-stress benchmark by skipping visit of types that do not have regions Jul 3, 2018

@nikomatsakis nikomatsakis added this to the Rust 2018 Preview 2 milestone Jul 3, 2018

@lqd lqd self-assigned this Jul 3, 2018

@nnethercote

This comment has been minimized.

Copy link
Contributor

nnethercote commented Jul 3, 2018

FWIW, I think the first code snippet in the above description should be this:

self.liveness
.regular
.simulate_block(self.mir, bb, |location, live_locals| {
for live_local in live_locals.iter() {
let live_local_ty = self.mir.local_decls[live_local].ty;
Self::push_type_live_constraint(&mut self.cx, live_local_ty, location);
}
});

bors added a commit that referenced this issue Jul 4, 2018

Auto merge of #52037 - lqd:skipping-regionless-types, r=<try>
NLL Liveness: Skip regionless types when visiting free regions

The tuple-stress benchmark exercises the liveness constraint generation code for types which do not have regions

Closes #52027

bors added a commit that referenced this issue Jul 7, 2018

Auto merge of #52037 - lqd:skipping-regionless-types, r=nikomatsakis
NLL Liveness: Skip regionless types when visiting free regions

The tuple-stress benchmark exercises the liveness constraint generation code for types which do not have regions

Closes #52027

@bors bors closed this in #52037 Jul 7, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.