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 >