[GHC] #11222: Teach strictness analysis about `catch`-like operations
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: feature | Status: new request | Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.10.3 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: Runtime Unknown/Multiple | performance bug Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- Consider the `catch#` primop, {{{#!hs catch# :: (State# RealWorld -> (# State# RealWorld, a #) ) -- ^ thing to catch exceptions from -> (b -> State# RealWorld -> (# State# RealWorld, a #) ) -- ^ exception handler -> State# RealWorld -> (# State# RealWorld, a #) }}} Semantically, this operation will always evaluate its first argument. Ideally we would indicate this in the primop's strictness signature in `primops.txt.pp`. Sadly, we can't do this at the moment due to a subtle wrinkle (discovered in #10712): Consider, {{{#!hs let r = \st -> raiseIO# blah st in catch (\st -> ...(r st)..) handler st }}} If we give the first argument of catch a strict signature, we'll get a demand `C(S)` for `r`; that is, `r` is definitely called with one argument, which indeed it is. The trouble comes when we feed `C(S)` into `r`'s RHS as the demand of the body as this will lead us to conclude that the whole `let` will diverge; clearly this isn't right. As Simon noted in ticket:10712#comment:4,
There's something very special about catch: it turns divergence into non-divergence.
In order to apply a proper strictness signature to `catch`-like operations we would need to teach the strictness analyzer about this property. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by Ben Gamari <ben@…>): In [changeset:"28638dfe79e915f33d75a1b22c5adce9e2b62b97/ghc" 28638df/ghc]: {{{ #!CommitTicketReference repository="ghc" revision="28638dfe79e915f33d75a1b22c5adce9e2b62b97" primops: Mark actions evaluated by `catch*` as lazy There is something very peculiar about the `catch` family of operations with respect to strictness analysis: they turn divergence into non-divergence. For this reason, it isn't safe to mark them as strict in the expression whose exceptions they are catching. The reason is this: Consider, let r = \st -> raiseIO# blah st in catch (\st -> ...(r st)..) handler st If we give the first argument of catch a strict signature, we'll get a demand 'C(S)' for 'r'; that is, 'r' is definitely called with one argument, which indeed it is. The trouble comes when we feed 'C(S)' into 'r's RHS as the demand of the body as this will lead us to conclude that the whole 'let' will diverge; clearly this isn't right. This is essentially the problem in #10712, which arose when 7c0fff41789669450b02dc1db7f5d7babba5dee6 marked the `catch*` primops as being strict in the thing to be evaluated. Here I've partially reverted this commit, again marking the first argument of these primops as lazy. Fixes #10712. Test Plan: Validate checking `exceptionsrun001` Reviewers: simonpj, austin Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1616 GHC Trac Issues: #10712, #11222 }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:1> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by simonmar): * cc: simonmar (added) -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:2> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by Simon Peyton Jones <simonpj@…>): In [changeset:"9915b6564403a6d17651e9969e9ea5d7d7e78e7f/ghc" 9915b656/ghc]: {{{ #!CommitTicketReference repository="ghc" revision="9915b6564403a6d17651e9969e9ea5d7d7e78e7f" Make demand analysis understand catch As Trac #11222, and #10712 note, the strictness analyser needs to be rather careful about exceptions. Previously it treated them as identical to divergence, but that won't quite do. See Note [Exceptions and strictness] in Demand, which explains the deal. Getting more strictness in 'catch' and friends is a very good thing. Here is the nofib summary, keeping only the big ones. -------------------------------------------------------------------------------- Program Size Allocs Runtime Elapsed TotalMem -------------------------------------------------------------------------------- fasta -0.1% -6.9% -3.0% -3.0% +0.0% hpg -0.1% -2.0% -6.2% -6.2% +0.0% maillist -0.1% -0.3% 0.08 0.09 +1.2% reverse-complem -0.1% -10.9% -6.0% -5.9% +0.0% sphere -0.1% -4.3% 0.08 0.08 +0.0% x2n1 -0.1% -0.0% 0.00 0.00 +0.0% -------------------------------------------------------------------------------- Min -0.2% -10.9% -17.4% -17.3% +0.0% Max -0.0% +0.0% +4.3% +4.4% +1.2% Geometric Mean -0.1% -0.3% -2.9% -3.0% +0.0% On the way I did quite a bit of refactoring in Demand.hs }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:3> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: Type: feature request | Status: closed Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.10.3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by simonpj): * status: new => closed * resolution: => fixed Comment: Done! -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:4> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: feature request | Status: closed Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.10.3 Resolution: fixed | Keywords: Exceptions Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by simonpj): * keywords: => Exceptions -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:5> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Exceptions Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by dfeuer): * status: closed => new * resolution: fixed => Comment: This was semantically shady and has been partially reverted. We would like to find a way to recover some of the benefits without the downsides. One strong possibility is to add a `catchIO#` primop that only catches exceptions thrown by `raiseIO#`. Such a primop could be handled more aggressively. See https://ghc.haskell.org/trac/ghc/wiki/Exceptions/PreciseExceptions. Another direction would be to treat `catch#` forms specially in strictness analysis, somewhat like `case` expressions. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:6> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: dfeuer Type: feature request | Status: new Priority: normal | Milestone: 8.2.1 Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Exceptions Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by dfeuer): * owner: (none) => dfeuer -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:7> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: dfeuer Type: feature request | Status: new Priority: normal | Milestone: 8.4.1 Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Exceptions Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by dfeuer): * milestone: 8.2.1 => 8.4.1 -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:8> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: dfeuer Type: feature request | Status: new Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Exceptions Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by Ben Gamari <ben@…>): In [changeset:"00b8ecb78624511a045120673b01fafe5794ecdc/ghc" 00b8ecb7/ghc]: {{{ #!CommitTicketReference repository="ghc" revision="00b8ecb78624511a045120673b01fafe5794ecdc" Declare `catchRetry#` lazy in its first argument As per the results on item 1 in T14998, declaring `catchRetry#` lazy in its first argument opens the possibility to remove `ExnStr` complexity from strictness demands at virtually no regressions in NoFib. This brings `catchRetry#` in line with other primops from the `catch*` family. Reviewers: bgamari, simonpj, nomeata Reviewed By: bgamari Subscribers: thomie, carter GHC Trac Issues: #14998, #11222 Differential Revision: https://phabricator.haskell.org/D4573 }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:10> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: dfeuer Type: feature request | Status: new Priority: normal | Milestone: 8.10.1 Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Exceptions Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: #10712, #14998 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by sgraf): * related: => #10712, #14998 -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:13> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: dfeuer Type: feature request | Status: new Priority: normal | Milestone: 8.10.1 Component: Compiler | Version: 7.10.3 Resolution: | Keywords: Exceptions Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: #10712, #14998 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by sgraf): #14998 suggests that we have the performance gains without actually making `catch#` and `catchRetry#` any more special than necessary. I think we can close this? -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:14> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#11222: Teach strictness analysis about `catch`-like operations -------------------------------------+------------------------------------- Reporter: bgamari | Owner: dfeuer Type: feature request | Status: closed Priority: normal | Milestone: 8.10.1 Component: Compiler | Version: 7.10.3 Resolution: wontfix | Keywords: Exceptions Operating System: Unknown/Multiple | Architecture: Type of failure: Runtime | Unknown/Multiple performance bug | Test Case: Blocked By: | Blocking: Related Tickets: #10712, #14998 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by simonpj): * status: new => closed * resolution: => wontfix Comment:
I think we can close this?
Yes I think so. -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/11222#comment:15> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
participants (1)
-
GHC