User:Pietinger/Tutorials/Optimize compile times

Optimize compile times
We have already two Wiki articles about MAKEOPTS and EMERGE_DEFAULT_OPTS. Why another tutorial ?

I will explain again the usage of these parameters because we have still threads with questions about it. Let us start with a simple configuration:

What does MAKEOPTS="-j8"
As you surely already know you can set the number of compile threads for a single package. It has two limitations:

1. The quantity of your CPU cores. SMT / Hyperthreading can be added if you have allowed it in your kernel configuration (default is "enabled"). I have an Intel i7 with 4 physical cores. Hyperthreading (this is the name from Intel for SMT) gives me 8 logical cores. So, I can use "-j8" as a maximum. Higher values would make all compiles SLOWER.

2. The quantitiy of your installed Memory (RAM). Every compile thread needs RAM for its work. But not every package use the same amount of RAM when compiling it. We have "small" packages which uses only less than 1 GB for every compile job. So, compiling this one with 8 threads would need only less than 8 GB of RAM. We have "monster" packages (e.g. "rust") which needs approximately 4 GB RAM for every compile job. If you emerge these kind of packages you would need 32 GB RAM for 8 compile jobs. If you have only 16 GB RAM installed you will get an OOM abort - Out of memory ! So, Gentoo has a recommendation:

Calculate 2 GB RAM for every compile job !

If you have 32 GB RAM the maximum would be "-j16" ... BUT ...

You can use only the smaller maximum of both limitations !

Examples:

4 cores and 16 GB RAM -> Use "-j4" because of your CPU

8 cores and 16 GB RAM -> Use "-j8"

8 cores and 32 GB RAM -> Use "-j8" because of your CPU

16 cores and 16 GB RAM -> Use "-j8" because of your RAM

16 cores and 32 GB RAM -> Use "-j16"

12 cores and 32 GB RAM -> Use "-j12" because of your CPU

How to handle "monster" packages ?
You have two choices:

1. You can lower MAKEOPTS so every compile will have 4 GB RAM for every compile job (divide your RAM with 4). Please dont laugh, but I use this. Why ? Because I do all my @world updates in the night and I dont wait for it. So, I dont care if it needs 3 hours or 4 hours ... But if you wait for it you can use:

2. Set exceptions for some big packages with /etc/portage/package.env

Here is an example you might use:

Using a tmpfs for Portage's TMPDIR
If you use additionally Portage_TMPDIR_on_tmpfs you must calculate a higher RAM usage. Most packages will need only 1 or 2 GB when compiling. Other packages will need up to 20 GB when compiling them. The question will be now: Shall I give my RAM to my compile jobs or using it for my TMPFS ? In most cases you will be faster when using your RAM for compiling. This means you must make also exceptions for packages using much RAM when compiling them. At minimum you should make a exception for rust:

Now you can add it to your existing exception file:

Using EMERGE_DEFAULT_OPTS
As you surely already know you can set the number of how many competitive packages shall be compiled at the same time. Of course this will only work if you want emerge more than one single package; e.g. when you do an "emerge -u @world". With an EMERGE_DEFAULT_OPTS="--jobs 2" you tell portage to compile the first package of your @world list and at the same time the 2nd package of your @world list. This means it can double now the needed Ressources - RAM and threads. Why you want do this ? The answer is:

Every emerge of a package has different phases. Before a package will be compiled there is a configuration phase. And this configuration phase will ALWAYS use only ONE thread.

If you have two packages for an emerge and you have a MAKEOPTS="-j8" then your system does:

1. Configuring Package 1 with 1 thread working

2. Compiling Package 1 with 8 threads working

3. Configuring Package 2 with 1 thread working

4. Compiling Package 2 with 8 threads working

If you have two (or more) packages for an emerge and you have a MAKEOPTS="-j4" AND EMERGE_DEFAULT_OPTS="--jobs 2" then your system does:

1. Configuring Package 1 and Package 2 with 1 thread for each == 2 threads working

2. As soon as one of them is configured it starts compiling one of them == 5 threads working

3. As soon as the 2nd Package is configured it starts compiling this one also == 8 threads working

4. As soon as one of them is finished it starts a 3rd package - OR - it will compile the 2nd package with 4 threads working

As you can imagine the last situation CAN be faster ... BUT ... it could be also slower if you have one small package AND a 2nd BIG package, because the small package is finished in some seconds and you have only 4 compile threads for your 2nd big package.

So, yes it depends what you want to emerge !

If you want emerge (update) only ONE big package - like libreoffice - with "emerge -1uvD libreoffice" then you will be faster if you set MAKEOPTS to its maximum (see above) and DONT set EMERGE_DEFAULT_OPTS.

If you want to do an "emerge -u @world" with hundreds of packages then using EMERGE_DEFAULT_OPTS can speed up the complete Update (but dont compare the time for compiling a single package with the time needed if you update this package alone).