
Saurabh Nanda
Hi,
We're struggling to get our build pipeline working on CircleCI, which has a 4GB RAM limit. Here are some project stats to set the context:
- 1,200+ modules - 36,315 LoC of Haskell - On the local machine with -O1 -j the build takes approx 5.2 GB of RAM [1]
Trying to build on CircleCI with -O1 -j fails consistently, as expected. However, the behaviour of -M -j -O1 is erratic, at best. Sometimes it magically works, sometimes it fails. A number of times we've seen GHC take 3.5 GB (as reported by `top`), even though the limit was set to 2.5GB. Here are flags that we've tried in various combinations we've tried. None of them is consistent in building / failing:
* -O1 * -j * +RTS -M2621440000 -RTS * +RTS -A32m -RTS * +RTS -n2m -RTS
What is the **real** behaviour of the -M option? How does it interact with -j and -A?
Did you ever make any progress on this, Saurabh? The summary is this: * -j just tells GHC to parallelise compilation across modules. This can increase the maximum heap size needed by the compiler. * -A sets the nursery size; to first order the doesn't affect the maximum heap size, but rather is helpful when running parallel programs (e.g. ghc with -j) to minimize the frequency with which we must garbage-collect. * -M is a bit tricky to define. For one, it defines the maximum heap size beyond which we will terminate. However, we also use it in garbage collector to make various decisions about GC scheduling. I'll admit that I'm not terribly familiar with the details here. Note that -M does not guarantee that GHC will find a way to keep your program under the limit that you provide. It merely ensures that the program doesn't exceed the given size, aborting if necessary. At least this is my understanding. Cheers, - Ben