2011-02-01 20 views
137

¿Hay una respuesta simple: por qué es tan grande GHC?¿Por qué es GHC tan grande/grande?

  • OCaml: 2 MB
  • Python: 15MB
  • SBCL: 9 MB
  • OpenJRE - 26MB
  • GHC: 113MB

No está interesado en el evangelismo de "¿Por qué No debería 'No importa el tamaño si Haskell es la herramienta correcta'; esta es una pregunta técnica

+1

¿De dónde sacas estos 500MB? Mi GHC no está ni cerca de tan grande. – Jacob

+0

A menos que cuente todas las bibliotecas, supongo ... – Jacob

+0

Disculpe, estaba saliendo de una descarga del administrador de paquetes que incluye algunos deps. Lo actualicé para reflejar el tamaño de descarga del sitio web. Agregué un resumen de edición pero no apareció aquí (¿todavía?). Creo que la pregunta sigue en pie. Es grande. –

Respuesta

174

Es un poco tonto realmente. Cada biblioteca que viene con GHC se proporciona en no menos de 4 sabores:

  • estática
  • dinámica
  • perfilado
  • GHCi

La versión GHCi es sólo la versión estática vinculados en un solo archivo .o. Las otras tres versiones tienen su propio conjunto de archivos de interfaz (archivos .hi) también. Las versiones perfiladas parecen ser aproximadamente el doble del tamaño de las versiones no perfiladas (lo cual es un poco sospechoso, debería ver por qué).

Recuerde que GHC en sí es una biblioteca, por lo que obtendrá 4 copias de GHC. No solo eso, sino que el binario de GHC está vinculado estáticamente, por lo que son 5 copias de GHC.

Recientemente lo hicimos para que GHCi pudiera usar los archivos estáticos .a. Eso nos permitirá deshacernos de uno de estos sabores. A más largo plazo, deberíamos vincular dinámicamente el GHC, pero ese es un cambio mayor porque implicaría establecer un enlace dinámico al predeterminado: a diferencia de C, con GHC debe decidir por adelantado si va a vincular dinámicamente o no. Y necesitamos más cambios (por ejemplo, para Cabal y el sistema de paquetes, entre otras cosas) antes de que esto sea realmente práctico.

+15

Y aquí pensé que era toda la lógica que ofrece Haskell: evaluación diferida, tipo de inferencia, etc. – mcandre

+4

Entonces, 113MB/4 ~ = 28MB, aún más grande que OpenJRE ... Pero consideremos que GHC es comparable a OpenJDK, no solo a JRE , Me hace sentir mejor. –

+0

Ahora que creo que GHC usa la vinculación dinámica, tal vez las ideas del Dr. @Simon Marlow para la compresión de los cuatro sabores sean más prácticas. Cites: 1. # 3658 (Vincular dinámicamente GHCi (y usar el enlazador del sistema) en las plataformas que lo soportan) - GHC https://ghc.haskell.org/trac/ghc/ticket/3658; 2. # 8266 (Enlace dinámico en Mac) - GHC https://ghc.haskell.org/trac/ghc/ticket/8266; 3. # 8376 (Static Executable + GHC API (+ Dynamic Linking?) Da Segfault) - GHC – AnneTheAgile

4

Aquí está el desglose tamaño del directorio en mi caja:

https://spreadsheets.google.com/ccc?key=0AveoXImmNnZ6dDlQeHY2MmxPcEYzYkpweEtDSS1fUlE&hl=en

Parece que el directorio más grande (123 MB) es los binarios para compilar el propio compilador. Los documentos pesan unos asombrosos 65 MB. El tercer lugar es Cabal en 41 MB.

El directorio bin es de 33 MB, y creo que solo un subconjunto de eso es lo que se requiere técnicamente para construir aplicaciones Haskell.

+6

Permítanme agregar algo a esto: si solo toma el compilador de barebone y quita todo lo que no sea absolutamente necesario (como compilar el compilador sin filtrar, sin componentes) etc.), puede bajar a unos 5 MB. Pero intente comparar el tamaño de los compiladores con GCC. (Edité el comentario, así que tuve que eliminarlo ... lo siento) – fuz

8

Supongo que hay muchos enlaces estáticos. Cada biblioteca necesita vincular estáticamente sus dependencias, que a su vez deben vincular estáticamente las suyas y las externas. Y todo esto se compila a menudo con y sin perfiles, e incluso sin crear perfiles, los archivos binarios no se eliminan y, por lo tanto, contienen mucha información del depurador.

