[GHC] #11375: Type aliases twice as slow to compile as closed type families.

GHC ghc-devs at haskell.org
Thu Jan 7 21:57:10 UTC 2016


#11375: Type aliases twice as slow to compile as closed type families.
-------------------------------------+-------------------------------------
           Reporter:  danilo2        |             Owner:
               Type:  bug            |            Status:  new
           Priority:  high           |         Milestone:
          Component:  Compiler       |           Version:  8.1
  (Type checker)                     |
           Keywords:                 |  Operating System:  MacOS X
       Architecture:  aarch64        |   Type of failure:  Compile-time
                                     |  performance bug
          Test Case:                 |        Blocked By:
           Blocking:                 |   Related Tickets:
Differential Rev(s):                 |         Wiki Page:
-------------------------------------+-------------------------------------
 Hello guys! This bug is awkard at last to me. So I notiiced today, that
 using type aliases in my code takes twice as long to copile than using
 closed type families with just single member. So to be most precise - when
 I replace the following line:
 {{{
 type XQ1 m a = Targets (Match m a)
 }}}

 with

 {{{
 type family XQ1 m a where XQ1 m a = Targets (Match m a)
 }}}

 the compilation time drops from 15s to 7s (this type alias is heavily used
 across the application). I think it could be somehow related to the famous
 #8095 bug, but I can of course be wrong here.

 Unfortunetally the codebase is pretty big and its not so easy to make a
 minimal example, but I'll try to work on it during the upcoming weekend
 (please notify me if that would not be necessary).

 And some statistics from `-dshow-passes`:

 When using type alias:
 {{{
 *** Parser:
 *** Renamer/typechecker:
 *** Desugar:
 Result size of Desugar (after optimization)
   = {terms: 10,303, types: 66,949, coercions: 16,383,834}
 *** Simplifier:
 Result size of Simplifier iteration=1
   = {terms: 10,722, types: 75,391, coercions: 16,507,338}
 Result size of Simplifier iteration=2
   = {terms: 10,550, types: 74,437, coercions: 16,504,770}
 Result size of Simplifier iteration=3
   = {terms: 10,543, types: 74,347, coercions: 16,504,734}
 Result size of Simplifier
   = {terms: 10,543, types: 74,347, coercions: 16,504,630}
 *** Tidy Core:
 Result size of Tidy Core
   = {terms: 10,846, types: 75,522, coercions: 16,504,729}
 *** CorePrep:
 Result size of CorePrep
   = {terms: 14,823, types: 96,430, coercions: 16,504,729}
 *** ByteCodeGen:
 Upsweep completely successful.
 *** Deleting temp files:
 Warning: deleting non-existent
 /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64965_0/ghc_95.c
 Warning: deleting non-existent
 /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64965_0/ghc_94.o
 Ok, modules loaded: Prologue, Type.Bool, Type.Container, Type.List,
 Type.Set, Data.Cata, Type.Promotion, Data.Bits.Mask,
 Control.Monad.State.Dependent, Control.Monad.Poly,
 Control.Applicative.Poly, Type.Regex, Type.Either, Data.Reprx,
 Data.Impossible, Type.Cache.TH, Main, Control.Lens.Utils,
 Control.Lens.Wrapped.Utils, Data.Text.CodeBuilder,
 Data.Text.CodeBuilder.Tok, Data.Text.CodeBuilder.Builder,
 Data.Text.CodeBuilder.Doc, Data.Binary.Instances.Missing,
 Data.Default.Instances.Missing, Data.String.Class, Data.Text.Class,
 Data.Convert, Data.Layer, Data.Container.Class, Data.Container.List,
 Data.Functor.Utils, Type.Operators, Type.Show, Type.Wrapped,
 Data.Container.Opts, Data.Container.Poly, Data.Convert.Base,
 Data.Convert.Instances, Data.Convert.Instances.Map,
 Data.Convert.Instances.Num, Data.Convert.Instances.Text,
 Data.Convert.Instances.TH, Data.Convert.Bound, Data.Bits.Base.
 *** Parser:
 *** Desugar:
 *** Simplify:
 *** CorePrep:
 *** ByteCodeGen:
 ...
 }}}

 and with type families:

 {{{
 *** Parser:
 *** Renamer/typechecker:
 *** Desugar:
 Result size of Desugar (after optimization)
   = {terms: 310, types: 867, coercions: 78}
 *** Simplifier:
 Result size of Simplifier iteration=1
   = {terms: 301, types: 878, coercions: 296}
 Result size of Simplifier
   = {terms: 301, types: 878, coercions: 293}
 *** Tidy Core:
 Result size of Tidy Core
   = {terms: 337, types: 1,002, coercions: 293}
 *** CorePrep:
 Result size of CorePrep
   = {terms: 475, types: 1,305, coercions: 293}
 *** ByteCodeGen:
 *** Deleting temp files:
 Warning: deleting non-existent
 /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64863_0/ghc_93.c
 Warning: deleting non-existent
 /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64863_0/ghc_92.o
 compile: input file
 /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64863_0/ghc_1.hscpp
 *** Checking old interface for Main:
 [45 of 45] Compiling Main             (
 /Users/wdanilo/dev/hs/public/variants/Main.hs, interpreted )
 *** Parser:
 *** Renamer/typechecker:
 *** Desugar:
 Result size of Desugar (after optimization)
   = {terms: 10,303, types: 67,609, coercions: 162,249}
 *** Simplifier:
 Result size of Simplifier iteration=1
   = {terms: 10,722, types: 75,721, coercions: 323,027}
 Result size of Simplifier iteration=2
   = {terms: 10,550, types: 74,767, coercions: 320,473}
 Result size of Simplifier iteration=3
   = {terms: 10,543, types: 74,677, coercions: 320,437}
 Result size of Simplifier
   = {terms: 10,543, types: 74,677, coercions: 320,333}
 *** Tidy Core:
 Result size of Tidy Core
   = {terms: 10,846, types: 75,852, coercions: 320,432}
 *** CorePrep:
 Result size of CorePrep
   = {terms: 14,823, types: 96,760, coercions: 320,432}
 *** ByteCodeGen:
 Upsweep completely successful.
 *** Deleting temp files:
 Warning: deleting non-existent
 /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64863_0/ghc_95.c
 Warning: deleting non-existent
 /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64863_0/ghc_94.o
 Ok, modules loaded: Prologue, Type.Bool, Type.Container, Type.List,
 Type.Set, Data.Cata, Type.Promotion, Data.Bits.Mask,
 Control.Monad.State.Dependent, Control.Monad.Poly,
 Control.Applicative.Poly, Type.Regex, Type.Either, Data.Reprx,
 Data.Impossible, Type.Cache.TH, Main, Control.Lens.Utils,
 Control.Lens.Wrapped.Utils, Data.Text.CodeBuilder,
 Data.Text.CodeBuilder.Tok, Data.Text.CodeBuilder.Builder,
 Data.Text.CodeBuilder.Doc, Data.Binary.Instances.Missing,
 Data.Default.Instances.Missing, Data.String.Class, Data.Text.Class,
 Data.Convert, Data.Layer, Data.Container.Class, Data.Container.List,
 Data.Functor.Utils, Type.Operators, Type.Show, Type.Wrapped,
 Data.Container.Opts, Data.Container.Poly, Data.Convert.Base,
 Data.Convert.Instances, Data.Convert.Instances.Map,
 Data.Convert.Instances.Num, Data.Convert.Instances.Text,
 Data.Convert.Instances.TH, Data.Convert.Bound, Data.Bits.Base.
 *** Parser:
 *** Desugar:
 *** Simplify:
 *** CorePrep:
 *** ByteCodeGen:
 ...
 }}}

 As we can see the type aliases produce much more coertions: 16,383,834 vs
 78 using type families. This is really interesting thing and it seems
 related to the linked bug above.

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


More information about the ghc-tickets mailing list