Suppose, not entirely hypothetically, that you periodically rebuild Firefox from source and that you've discovered that parts of this build process kill your machine due to memory (over)use. You would like to fix this by somehow choking off the total amount of RAM that the whole Firefox build process uses. The relatively simple tool to use for this is a cgroup .
There is probably lots of documentation on the full details of cgroups floating around. This is a practical guide instead.
First we need a cgroup that will actually apply memory limits. Ad-hoc cgroups are created on the fly with
cgcreate
(which is run as
root
):
cgcreate -t cks -a cks -g memory,cpu,blkio:confine
I'm doing some overkill here; in theory we only need to limit memory usage. But who cares. As I found out, it's important to specify both
-t
and
-a
here;
-a
lets us set limits,
-t
lets us actually put something into the new cgroup.
The easiest way to set limits is by writing to files in
/sys/fs/cgroup/
controller
/
path
. Here we have controllers for memory, cpu, and blkio and our path under them is
confine
, so:
cd /sys/fs/cgroup # This is 3 GB echo 3221225472 >memory/confine/memory.limit_in_bytes # only gets half of contended CPU and disk bandwidth # (in theory) echo 512 >cpu/confine/cpu.shares echo 500 >blkio/confine/blkio.weight
(Since we gave ourselves permissions with
-a
, we can set all of these limits directly without being
root
.)
What parameters controllers take is established partly by poking around in
/sys/fs/cgroup
, partly by experimentation, partly by Internet searches, and sometimes from the official kernel documentation . Where limits exist (and work) they may have side effects; for example, limiting total RAM here is going to force a memory-hungry program to swap, using up a bunch of disk IO bandwidth.
(If you want this cgroup and its settings to persist over reboot you can make a suitable entry in
/etc/cgconfig.conf
. On Fedora you may also need to make sure that the
cgconfig
service is enabled.)
Finally we need to actually run our
make
or whatever so that it is put into our new '
confine
' cgroup and it and its children have their total RAM usage limited the way we want. This is done on the fly with
cgexec
(run as ourselves):
cgexec -g memory,cpu,blkio:confine --sticky make
You don't need
--sticky
in various common situations, for example if you're not running the cgroups automatic classification daemon. But I don't think it does any harm to supply it and anyways you may well want to wrap this magic command up in a script so you don't have to remember it.
You can check to see that
cgexec
is properly putting things into cgroups by looking at
/proc/
pid
/cgroup
to see what cgroups a suitable process is part of. In this case you would expect to see
memory:/confine
among the list. Testing whether your actual cgroup controller settings are working and doing what you want is beyond the scope of this entry.
The good news is that this seems to work for me . My Firefox build process has been significantly tamed.
(I've looked at fair share scheduling with cgroups before, which certainly helped here. People have written all of this information down in bits and pieces and partial explanation and Stack Overflow answers and so on, but since I put it together I want to write it down all in one place for later use. (I'm sure there'll be later use.))