[GHC] #14461: Reuse free variable lists through nested closures
GHC
ghc-devs at haskell.org
Fri Dec 1 13:19:01 UTC 2017
#14461: Reuse free variable lists through nested closures
-------------------------------------+-------------------------------------
Reporter: tdammers | Owner: alexbiehl
Type: task | Status: new
Priority: normal | Milestone:
Component: Compiler | Version: 8.2.1
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: | Blocking:
Related Tickets: 7258 | Differential Rev(s):
Wiki Page: NestedClosures |
-------------------------------------+-------------------------------------
Comment (by simonpj):
> Now, when forcing `outer` we push an update frame which overwrites
`outer`s closure to be an indirection to the resulting value hereby
turning the free variables effectively into garbage.
Ah! That's an excellent point, one that I had totally neglected.
Possibilities:
* Step 1. Don't do this for thunks. We have no data about what the
troublesome cases are, but the one case we do know about has functions.
* Step 2. Still don't do the this for thunks, but
{{{
let k1 = [fv1, ..., fvn] \ []
let k2 = [fv1, ..., fvn] \ [] -> ...
in ...
in ...
===>
let t = (fv1, ..., fvn) in
let k1 = [t{fv1, ..., fvn}] \ [] ->
let k2 = [t{fv1, ..., fvn}]] \ [] -> ...
in ...
in ...
}}}
NB: here I am allowing the `t{fv1,..,fvn}` as a way to access the free
vars of a data constructor, as well as a function closure. I don't think
this should be hard to arrange. And it might be useful anyway.
Now the shared bit is a separate tuple, which won't get updated.
One thing that would help would be some '''data''' on how common this kind
of thing is.
Even deciding what to measure is non-obvious. For example:
* For each STG let-binding
{{{
let x = [fv1..fvn] \ argsx -> ex
}}}
How often is it the case that there is an enclosing binding
{{{
let y = [gv1,...gvm] \ argsy -> ey
}}}
where the `[gv1,..gvm]` is a subset of `[fv1,..fvn]`? And what is the
distribution of savings?
By "enclosing" here, in the RHS of a let, I include the let-binding
itself, ''even if it is non-recursive''. All the examples above have this
form.
Some data along these lines would be extremely helpful in guiding what we
do.
Another variant: currently we insist that `[gv1,..gvm]` is a '''subset'''
of `[fv1,..fvn]`, to avoid space leaks. But with some RTS support we
could do better: the closure for `x` could point to the closure for `y`,
but ''also'' have a bitmap (in `x`'s info table) to say which of `y`'s
free vars are actually used by `x`. That would open up the possibility
for much more flexible sharing, at the cost of more bitmaps etc. E.g.
{{{
x = [fv1,...fv100] \ [a] ->
let y = [fv1,...fv99, a] \ [] -> ...
in ...
}}}
Here `y` needs all but one of `x`'s free vars. Data on how often this
happens would be would be jolly useful.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14461#comment:10>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list