[GHC] #9781: Make list monad operations fuse

#9781: Make list monad operations fuse -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: dfeuer Type: task | Status: new Priority: normal | Milestone: 7.10.1 Component: Core Libraries | Version: 7.9 Keywords: | Operating System: Architecture: Unknown/Multiple | Unknown/Multiple Difficulty: Unknown | Type of failure: Runtime Blocked By: | performance bug Related Tickets: | Test Case: | Blocking: | Differential Revisions: Phab:D455 -------------------------------------+------------------------------------- We like to think that `do {x <- xs; y <- f x ; return g y}` is the same as `[g y | x <- xs, y <- f x]`, but the former does not fuse nearly as well. Let's fix that. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9781 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9781: Make list monad operations fuse -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: dfeuer Type: task | Status: new Priority: normal | Milestone: 7.10.1 Component: Core | Version: 7.9 Libraries | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: Runtime | Related Tickets: performance bug | Test Case: | Blocking: | Differential Revisions: Phab:D455 | -------------------------------------+------------------------------------- Comment (by ekmett): I have no issues with improving fusion for do sugared lists, the question is if it is possible to achieve this change with just a libraries fix or if you need to go into the compiler. There is a lot of crazy code down in the list comprehension module that gets used to make lists fast there. It isn't clear to me how we'd lean on it. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9781#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9781: Make list monad operations fuse -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: dfeuer Type: task | Status: new Priority: normal | Milestone: 7.10.1 Component: Core | Version: 7.9 Libraries | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: Runtime | Related Tickets: performance bug | Test Case: | Blocking: | Differential Revisions: Phab:D455 | -------------------------------------+------------------------------------- Comment (by dfeuer): Replying to [comment:1 ekmett]:
I have no issues with improving fusion for do sugared lists, the question is if it is possible to achieve this change with just a libraries fix or if you need to go into the compiler.
There is a lot of crazy code down in the list comprehension module that gets used to make lists fast there. It isn't clear to me how we'd lean on it.
The easy way is to ''use'' the list comprehension desugaring, as in the linked code review. The hard way (because it makes us hide it in some imports) is to move `concatMap` from `GHC.List` into `GHC.Base` and use `xs >>= f = concatMap f xs`, etc. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9781#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9781: Make list monad operations fuse -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: dfeuer Type: task | Status: patch Priority: normal | Milestone: 7.10.1 Component: Core | Version: 7.9 Libraries | Keywords: Resolution: | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: Runtime | Related Tickets: performance bug | Test Case: | Blocking: | Differential Revisions: Phab:D455 | -------------------------------------+------------------------------------- Changes (by dfeuer): * status: new => patch -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9781#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9781: Make list monad operations fuse
-------------------------------------+-------------------------------------
Reporter: dfeuer | Owner: dfeuer
Type: task | Status: patch
Priority: normal | Milestone: 7.10.1
Component: Core | Version: 7.9
Libraries | Keywords:
Resolution: | Architecture: Unknown/Multiple
Operating System: | Difficulty: Unknown
Unknown/Multiple | Blocked By:
Type of failure: Runtime | Related Tickets:
performance bug |
Test Case: |
Blocking: |
Differential Revisions: Phab:D455 |
-------------------------------------+-------------------------------------
Comment (by Herbert Valerio Riedel

#9781: Make list monad operations fuse -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: dfeuer Type: task | Status: closed Priority: normal | Milestone: 7.10.1 Component: Core | Version: 7.9 Libraries | Keywords: Resolution: fixed | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: Runtime | Related Tickets: performance bug | Test Case: | Blocking: | Differential Revisions: Phab:D455 | -------------------------------------+------------------------------------- Changes (by nomeata): * status: patch => closed * resolution: => fixed Comment: This showed some minor performance improvements, and one huge one, as you noticed already: cryptarithm2’s allocation went down by more than 50%! (I just spent a few minutes looking for list monad operations in that benchmark until I noticed that your commit also had an unrelated(?) change to mapM.) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9781#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9781: Make list monad operations fuse -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: dfeuer Type: task | Status: closed Priority: normal | Milestone: 7.10.1 Component: Core | Version: 7.9 Libraries | Keywords: Resolution: fixed | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: Runtime | Related Tickets: performance bug | Test Case: | Blocking: | Differential Revisions: Phab:D455 | -------------------------------------+------------------------------------- Comment (by dfeuer): Replying to [comment:5 nomeata]:
This showed some minor performance improvements, and one huge one, as you noticed already: cryptarithm2’s allocation went down by more than 50%!
(I just spent a few minutes looking for list monad operations in that benchmark until I noticed that your commit also had an unrelated(?) change to mapM.)
The change also improves cryptarithm2 without the `mapM` change, but not as much. So there must have been something else. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9781#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9781: Make list monad operations fuse -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: dfeuer Type: task | Status: closed Priority: normal | Milestone: 7.10.1 Component: Core | Version: 7.9 Libraries | Keywords: Resolution: fixed | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: Runtime | Related Tickets: performance bug | Test Case: | Blocking: | Differential Revisions: Phab:D455 | -------------------------------------+------------------------------------- Comment (by schyler): It would be nice to understand why the `mapM` change did anything at all. That's an enormous difference. I wonder how much real code in the wild has similar properties (is it a lack of INLINEing?) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9781#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#9781: Make list monad operations fuse -------------------------------------+------------------------------------- Reporter: dfeuer | Owner: dfeuer Type: task | Status: closed Priority: normal | Milestone: 7.10.1 Component: Core | Version: 7.9 Libraries | Keywords: Resolution: fixed | Architecture: Unknown/Multiple Operating System: | Difficulty: Unknown Unknown/Multiple | Blocked By: Type of failure: Runtime | Related Tickets: performance bug | Test Case: | Blocking: | Differential Revisions: Phab:D455 | -------------------------------------+------------------------------------- Comment (by dfeuer): Replying to [comment:7 schyler]:
It would be nice to understand why the `mapM` change did anything at all. That's an enormous difference. I wonder how much real code in the wild has similar properties (is it a lack of INLINEing?)
I believe it's either a lack of inlining or an unfortunate effect of full laziness. I haven't tried to dig into that particular one so deeply. Short cut fusion is great stuff, but it's on the finicky side; writing library functions so they don't themselves rely on it seems to be a good idea in many cases. The inliner will be less likely to over-estimate their cost, I believe. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/9781#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC