[GHC] #9630: compile-time performance regression (probably due to Generics)
GHC
ghc-devs at haskell.org
Fri Dec 18 00:03:34 UTC 2015
#9630: compile-time performance regression (probably due to Generics)
-------------------------------------+-------------------------------------
Reporter: hvr | Owner: simonpj
Type: bug | Status: new
Priority: high | Milestone: 8.0.1
Component: Compiler | Version: 7.9
Resolution: | Keywords: deriving-perf
Operating System: Unknown/Multiple | Architecture:
Type of failure: Compile-time | Unknown/Multiple
performance bug | Test Case:
Blocked By: | Blocking:
Related Tickets: #9583, #10293 | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by ezyang):
I did some investigation related to this bug on GHC 7.10.3-ish and binary
0.7.5.0 (yes it's old, but I didn't see any more recent relevant commits;
and it's what GHC is bootstrapping with). Here are some partial findings:
1. I can trigger bad constant factors this data type:
{{{
{-# LANGUAGE DeriveGeneric #-}
module A where
import Data.Binary
import GHC.Generics
data T = T
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
deriving Generic
instance Binary T
}}}
{{{
ezyang at sabre:~/Dev/labs$ time $DEV/ghc-7.10-frontend-plugins/usr/bin/ghc
--make Bin.hs -O2 -fforce-recomp -fliberate-case-threshold=1000
[1 of 1] Compiling A ( Bin.hs, Bin.o )
real 0m7.369s
user 0m6.408s
sys 0m0.224s
ezyang at sabre:~/Dev/labs$ time $DEV/ghc-7.10-frontend-plugins/usr/bin/ghc
--make Bin.hs -O0 -fforce-recomp -fliberate-case-threshold=1000
[1 of 1] Compiling A ( Bin.hs, Bin.o )
real 0m0.881s
user 0m0.776s
sys 0m0.080s
}}}
2. The problem gets worse if you have explicit field names, something like
a x2 factor.
{{{
data T = T
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
() () () () () () () () () ()
deriving Generic
-- versus
data T = T {
f0 :: (),
f1 :: (),
f2 :: (),
f3 :: (),
f4 :: (),
f5 :: (),
f6 :: (),
f7 :: (),
f8 :: (),
f9 :: (),
f10 :: (),
f11 :: (),
f12 :: (),
f13 :: (),
f14 :: (),
f15 :: (),
f16 :: (),
f17 :: (),
f18 :: (),
f19 :: (),
f20 :: (),
f21 :: (),
f22 :: (),
f23 :: (),
f24 :: (),
f25 :: (),
f26 :: (),
f27 :: (),
f28 :: (),
f29 :: (),
f30 :: (),
f31 :: (),
f32 :: (),
f33 :: (),
f34 :: (),
f35 :: (),
f36 :: (),
f37 :: (),
f38 :: (),
f39 :: ()
}
deriving (Generic)
}}}
{{{
ezyang at sabre:~/Dev/labs$ time $DEV/ghc-7.10-frontend-plugins/usr/bin/ghc
--make Bin.hs -O -fforce-recomp -fliberate-case-threshold=1000
[1 of 1] Compiling A ( Bin.hs, Bin.o )
real 0m2.649s
user 0m2.520s
sys 0m0.080s
ezyang at sabre:~/Dev/labs$ time $DEV/ghc-7.10-frontend-plugins/usr/bin/ghc
--make Bin.hs -O -fforce-recomp -fliberate-case-threshold=1000
[1 of 1] Compiling A ( Bin.hs, Bin.o )
real 0m4.990s
user 0m4.824s
sys 0m0.144s
}}}
It's NOT just generic deriving; the generic deriving is still pretty
speedy, honestly.
3. If you inline all of Binary's class definitions into the same file,
things speed up. Comparing the two cases, it seems that when we cross-
module compile, GHC does more inlining and more optimization, and it takes
longer. This is something like a 30% factor.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9630#comment:21>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list