Dlaczego GHC jest tak duży / duży?

147

Czy jest prosta odpowiedź: dlaczego GHC jest tak duży?

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

Nie interesuje się ewangelizacją: „Dlaczego nie powinienem przejmować się rozmiarem, jeśli Haskell jest właściwym narzędziem”; to jest kwestia techniczna.

Christopher Gotowe
źródło
1
Skąd bierzesz to 500 MB? Mój GHC nie jest tak duży.
Jacob
Chyba że policzysz wszystkie biblioteki, myślę, że ...
Jacob
Przepraszam, wychodziłem z pobierania menedżera pakietów, który zawiera kilka deps. Zaktualizowałem go, aby odzwierciedlał rozmiar pobierania ze strony internetowej. Dodałem podsumowanie edycji, ale nie pojawiło się tutaj (jeszcze?). Myślę, że pytanie wciąż jest aktualne. To jest duże.
Christopher Gotowe
20
Prawdopodobnie powinniśmy porównać jabłka do jabłek, a pomarańcze do pomarańczy. JRE to środowisko wykonawcze, a nie zestaw deweloperski. Pakiet źródłowy OpenJDK 7, 82 MB ( download.java.net/openjdk/jdk7 ) vs pakiet źródłowy GHC 7, 23 MB ( haskell.org/ghc/download_ghc_7_0_1 ). Teraz środowisko uruchomieniowe: openjdk-6-jre-headless na Ubuntu, 77 MB nieskompresowane vs Haskell helloworld, statycznie połączone z jego uruchomieniem, <1 MB.
sastanin
Dzisiaj byłam ciekawa rozmiarów, które teraz są w 2014 roku. Wygląda na to, że argument nadal się utrzymuje. Znalazłem adresy URL : 1.GHC haskell.org/ghc/download_ghc_7_8_3 ; 2.OpenJCK packages.ubuntu.com/precise/openjdk-7-jdk
AnneTheAgile

Odpowiedzi:

187

To naprawdę trochę głupie. Każda biblioteka dostarczana z GHC jest dostarczana w co najmniej 4 wersjach :

  • statyczny
  • dynamiczny
  • profilowane
  • GHCi

Wersja GHCi to po prostu wersja statyczna połączona w jednym .opliku. Pozostałe trzy wersje również mają swój własny zestaw plików interfejsu ( .hiplików). Wersje profilowane wydają się być około dwa razy większe niż wersje nieprofilowane (co jest nieco podejrzane, powinienem sprawdzić, dlaczego tak jest).

Pamiętaj, że sam GHC jest biblioteką , więc otrzymujesz 4 kopie GHC. Nie tylko to, ale sam plik binarny GHC jest statycznie połączony, więc jest to 5 kopii GHC.

Niedawno zrobiliśmy to tak, że GHCi może używać .aplików statycznych . To pozwoli nam pozbyć się jednego z tych smaków. W dłuższej perspektywie powinniśmy dynamicznie łączyć GHC, ale to większa zmiana, ponieważ oznaczałoby to uczynienie dynamicznego łączenia jako domyślnego - w przeciwieństwie do C, w przypadku GHC musisz z góry zdecydować, czy chcesz łączyć się dynamicznie, czy nie. I potrzebujemy więcej zmian (np. Między innymi w Cabal i systemie pakietów), zanim stanie się to naprawdę praktyczne.

Simon Marlow
źródło
16
I tutaj pomyślałem, że to cała logika, którą oferuje Haskell: leniwa ocena, wnioskowanie o typie itp.
mcandre,
4
Więc 113 MB / 4 ~ = 28 MB, wciąż większe niż OpenJRE ... Ale weź pod uwagę, że GHC jest porównywalne z OpenJDK, a nie tylko z JRE, to sprawia, że ​​czuję się lepiej.
Earth Engine
1
Teraz, kiedy myślę, że GHC wykorzystuje dynamiczne łączenie, być może pomysły dr @Simona Marlowa dotyczące kompresji czterech smaków są bardziej praktyczne? Cytuje: 1. # 3658 (Łącz dynamicznie GHCi (i używaj konsolidatora systemowego) na platformach, które go obsługują) - GHC ghc.haskell.org/trac/ghc/ticket/3658 ; 2. # 8266 (dynamiczne linkowanie na Macu) - GHC ghc.haskell.org/trac/ghc/ticket/8266 ; 3. # 8376 (Static Executable + GHC API (+ Dynamic Linking?) Daje Segfault) - GHC
AnneTheAgile
56