+1

Probablemente no me importaría si GHC cambiara a un programa completo, recompilara casi todo el modelo, similar a jhc. Incluso podría compilar más rápido si evitara que 'ld' se intercambie. –

8

Porque agrupa gcc y un conjunto de bibliotecas, todas vinculadas estáticamente.

Al menos en Windows.

+0

Y también en Linux. – fuz

+12

no, no en Linux. solo depende de gcc. porque windows no tiene gcc en su "distribución", tiene que venir con ghc. – comonad

54

Probablemente deberíamos comparar manzanas con manzanas y naranjas con naranjas. JRE es un tiempo de ejecución, no un kit de desarrollo. Podemos comparar: tamaño de fuente del kit de desarrollo, el tamaño del kit de desarrollo compilado y el tamaño compilado del tiempo de ejecución mínimo.

El paquete de orígenes OpenJDK 7 es de 82 MB (download.java.net/openjdk/jdk7) frente a paquete de orígenes GHC 7, que es de 23 MB (haskell.org/ghc/download_ghc_7_0_1). GHC no es grande aquí. Tamaño de tiempo de ejecución: openjdk-6-jre-headless en Ubuntu tiene 77 MB sin comprimir frente a Haskell helloworld, estático enlazado con su tiempo de ejecución, que es < 1 MB. GHC no es grande aquí.

Dónde GHC es grande, es el tamaño del kit de desarrollo compilado:

GHC disk usage

GHC en sí toma 270 MB, y con todas las bibliotecas y los servicios públicos que se juntan se tarda más de 500 MB. Y sí, es mucho, incluso con bibliotecas base y una herramienta de compilación/administrador de dependencias. La plataforma de desarrollo Java es más pequeña.

GHC:

$ aptitude show ghc6 | grep Size 
Uncompressed Size: 388M 

contra withdependencies OpenJDK:

$ aptitude show openjdk-6-jdk openjdk-6-jre openjdk-6-jre-headless ant maven2 ivy | grep Size 
Uncompressed Size: 34.9M 
Uncompressed Size: 905k 
Uncompressed Size: 77.3M 
Uncompressed Size: 1,585k 
Uncompressed Size: 3,736k 
Uncompressed Size: 991k 

Pero todavía es más de 100 MB, 26 MB, no a medida que escribe.

cosas peso pesado en ghc6 y ghc6-prof son:

$ dpkg -L ghc6 | grep '\.a$' | xargs ls -1ks | sort -k 1 -n -r | head -3 
57048 /usr/lib/ghc-6.12.1/ghc-6.12.1/libHSghc-6.12.1.a 
22668 /usr/lib/ghc-6.12.1/Cabal-1.8.0.2/libHSCabal-1.8.0.2.a 
21468 /usr/lib/ghc-6.12.1/base-4.2.0.0/libHSbase-4.2.0.0.a 
$ dpkg -L ghc6-prof | grep '\.a$' | xargs ls -1ks | sort -k 1 -n -r | head -3 
112596 /usr/lib/ghc-6.12.1/ghc-6.12.1/libHSghc-6.12.1_p.a 
33536 /usr/lib/ghc-6.12.1/Cabal-1.8.0.2/libHSCabal-1.8.0.2_p.a 
31724 /usr/lib/ghc-6.12.1/base-4.2.0.0/libHSbase-4.2.0.0_p.a 

Tenga en cuenta lo grande que es libHSghc-6.12.1_p.a. Entonces, la respuesta parece ser la vinculación estática y las versiones de creación de perfiles para cada biblioteca.

+4

+1 para "openjdk-6-jre-headless en Ubuntu es de 77 MB descomprimido frente a Haskell helloworld, enlazado estáticamente con su tiempo de ejecución, que es <1 MB. GHC no es grande aquí". – fuz

5

La respuesta breve es que se debe a que todos los ejecutables están vinculados estáticamente, pueden contener información de depuración y las bibliotecas se incluyen en varias copias. Esto ya lo han dicho otros comentaristas.

La vinculación dinámica es posible y reducirá drásticamente el tamaño. Aquí está un ejemplo Hello.hs:

main = putStrLn "Hello world" 

construyo con GHC 7.4.2 en Windows.

ghc --make -O2 da Hello.exe de 1105Ks

Correr strip en él deja 630K

ghc --make -O2 -dynamic da 40K

Decapado deja solo 13K.

Sus dependencias son 5 dlls con un tamaño total de 9,2 MB sin eliminar y 5,7 MB despojados.