From a61cc2c5439f9f41585d8eb455f5f36af269f7b0 Mon Sep 17 00:00:00 2001 From: Matthew Pickering Date: Wed, 21 Jul 2021 10:03:42 +0100 Subject: Stop ug_boring_info retaining a chain of old CoreExpr It was noticed in #20134 that each simplifier iteration used an increasing amount of memory and that a certain portion of memory was not released until the simplfier had completely finished. I profiled the program using `-hi` profiling and observed that there was a thunk arising in the computation of `ug_boring_ok`. On each iteration `ug_boring_ok` would be updated, but not forced, which would leave a thunk in the shape of ug_boring_ok = inlineBoringOk expr0 || inlineBoringOk expr2 || inlineBoringOk expr3 || ... which would retain all previous `expr` until `ug_boring_ok` was forced or discarded. Forcing this accumulator eagerly results in a flat profile over multiple simplifier runs. This reduces the maximum residency when compiling the test in #20134 from 2GB to 1.3G. ------------------------- Metric Decrease: T11545 ------------------------- --- compiler/GHC/Core/Opt/Simplify.hs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/compiler/GHC/Core/Opt/Simplify.hs b/compiler/GHC/Core/Opt/Simplify.hs index 1bbb728de6..1cecda63b2 100644 --- a/compiler/GHC/Core/Opt/Simplify.hs +++ b/compiler/GHC/Core/Opt/Simplify.hs @@ -4003,8 +4003,7 @@ simplLetUnfolding env top_lvl cont_mb id new_rhs rhs_ty arity unf mkLetUnfolding :: UnfoldingOpts -> TopLevelFlag -> UnfoldingSource -> InId -> OutExpr -> SimplM Unfolding mkLetUnfolding !uf_opts top_lvl src id new_rhs - = is_bottoming `seq` -- See Note [Force bottoming field] - return (mkUnfolding uf_opts src is_top_lvl is_bottoming new_rhs) + = return (mkUnfolding uf_opts src is_top_lvl is_bottoming new_rhs) -- We make an unfolding *even for loop-breakers*. -- Reason: (a) It might be useful to know that they are WHNF -- (b) In GHC.Iface.Tidy we currently assume that, if we want to @@ -4012,8 +4011,11 @@ mkLetUnfolding !uf_opts top_lvl src id new_rhs -- to expose. (We could instead use the RHS, but currently -- we don't.) The simple thing is always to have one. where - is_top_lvl = isTopLevel top_lvl - is_bottoming = isDeadEndId id + -- Might as well force this, profiles indicate up to 0.5MB of thunks + -- just from this site. + !is_top_lvl = isTopLevel top_lvl + -- See Note [Force bottoming field] + !is_bottoming = isDeadEndId id ------------------- simplStableUnfolding :: SimplEnv -> TopLevelFlag @@ -4050,11 +4052,17 @@ simplStableUnfolding env top_lvl mb_cont id rhs_ty id_arity unf , ug_boring_ok = boring_ok } -- Happens for INLINE things - -> let guide' = + -- Really important to force new_boring_ok as otherwise + -- `ug_boring_ok` is a thunk chain of + -- inlineBoringExprOk expr0 + -- || inlineBoringExprOk expr1 || ... + -- See #20134 + -> let !new_boring_ok = boring_ok || inlineBoringOk expr' + guide' = UnfWhen { ug_arity = arity , ug_unsat_ok = sat_ok - , ug_boring_ok = - boring_ok || inlineBoringOk expr' + , ug_boring_ok = new_boring_ok + } -- Refresh the boring-ok flag, in case expr' -- has got small. This happens, notably in the inlinings @@ -4075,7 +4083,9 @@ simplStableUnfolding env top_lvl mb_cont id rhs_ty id_arity unf | otherwise -> return noUnfolding -- Discard unstable unfoldings where uf_opts = seUnfoldingOpts env - is_top_lvl = isTopLevel top_lvl + -- Forcing this can save about 0.5MB of max residency and the result + -- is small and easy to compute so might as well force it. + !is_top_lvl = isTopLevel top_lvl act = idInlineActivation id unf_env = updMode (updModeForStableUnfoldings act) env -- See Note [Simplifying inside stable unfoldings] in GHC.Core.Opt.Simplify.Utils @@ -4216,3 +4226,4 @@ for the RHS as well as the LHS, but that seems more conservative than necesary. Allowing some inlining might, for example, eliminate a binding. -} + -- cgit v1.2.1