[GHC] #13110: GHC API allocates memory which is never GC'd

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.1 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- I've run into a very strange sort of memory leak it seems. GHC seems to manage to allocate memory which I cannot get rid of no matter what I try even after all references have disappeared. The allocated memory doesn't show up in heap profiles but is still visibly allocated (as seen in ps or pmap). I discovered this while investigating reports of large memory usage in ghc-mod where this issue is forcing us to dump completion information in a separate process to avoid the allocated memory sticking around for the rest of the user's session. The attached test case demonstrates this problem by first calling `getModuleInfo` for all modules in all visible packages and then just looping forever in `main`. I would expect all memory GHC allocated to be GC'd at this point but this does not happen. When run as {{{ $ ./Leaky -hide-all-packages }}} the test case consumes around 30M of memory on my system, if we however load some large package, say GHC itself {{{ $ ./Leaky -hide-all-packages -package ghc }}} the program will consume around 2-300M of memory which are never deallocated. The behaviour is not related to the loaded package though I tried it with `Cabal` too with the same result though smaller memory usage. At first I thought this might be related to large CAFs with IORefs inside not being GCd for some reason so I tried calling `resetCAFs` from the RTS before entering the loop. This however makes no difference whatsoever. I also tried forcing a major GC just to be save to no avail. Next I speculated that maybe the allocated memory is beyond the GC's control (malloc()ed or something) but looking at the memory map of the process with `pmap $(pgrep Leaky)` that the majority of the memory usage I'm seeing comes from address `0x0000000200000000` which is where the RTS allocates memory AFAIK. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by DanielG): * Attachment "Leaky.hs" added. Test case -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Description changed by DanielG: @@ -43,3 +43,3 @@ - process with `pmap $(pgrep Leaky)` that the majority of the memory usage - I'm seeing comes from address `0x0000000200000000` which is where the RTS - allocates memory AFAIK. + process with `pmap $(pgrep Leaky)` I can see that the majority of the + memory usage I'm seeing comes from address `0x0000000200000000` which is + where the RTS allocates memory AFAIK. New description: I've run into a very strange sort of memory leak it seems. GHC seems to manage to allocate memory which I cannot get rid of no matter what I try even after all references have disappeared. The allocated memory doesn't show up in heap profiles but is still visibly allocated (as seen in ps or pmap). I discovered this while investigating reports of large memory usage in ghc-mod where this issue is forcing us to dump completion information in a separate process to avoid the allocated memory sticking around for the rest of the user's session. The attached test case demonstrates this problem by first calling `getModuleInfo` for all modules in all visible packages and then just looping forever in `main`. I would expect all memory GHC allocated to be GC'd at this point but this does not happen. When run as {{{ $ ./Leaky -hide-all-packages }}} the test case consumes around 30M of memory on my system, if we however load some large package, say GHC itself {{{ $ ./Leaky -hide-all-packages -package ghc }}} the program will consume around 2-300M of memory which are never deallocated. The behaviour is not related to the loaded package though I tried it with `Cabal` too with the same result though smaller memory usage. At first I thought this might be related to large CAFs with IORefs inside not being GCd for some reason so I tried calling `resetCAFs` from the RTS before entering the loop. This however makes no difference whatsoever. I also tried forcing a major GC just to be save to no avail. Next I speculated that maybe the allocated memory is beyond the GC's control (malloc()ed or something) but looking at the memory map of the process with `pmap $(pgrep Leaky)` I can see that the majority of the memory usage I'm seeing comes from address `0x0000000200000000` which is where the RTS allocates memory AFAIK. -- -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by DanielG): * version: 8.0.1 => 8.0.2 Old description:
I've run into a very strange sort of memory leak it seems. GHC seems to manage to allocate memory which I cannot get rid of no matter what I try even after all references have disappeared. The allocated memory doesn't show up in heap profiles but is still visibly allocated (as seen in ps or pmap).
I discovered this while investigating reports of large memory usage in ghc-mod where this issue is forcing us to dump completion information in a separate process to avoid the allocated memory sticking around for the rest of the user's session.
The attached test case demonstrates this problem by first calling `getModuleInfo` for all modules in all visible packages and then just looping forever in `main`. I would expect all memory GHC allocated to be GC'd at this point but this does not happen.
When run as
{{{ $ ./Leaky -hide-all-packages }}}
the test case consumes around 30M of memory on my system, if we however load some large package, say GHC itself
{{{ $ ./Leaky -hide-all-packages -package ghc }}}
the program will consume around 2-300M of memory which are never deallocated. The behaviour is not related to the loaded package though I tried it with `Cabal` too with the same result though smaller memory usage.
At first I thought this might be related to large CAFs with IORefs inside not being GCd for some reason so I tried calling `resetCAFs` from the RTS before entering the loop. This however makes no difference whatsoever. I also tried forcing a major GC just to be save to no avail.
Next I speculated that maybe the allocated memory is beyond the GC's control (malloc()ed or something) but looking at the memory map of the process with `pmap $(pgrep Leaky)` I can see that the majority of the memory usage I'm seeing comes from address `0x0000000200000000` which is where the RTS allocates memory AFAIK.
New description: I've run into a very strange sort of memory leak it seems. GHC seems to manage to allocate memory which I cannot get rid of no matter what I try even after all references have disappeared. The allocated memory doesn't show up in heap profiles but is still visibly allocated (as seen in ps or pmap). I discovered this while investigating reports of large memory usage in ghc-mod where this issue is forcing us to dump completion information in a separate process to avoid the allocated memory sticking around for the rest of the user's session. The attached test case demonstrates this problem by first calling `getModuleInfo` for all modules in all visible packages and then just looping forever in `main`. I would expect all memory GHC allocated to be GC'd at this point but this does not happen. When run as {{{ $ ./Leaky -hide-all-packages }}} the test case consumes around 30M of memory on my system, if we however load some large package, say GHC itself {{{ $ ./Leaky -hide-all-packages -package ghc }}} the program will consume around 2-300M of memory which is never deallocated. The behaviour is not related to the loaded package though I tried it with `Cabal` too with the same result though smaller memory usage. At first I thought this might be related to large CAFs with IORefs inside not being GCd for some reason so I tried calling `resetCAFs` from the RTS before entering the loop. This however makes no difference whatsoever. I also tried forcing a major GC just to be save to no avail. Next I speculated that maybe the allocated memory is beyond the GC's control (malloc()ed or something) but looking at the memory map of the process with `pmap $(pgrep Leaky)` I can see that the majority of the memory usage I'm seeing comes from address `0x0000000200000000` which is where the RTS allocates memory AFAIK. -- Comment: I can still reproduce this with 8.0.2. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by rwbarton): You should at least run the GC once if you want to return memory to the OS, it doesn't happen magically. If I add a `rts_performMajorGC` after `print "done"` then the stable heap usage of the program reduces to about 110MB. I think it's more or less attributable to the actual 20MB heap usage plus ghc's conservatism in returning memory to the OS (since it will likely just need it again later). I'm not sure where the 20MB leak is coming from, it's apparently a list of `FastString`s but that doesn't narrow it down very much... -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by lelf): * cc: lelf (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by lukexi): * cc: simonmar (added) Comment: Does anyone on specializing in the GHC API have any clues on this? (cc'ing simonmar) (or, ideas on how to track it down, should I get some time to dig back into GHC myself soon) It's a pretty major tax to pay on every program that wants to use the GHC API and also achieve soft-realtime timing, so would love to get it squashed! -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonmar): @rwbarton's comment above is correct. GHC keeps a hash table of strings (the `FastString` table) that is never deallocated. This is likely the 20MB you're seeing. If this is really a problem for you, then we could provide a way via the GHC API to clear the table. (but I'm surprised if this is really a problem, GHC will keep a lot of other data structures while it is being used, such as all the interface files it read) `resetCAFs` only applies to code that is dynamically loaded by the RTS linker, so it's not doing anything in your case - the ghc package is statically linked into your binary. You do need to force a major GC as @rwbarton mentioned to get the RTS to return memory to the OS. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by DanielG): * Attachment "LeakyResetStringTable.hs" added. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by DanielG): I used to think it's the `FastString` table too because some initial profiling data pointed to retainers being in `FastString.<CAF>`. After some experimentation I dropped that hypothesis because 1) the memory consuption didn't change when I cleared the table and 2) the retainers actually disappeared from the profile after I made some changes (the details of which I do not recall) to the testcase to yield the current version. See also https://github.com/DanielG/ghc-mod/issues/834#issuecomment-271056632. FYI I patched GHC to export `string_table` and just re-initialized it before going into the loop. See the attached modified test case `LeakyResetStringTable.hs`. I'm not quite sure where this 20M number is coming from. My memory usage observations are based on [1] and [2] for all inclusive memory usage and Haskell heap only usage respectively. [1]: {{{ echo $(( $(ps -eo size,pid,user,command --sort -size | grep Leaky | head -n1 | cut -d " " -f 1) / 1024 )) }}} [2]: {{{ echo $(( $(pmap $(pgrep Leaky) | grep 200000000 | tr -s ' ' | cut -d ' ' -f 2 | sed 's/K$//') / 1024 )) }}} As far as `rts_performMajorGC` goes I tried that of course which is why included it as a comment in the testcase. I just wasn't sure if it was actually necessary especially since I could reproduce the same memory usage with and without it. Thanks for clarifying that though. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by DanielG): * Attachment "LeakyResetStringTable.hs" added. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by cornuz): Any progress on this? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bgamari): It's not clear to me whether DanielG actually solved his issue or not. The ticket is still open so presumably not. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by DanielG): * Attachment "LeakyResetStringTable2.hs" added. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by DanielG): * Attachment "ghc-expose-string-table.patch" added. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by DanielG): * Attachment "LeakyResetStringTable2.hs" added. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.0.2 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by DanielG): I just tried with master (c7297342a4) and the ghc-8.2 branch (befd937353) and I can still reproduce this. As I said above resetting the string table doesn't seem to improve the steady state memory usage at all. I made the test case a little easier to use and I'm including the patch I used to expose the `string_table`. With `ghc-expose-string-table.patch` applied you can reproduce this in a GHC source tree like so: {{{ $ ./inplace/bin/ghc-stage2 -package ghc LeakyResetStringTable2.hs -rtsopts -with-rtsopts=-T $ ./LeakyResetStringTable gcdetails_live (MB): 0.443450927734375 gcdetails_mem_in_use (MB): 81.0 VmData (MB): 246.2578125 }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by DanielG): * version: 8.0.2 => 8.3 -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:11 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by Phyx-): * cc: phyx- (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:12 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bgamari): Thanks DanielG, this is quite helpful. If I compile with profiling enabled the profile claims that heap size increases to around 100 MB and then immediately decreases back to essentially zero. The GC statistics reported are in line with comment:10: {{{ $ ./LeakyResetStringTable2 +RTS -p -T -hy gcdetails_live (MB): 0.9342498779296875 gcdetails_mem_in_use (MB): 82.0 VmData (MB): 235.83984375 }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:13 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13110: GHC API allocates memory which is never GC'd -------------------------------------+------------------------------------- Reporter: DanielG | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: Component: GHC API | Version: 8.3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by bgamari): Simon says that reverting CAFs will only revert CAFs in objects loaded by the runtime's linker. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13110#comment:14 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC