[GHC] #13081: Code size explosion with with inlined instances for fixed point of functor

GHC ghc-devs at haskell.org
Sat Jan 7 15:00:11 UTC 2017


#13081: Code size explosion with with inlined instances for fixed point of functor
-------------------------------------+-------------------------------------
           Reporter:  kja            |             Owner:
               Type:  bug            |            Status:  new
           Priority:  normal         |         Milestone:
          Component:  Compiler       |           Version:  8.0.2
           Keywords:                 |  Operating System:  Unknown/Multiple
       Architecture:                 |   Type of failure:  Compile-time
  Unknown/Multiple                   |  performance bug
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 The following code is not feasible to compile due to a massive explosion
 in "terms" generated by the simplifier as reported by `-v` flag.

 {{{#!hs
 ---[ import Data.Functor.Fixedpoint from unification-fd ]-----------------

 newtype Fix f = Fix { unFix :: f (Fix f) }

 instance (Eq (f (Fix f))) => Eq (Fix f) where
   x == y  = unFix x == unFix y
   x /= y  = unFix x /= unFix y

 --------------------------------------------------------------------------------

 data Foo' a = A
             | B a
             | C a
             | D a a
             | E a a a
             deriving (Eq)

 type Foo = Fix Foo'

 bar :: Foo -> Foo -> m ()
 bar t t' =
   if t == t'
   then undefined
   else undefined
 }}}

 Compiling with `-v` on 8.0.2 yields:

 {{{
 [1 of 1] Compiling Lib              ( src/Lib.hs, .stack-
 work/dist/x86_64-osx/Cabal-1.24.2.0/build/Lib.o )
 *** Parser [Lib]:
 !!! Parser [Lib]: finished in 0.90 milliseconds, allocated 0.797 megabytes
 *** Renamer/typechecker [Lib]:
 !!! Renamer/typechecker [Lib]: finished in 136.61 milliseconds, allocated
 57.026 megabytes
 *** Desugar [Lib]:
 Result size of Desugar (after optimization)
   = {terms: 257, types: 237, coercions: 24}
 !!! Desugar [Lib]: finished in 2.38 milliseconds, allocated 1.264
 megabytes
 *** Simplifier [Lib]:
 Result size of Simplifier iteration=1
   = {terms: 297, types: 305, coercions: 18}
 Result size of Simplifier = {terms: 294, types: 301, coercions: 18}
 !!! Simplifier [Lib]: finished in 3.78 milliseconds, allocated 2.165
 megabytes
 *** Specialise [Lib]:
 Result size of Specialise = {terms: 294, types: 301, coercions: 18}
 !!! Specialise [Lib]: finished in 0.52 milliseconds, allocated 0.382
 megabytes
 *** Float out(FOS {Lam = Just 0,
                    Consts = True,
                    OverSatApps = False}) [Lib]:
 Result size of Float out(FOS {Lam = Just 0,
                               Consts = True,
                               OverSatApps = False})
   = {terms: 366, types: 418, coercions: 18}
 !!! Float out(FOS {Lam = Just 0,
                    Consts = True,
                    OverSatApps = False}) [Lib]: finished in 1.38
 milliseconds, allocated 1.657 megabytes
 *** Simplifier [Lib]:
 Result size of Simplifier iteration=1
   = {terms: 364, types: 362, coercions: 38}
 Result size of Simplifier iteration=2
   = {terms: 311, types: 325, coercions: 38}
 Result size of Simplifier iteration=3
   = {terms: 395, types: 417, coercions: 74}
 Result size of Simplifier iteration=4
   = {terms: 395, types: 410, coercions: 74}
 Result size of Simplifier = {terms: 395, types: 410, coercions: 74}
 !!! Simplifier [Lib]: finished in 9.11 milliseconds, allocated 5.846
 megabytes
 *** Simplifier [Lib]:
 Result size of Simplifier iteration=1
   = {terms: 991, types: 1,022, coercions: 326}
 Result size of Simplifier iteration=2
   = {terms: 991, types: 973, coercions: 326}
 Result size of Simplifier iteration=3
   = {terms: 5,323, types: 5,433, coercions: 2,090}
 Result size of Simplifier iteration=4
   = {terms: 5,323, types: 5,090, coercions: 2,090}
 Result size of Simplifier
   = {terms: 5,323, types: 5,090, coercions: 2,090}
 !!! Simplifier [Lib]: finished in 95.35 milliseconds, allocated 60.572
 megabytes
 *** Simplifier [Lib]:
 Result size of Simplifier iteration=1
   = {terms: 35,839, types: 36,118, coercions: 14,438}
 Result size of Simplifier iteration=2
   = {terms: 35,839, types: 33,717, coercions: 14,438}
 Result size of Simplifier iteration=3
   = {terms: 250,219, types: 250,145, coercions: 100,874}
 Result size of Simplifier iteration=4
   = {terms: 250,219, types: 233,338, coercions: 100,874}
 Result size of Simplifier
   = {terms: 250,219, types: 233,338, coercions: 100,874}
 !!! Simplifier [Lib]: finished in 5567.46 milliseconds, allocated 2798.871
 megabytes
 *** Float inwards [Lib]:
 Result size of Float inwards
   = {terms: 250,219, types: 233,338, coercions: 100,874}
 !!! Float inwards [Lib]: finished in 744.72 milliseconds, allocated
 594.429 megabytes
 *** Called arity analysis [Lib]:
 Result size of Called arity analysis
   = {terms: 250,219, types: 233,338, coercions: 100,874}
 !!! Called arity analysis [Lib]: finished in 311.34 milliseconds,
 allocated 190.166 megabytes
 *** Simplifier [Lib]:

 }}}

 ... at which point it seems to "hang", though depending on hardware it
 might still succeed. It is clearly proportional in the number of
 constructors and occurrences of the type variable in those constructor. To
 aggravate the issue, simply add more of both.

 Any of ...

   * compiling with -O0
   * adding a NOINLINE pragma to `(==)` in the instance for `Fix`
   * implementing a manual `Eq` instance for `Foo` and adding a NOINLINE
 pragma there

 ... solves the issue for me.

 Observed on both 8.0.1 (Windows and macOS) and 8.0.2 (macOS)

 Not present on 7.10.3 (Windows and macOS).

--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/13081>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list