Change:
It's not clear yet whether mir interpretation is the culprit or some changes that crept into the same PR. Perf data: cc [ ] tuple-stress max: 109.4% clean-incremental is a 100% hit! The rest are small. [ ] tuple-stress-opt max: 109.1% same, clean-incremental is a 100% hit! [ ] encoding-opt max: 97.6% clean incremental-opt patched incremental: println-opt [ ] encoding max: 94.9% clean is ~ 20%, as is baseline incremental incremental cases are almost 100% [ ] coercions-opt max: 74.6% pretty universally bad, though incremental hurts worse [ ] coercions max: 66.6% pretty universally bad, though incremental hurts worse [ ] html5ever-opt max: 41.3% incremental [ ] inflate max: 40.4% universally bad, though incremental hurts worse [ ] regex-opt max: 4.7% patched incremental: byte frequencies-opt [ ] script-servo-opt max: 12.1% clean incremental-opt [ ] script-servo max: 11.6% clean incremental [ ] inflate-opt max: 11.6% incremental cases primarily
I'm going to start with ...
It would be good to dig into those use cases -- in particular, if you open them, we can see which of them are incremental use cases and which are not.
I just updated the tracking issue with that information. Most of them are incremental cases.
OK, for it's pretty clear: 58% of the execution time are spent in called from . Does that ring a bell, I haven't had time yet to really look at the code in question.
We might simply be encoding more constants now (that were previously encoded as HIR). I'll have to look at the exact logs (rustcmir::interpret::consteval=debug to just get the entry points). I'll check tomorrow morning
Ok. I found the issue. We don't seem to be loading constants from the cache. So the enormous regressions are from recomputing all constants, even if nothing changed in the code at all. That should be easy enough to fix
Only the incremental regressions were fixed. I'll investigate the others, too New perf data:
There have been a lot of perf optimizations for const eval over the last year. I think we're good now

Discussion:
fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> String { format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id())) } <ins> #[inline] fn cache_on_disk(_key: Self::Key) -> bool { true } #[inline] fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option<Self::Value> { tcx.on_disk_query_result_cache.try_load_query_result(tcx, id).map(Ok) } </ins> } impl<'tcx> QueryDescription<'tcx> for queries::mir_keys<'tcx> {

// the driver creates (using several `rustc_*` crates). // // The result of query must implement Clone. They must also implement ty::maps::values::Value <del> // which produces an appropiate error value if the query resulted in a query cycle. </del> <ins> // which produces an appropriate error value if the query resulted in a query cycle. </ins> // Queries marked with `fatal_cycle` do not need that implementation // as they will raise an fatal error on query cycles instead. define_maps! { <'tcx>

encode_query_results::<symbol_name, _>(tcx, enc, qri)?; encode_query_results::<check_match, _>(tcx, enc, qri)?; encode_query_results::<trans_fn_attrs, _>(tcx, enc, qri)?; <ins> // const eval is special, it only encodes successfully evaluated constants use ty::maps::plumbing::GetCacheInternal; for (key, entry) in const_eval::get_cache_internal(tcx).map.iter() { use ty::maps::config::QueryDescription; if const_eval::cache_on_disk(key.clone()) { if let Ok(ref value) = entry.value { let dep_node = SerializedDepNodeIndex::new(entry.index.index()); // Record position of the cache entry qri.push((dep_node, AbsoluteBytePos::new(enc.position()))); // Encode the type check tables with the SerializedDepNodeIndex // as tag. enc.encode_tagged(dep_node, value)?; } } } </ins> } // Encode diagnostics

tcx.interpret_interner.intern_at_reserved(alloc_id, allocation); if let Some(glob) = Option::<DefId>::decode(self)? { <ins> trace!("connecting alloc {:?} with {:?}", alloc_id, glob); </ins> tcx.interpret_interner.cache(glob, alloc_id); }

span = mir.span; let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); <ins> let is_static = tcx.is_static(cid.instance.def_id()).is_some(); </ins> let alloc = match alloc { Some(alloc) => { assert!(cid.promoted.is_none());

layout.align, None, )?; <del> if tcx.is_static(cid.instance.def_id()).is_some() { </del> <ins> if is_static { </ins> tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); } let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span);

} }; let ptr = MemoryPointer::new(alloc, 0).into(); <ins> // always try to read the value and report errors </ins> let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { <del> Some(val) => val, </del> <ins> // if it's a constant (so it needs no address, directly compute its value) Some(val) if !is_static => val, // point at the allocation </ins> _ => Value::ByRef(ptr, layout.align), }; Ok((value, ptr, layout.ty))