Usage
Exactly one target: a pid (-p), an executable name or path (-e), or a command that cpulimit starts and limits. man cpulimit is the reference; this page adds the reasoning and examples.
Synopsis
cpulimit [OPTIONS...] -p PID
cpulimit [OPTIONS...] -e NAME_OR_PATH
cpulimit [OPTIONS...] [--] COMMAND [ARGS...]Options
| Option | Meaning |
|---|---|
-l, --limit=N | Allowed CPU in percent of one CPU, 0 to 100 × the number of CPUs (150 means one and a half CPUs). Required. |
-p, --pid=N | Limit this pid. Implies -z. |
-e, --exe=FILE | Limit the process whose executable has this name (matched against the basename) or this full path. cpulimit never selects itself. |
-c, --chunk-size=N | Control chunk in microseconds, 1 to 1000000, default 100000. Shorter chunks follow the limit more closely and cost more wake-ups. |
-i, --include-children | Also limit the descendants of the target. They are found again on every cycle, so children started later are picked up. |
-m, --minimum-limited-cpu=M | Processes using less than M of one CPU (0.05 means 5 %) are left running instead of being stopped. Note the unit differs from -l. Default 0. |
-z, --lazy | Exit when there is no target or it terminates, instead of waiting for one to appear. |
-d, --daemon | Detach and run in the background. Not valid with a command. |
-s, --syslog | Also send events to syslog, facility LOG_DAEMON. |
-P, --pidfile=FILE | Write the daemon's pid (needs -d). A pid file naming a live process is refused, a stale one is replaced, and it is removed on a normal exit. |
--no-lock | Allow a target that another cpulimit already limits. |
--no-boost | Do not try to raise cpulimit's own scheduling priority. |
-v, -V, -h | Verbose statistics, print the version, print the usage text (-h exits 1, as every release has). |
Numbers are parsed strictly: -l 5x, -l abc, an empty value, and values out of range are usage errors (exit 1), not silently read as 5 or 0.
Examples
An existing process
cpulimit -l 50 -p 1234 # half a CPU; exits when pid 1234 ends
cpulimit -l 200 -p 1234 # two CPUs' worth, for a multi-threaded targetBy name
cpulimit -l 25 -e ffmpeg # waits for ffmpeg to appear, limits it
cpulimit -l 25 -z -e ffmpeg # exits at once if there is none
cpulimit -l 25 -i -e make # make and everything it spawnsA command
cpulimit -l 80 -- make -j8 # exit status is make's
cpulimit -l 30 -i -- ./build.sh # the script and its childrenIn command mode there is exactly one cpulimit process; the command is its child. Its exit status comes straight from waitpid(), and if it was killed by a signal the raw wait status is returned, as before.
As a service
cpulimit -d -s -P /run/cpulimit.pid -l 30 -e backup
kill "$(cat /run/cpulimit.pid)" # SIGTERM: releases the target, exits 0Exit statuses
| Status | Meaning |
|---|---|
0 | Released the target after SIGINT, SIGTERM, SIGHUP or SIGQUIT; -z found no target; -V. |
1 | Usage error, a target that is already limited, or a target that is cpulimit itself. Also -h. |
2 | The control loop failed (an allocation or a system call). |
| other | In command mode: the command's own status. |
Signals
SIGINT, SIGTERM, SIGHUP and SIGQUIT make cpulimit send SIGCONT to every process it has been limiting, then exit. A signal that was already ignored when cpulimit started (for example SIGHUP under nohup) stays ignored. SIGPIPE is ignored, so a closed stdout cannot kill the limiter while a target is stopped.
One limiter per target
Two limiters on the same process undo each other's stop and continue, so the second is refused (exit 1) with the pid of the first. The lock is an fcntl record lock in $XDG_RUNTIME_DIR/cpulimit/ (or /tmp/cpulimit-<euid>/), keyed on pid and start time. It disappears with its holder, even on SIGKILL, so there are no stale locks. --no-lock overrides it.
Permissions
cpulimit signals the target, so it needs the privilege to do so: the same user, or root. Started on a process of another user without that privilege, -p prints Process found but you aren't allowed to control it, touches nothing, and waits or (with -z, which -p implies) exits. A process that becomes unsignalable while it is being limited is treated like one that has exited: it is dropped from the group, and the only trace is a line with -v (SIGSTOP failed. Process N dead!).
Unless --no-boost is given, cpulimit also tries to lower its own nice value so its timing is not delayed by the load it is limiting. This needs privilege; when it is refused, cpulimit carries on and says so only with -v (Cannot change priority. Run as root or renice for best results.). It never changes the nice value, I/O class, CPU affinity or scheduling policy of the target; the integration tests check that for nice, ionice, taskset and chrt.
Choosing -c and -m
- The default chunk of 100 ms is a good start. Shorter chunks smooth the load of the target at the price of more wake-ups; very long chunks make a stalled target visible to users and timeouts.
-mis for trees with many idle children (-i): idle processes are not worth a stop/continue every chunk, and leaving them running costs nothing because they use almost no CPU.