Prawdopodobnie powinniśmy porównać jabłka do jabłek, a pomarańcze do pomarańczy. JRE to środowisko wykonawcze, a nie zestaw deweloperski. Możemy porównać: rozmiar źródła zestawu deweloperskiego, rozmiar skompilowanego zestawu deweloperskiego i skompilowany rozmiar minimalnego środowiska uruchomieniowego.

Pakiet źródłowy OpenJDK 7 ma 82 MB (download.java.net/openjdk/jdk7) w porównaniu z pakietem źródłowym GHC 7, czyli 23 MB (haskell.org/ghc/download_ghc_7_0_1). GHC nie jest tu duży. Rozmiar środowiska wykonawczego: openjdk-6-jre-headless na Ubuntu to 77 MB nieskompresowanego w porównaniu z Haskell helloworld, statycznie połączonym z jego uruchomieniem, które wynosi <1 MB. GHC nie jest tu duży.

Gdzie GHC jest duży, jest to rozmiar skompilowanego zestawu deweloperskiego:

Wykorzystanie dysku GHC

Sam GHC zajmuje 270 MB, a wraz ze wszystkimi bibliotekami i narzędziami, które są razem, zajmuje ponad 500 MB. I tak, to dużo, nawet z podstawowymi bibliotekami i narzędziem do budowania / menedżerem zależności. Platforma programistyczna Java jest mniejsza.

GHC:

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

przeciwko OpenJDK z zależnościami:

$ 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

Ale nadal jest więcej niż 100 MB, a nie 26 MB, gdy piszesz.

Ciężkie rzeczy w ghc6 i ghc6-prof to:

$ 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

Zwróć uwagę, jak duży jest libHSghc-6.12.1_p.a. Więc odpowiedzią wydają się być statyczne wersje linkowania i profilowania dla każdej biblioteki.

śastanin
źródło
9

Domyślam się - dużo, wiele statycznych linków. Każda biblioteka musi łączyć statycznie swoje zależności, które z kolei muszą łączyć statycznie swoje i sofort. I to wszystko jest często kompilowane zarówno z profilowaniem, jak i bez niego, a nawet bez profilowania pliki binarne nie są usuwane, więc zawierają wiele informacji debugera.

sclv
źródło
2
Prawdopodobnie nie miałbym nic przeciwko, gdyby GHC przełączył się na cały program, przekompiluj prawie wszystko model, podobny do jhc. Mógłby nawet skompilować się szybciej, gdyby nie powodował zamiany „ld”.
John L
8

Ponieważ zawiera gcc i kilka bibliotek, wszystkie połączone statycznie.

Przynajmniej w systemie Windows.

Marko
źródło
12
nie, nie na Linuksie. zależy to tylko od gcc. ponieważ Windows nie ma gcc w swojej „dystrybucji”, musi pochodzić z ghc.
comonad
5

Oto podział rozmiaru katalogu na moim pudełku:

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

Wygląda na to, że największy katalog (123 MB) to pliki binarne do kompilacji samego kompilatora. Dokumenty ważą zdumiewające 65 MB. Trzecie miejsce zajmuje Cabal na 41 MB.

Katalog bin ma 33 MB i myślę, że tylko jego część jest technicznie wymagana do tworzenia aplikacji Haskell.

Jakub
źródło
6
Dodam coś do tego: jeśli weźmiesz tylko kompilator barebone i usuniesz wszystko, co nie jest absolutnie potrzebne (jak zbudowanie kompilatora nieprofilowanego, pozbawionego itp.), Możesz zejść do około 5 MB. Ale spróbuj porównać rozmiar kompilatorów z GCC. (Zredagowałem komentarz, więc musiałem go usunąć ... przepraszam)
fuz
5

Krótka odpowiedź jest taka, że ​​wszystkie pliki wykonywalne są statycznie połączone, mogą zawierać informacje o debugowaniu, a biblioteki są zawarte w wielu kopiach. Zostało to już powiedziane przez innych komentatorów.

Dynamiczne łączenie jest możliwe i znacznie zmniejszy rozmiar. Oto przykład Hello.hs:

main = putStrLn "Hello world"

Buduję z GHC 7.4.2 na Windows.

ghc --make -O2daje Hello.exe1105Ks

Bieganie stripna nim pozostawia 630K

ghc --make -O2 -dynamic daje 40K

Po usunięciu pozostawia tylko 13K.

Jego zależności to 5 bibliotek dll o łącznym rozmiarze 9,2 MB po usunięciu i 5,7 MB po usunięciu.

nponeccop
źródło