GHCが遅いのはGCCやPerlが遅いせい?

少し前にどこかで「Haskellは重い」という例として、「GHCのビルドが遅い(GHC自体のビルド時間が長い)」という話が出ていたと思うのですが、GHCのブートストラップはHaskellから生成されたCコードをコンパイルしていて、そのときに使われれているCコンパイラ(GCC)やポストプロセッサ(Perlスクリプト)が遅いだけだったりはしないのでしょうか。:-) 元の話もGHCもちゃんとフォローしていないので外れていたら or 既出だったらすみません。

言語処理系などを作っていてGCCを「高級アセンブラ」として使うとわかるのですが、本体の大きい関数や長いコードを-O2や-O3でコンパイルすると、いつまで経っても終わらない、ということがよくあります…。あと、アセンブリのポストプロセッシングもGCCのバージョンに依存したりして大変です。

追記:上の説はデマとの情報。あれ、デフォルトは-fasmなのか-fvia-Cなのか…?(Cf. http://www.haskell.org/ghc/docs/latest/html/users_guide/options-phases.html)

追記2:いつも人任せでは何なので、たまには自分で確認してみました。全体で5.195秒、gccが2.634秒、perlスクリプトのポストプロセッサ(Mangler)が0.929秒との結果。環境はLinux 2.6.8, Pentium4 3.40GHz, メインメモリ384MBです(古くてすみません)。

> wget http://shinh.skr.jp/koneta/sbf.hs
--10:21:04--  http://shinh.skr.jp/koneta/sbf.hs
           => `sbf.hs'
Resolving shinh.skr.jp... 59.106.13.141
Connecting to shinh.skr.jp[59.106.13.141]:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 10,328 [text/plain]

100%[====================================>] 10,328        --.--K/s             

10:21:05 (7.04 MB/s) - `sbf.hs' saved [10328/10328]

> time ghc -v -c -fvia-C -keep-hc-files sbf.hs
Glasgow Haskell Compiler, Version 6.2.2, for Haskell 98, compiled by GHC version 6.2.2
Using package config file: /usr/lib/ghc-6.2.2/package.conf

==================== Packages ====================
Package
   {name = "data",
    auto = False,
    import_dirs = ["/usr/lib/ghc-6.2.2/hslibs-imports/data"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSdata"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = [],
    package_deps = ["haskell98", "lang", "util"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "rts",
    auto = False,
    import_dirs = [],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSrts"],
    extra_libraries = ["m", "gmp", "dl"],
    include_dirs = ["/usr/lib/ghc-6.2.2/include"],
    c_includes = ["Stg.h"],
    package_deps = [],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts =
      ["-u",
       "GHCziBase_Izh_static_info",
       "-u",
       "GHCziBase_Czh_static_info",
       "-u",
       "GHCziFloat_Fzh_static_info",
       "-u",
       "GHCziFloat_Dzh_static_info",
       "-u",
       "GHCziPtr_Ptr_static_info",
       "-u",
       "GHCziWord_Wzh_static_info",
       "-u",
       "GHCziInt_I8zh_static_info",
       "-u",
       "GHCziInt_I16zh_static_info",
       "-u",
       "GHCziInt_I32zh_static_info",
       "-u",
       "GHCziInt_I64zh_static_info",
       "-u",
       "GHCziWord_W8zh_static_info",
       "-u",
       "GHCziWord_W16zh_static_info",
       "-u",
       "GHCziWord_W32zh_static_info",
       "-u",
       "GHCziWord_W64zh_static_info",
       "-u",
       "GHCziStable_StablePtr_static_info",
       "-u",
       "GHCziBase_Izh_con_info",
       "-u",
       "GHCziBase_Czh_con_info",
       "-u",
       "GHCziFloat_Fzh_con_info",
       "-u",
       "GHCziFloat_Dzh_con_info",
       "-u",
       "GHCziPtr_Ptr_con_info",
       "-u",
       "GHCziPtr_FunPtr_con_info",
       "-u",
       "GHCziStable_StablePtr_con_info",
       "-u",
       "GHCziBase_False_closure",
       "-u",
       "GHCziBase_True_closure",
       "-u",
       "GHCziPack_unpackCString_closure",
       "-u",
       "GHCziIOBase_stackOverflow_closure",
       "-u",
       "GHCziIOBase_heapOverflow_closure",
       "-u",
       "GHCziIOBase_NonTermination_closure",
       "-u",
       "GHCziIOBase_BlockedOnDeadMVar_closure",
       "-u",
       "GHCziIOBase_Deadlock_closure",
       "-u",
       "GHCziWeak_runFinalizzerBatch_closure",
       "-u",
       "__stginit_Prelude"],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "base",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSbase"],
    extra_libraries = ["HSbase_cbits"],
    include_dirs = [],
    c_includes = ["HsBase.h"],
    package_deps = ["rts"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "haskell98",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HShaskell98"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = [],
    package_deps = ["base"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "haskell-src",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HShaskell-src"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = [],
    package_deps = ["base", "haskell98"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "network",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSnetwork"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = ["HsNet.h"],
    package_deps = ["base"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "parsec",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSparsec"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = [],
    package_deps = ["base"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "QuickCheck",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSQuickCheck"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = [],
    package_deps = ["base"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "readline",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSreadline"],
    extra_libraries = ["readline", "ncurses"],
    include_dirs = [],
    c_includes = ["HsReadline.h"],
    package_deps = ["base"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "OpenGL",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSOpenGL"],
    extra_libraries = ["HSOpenGL_cbits"],
    include_dirs = [],
    c_includes = ["HsOpenGL.h"],
    package_deps = ["base"],
    extra_ghc_opts = [],
    extra_cc_opts = ["-I/usr/X11R6/include"],
    extra_ld_opts =
      ["-lGLU",
       "-lGL",
       "-L/usr/X11R6/lib",
       "-lSM",
       "-lICE",
       "-lXext",
       "-lX11",
       "-lm"],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "GLUT",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSGLUT"],
    extra_libraries = ["HSGLUT_cbits"],
    include_dirs = [],
    c_includes = ["HsGLUT.h"],
    package_deps = ["base", "OpenGL"],
    extra_ghc_opts = [],
    extra_cc_opts = ["-I/usr/X11R6/include"],
    extra_ld_opts =
      ["-lglut",
       "-lGLU",
       "-lGL",
       "-L/usr/X11R6/lib",
       "-lSM",
       "-lICE",
       "-lXmu",
       "-lXt",
       "-lXi",
       "-lXext",
       "-lX11",
       "-lm"],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "unix",
    auto = True,
    import_dirs = ["/usr/lib/ghc-6.2.2/imports"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSunix"],
    extra_libraries = ["HSunix_cbits", "dl"],
    include_dirs = [],
    c_includes = ["HsUnix.h"],
    package_deps = ["base"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "lang",
    auto = False,
    import_dirs = ["/usr/lib/ghc-6.2.2/hslibs-imports/lang"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSlang"],
    extra_libraries = ["HSlang_cbits"],
    include_dirs = [],
    c_includes = ["HsLang.h"],
    package_deps = ["base"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "concurrent",
    auto = False,
    import_dirs = ["/usr/lib/ghc-6.2.2/hslibs-imports/concurrent"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSconcurrent"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = [],
    package_deps = ["base"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "posix",
    auto = False,
    import_dirs = ["/usr/lib/ghc-6.2.2/hslibs-imports/posix"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSposix"],
    extra_libraries = ["HSposix_cbits", "dl"],
    include_dirs = [],
    c_includes = ["HsPosix.h"],
    package_deps = ["lang", "unix"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "util",
    auto = False,
    import_dirs = ["/usr/lib/ghc-6.2.2/hslibs-imports/util"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSutil"],
    extra_libraries = ["HSutil_cbits"],
    include_dirs = [],
    c_includes = ["HsUtil.h"],
    package_deps =
      ["lang", "concurrent", "QuickCheck", "readline", "posix"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "text",
    auto = False,
    import_dirs = ["/usr/lib/ghc-6.2.2/hslibs-imports/text"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HStext"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = [],
    package_deps = ["lang", "parsec"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "net",
    auto = False,
    import_dirs = ["/usr/lib/ghc-6.2.2/hslibs-imports/net"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HSnet"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = [],
    package_deps = ["network"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}
Package
   {name = "hssource",
    auto = False,
    import_dirs = ["/usr/lib/ghc-6.2.2/hslibs-imports/hssource"],
    source_dirs = [],
    library_dirs = ["/usr/lib/ghc-6.2.2"],
    hs_libraries = ["HShssource"],
    extra_libraries = [],
    include_dirs = [],
    c_includes = [],
    package_deps = ["haskell-src"],
    extra_ghc_opts = [],
    extra_cc_opts = [],
    extra_ld_opts = [],
    framework_dirs = [],
    extra_frameworks = []}


Hsc static flags: -static
*** Checking old interface for Main:
*** Parser:
*** Renamer/typechecker:
*** Desugar:
    Result size = 4581
*** Simplify:
    Result size = 6022
    Result size = 5231
    Result size = 5219
    Result size = 5219
*** Tidy Core:
    Result size = 5219
*** CorePrep:
    Result size = 6532
*** Stg2Stg:
*** CodeGen:
*** CodeOutput:
*** C Compiler
gcc -x c sbf.hc -o /tmp/ghc16003.raw_s -DDONT_WANT_WIN32_DLL_SUPPORT -fno-defer-pop -mno-omit-leaf-frame-pointer -fomit-frame-pointer -fno-builtin -DSTOLEN_X86_REGS=4 -v -S -Wimplicit -O -D__GLASGOW_HASKELL__=602 -ffloat-store -I . -I . -I /usr/lib/ghc-6.2.2/include
Reading specs from /exthd4/usr/bin/../lib/gcc-lib/i486-linux/3.3.5/specs
Configured with: ../src/configure -v --enable-languages=c,c++,java,f77,pascal,objc,ada,treelang --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-gxx-include-dir=/usr/include/c++/3.3 --enable-shared --enable-__cxa_atexit --with-system-zlib --enable-nls --without-included-gettext --enable-clocale=gnu --enable-debug --enable-java-gc=boehm --enable-java-awt=xlib --enable-objc-gc i486-linux
Thread model: posix
gcc version 3.3.5 (Debian 1:3.3.5-13)
 /exthd4/usr/bin/../lib/gcc-lib/i486-linux/3.3.5/cc1 -quiet -v -I . -I . -I /usr/lib/ghc-6.2.2/include -iprefix /exthd4/usr/bin/../lib/gcc-lib/i486-linux/3.3.5/ -D__GNUC__=3 -D__GNUC_MINOR__=3 -D__GNUC_PATCHLEVEL__=5 -DDONT_WANT_WIN32_DLL_SUPPORT -DSTOLEN_X86_REGS=4 -D__GLASGOW_HASKELL__=602 sbf.hc -quiet -dumpbase sbf.hc -mno-omit-leaf-frame-pointer -auxbase-strip /tmp/ghc16003.raw_s -O -Wimplicit -version -fno-defer-pop -fomit-frame-pointer -fno-builtin -ffloat-store -o /tmp/ghc16003.raw_s
GNU C version 3.3.5 (Debian 1:3.3.5-13) (i486-linux)
	compiled by GNU C version 3.3.5 (Debian 1:3.3.5-13).
GGC heuristics: --param ggc-min-expand=55 --param ggc-min-heapsize=48343
ignoring nonexistent directory "/exthd4/usr/i486-linux/include"
ignoring nonexistent directory "/usr/i486-linux/include"
ignoring duplicate directory "."
ignoring duplicate directory "/usr/lib/gcc-lib/i486-linux/3.3.5/include"
#include "..." search starts here:
#include <...> search starts here:
 .
 /usr/lib/ghc-6.2.2/include
 /exthd4/usr/lib/gcc-lib/i486-linux/3.3.5/include
 /usr/local/include
 /usr/include
End of search list.
*** Mangler
/usr/lib/ghc-6.2.2/ghc-asm /tmp/ghc16003.raw_s /tmp/ghc16003.s 4
*** Assembler
gcc -I. -I. -c /tmp/ghc16003.s -o sbf.o
*** Deleting temp files
Deleting: /tmp/ghc16003.s /tmp/ghc16003.raw_s
5.195u 0.704s 0:14.19 41.5%	0+0k 0+0io 0pf+0w
> time ghc -C sbf.hs
1.409u 0.151s 0:01.56 99.3%	0+0k 0+0io 0pf+0w
> time gcc -x c sbf.hc -o /tmp/ghc16003.raw_s -DDONT_WANT_WIN32_DLL_SUPPORT -fno-defer-pop -mno-omit-leaf-frame-pointer -fomit-frame-pointer -fno-builtin -DSTOLEN_X86_REGS=4 -S -Wimplicit -O -D__GLASGOW_HASKELL__=602 -ffloat-store -I . -I . -I /usr/lib/ghc-6.2.2/include
2.634u 0.300s 0:02.93 100.0%	0+0k 0+0io 0pf+0w
> time /usr/lib/ghc-6.2.2/ghc-asm /tmp/ghc16003.raw_s /tmp/ghc16003.s 4
0.929u 0.034s 0:00.94 101.0%	0+0k 0+0io 0pf+0w
>