There are many challenges you must deal to run a program consuming an almost-constant value of CPU (CPU time). Even if you use cpulimit
you must consider at least three elements:
- Which processes must be limited: The current Linux CFS scheduler tries to give the same time to all the processes that demand CPU and have the same priority. Then, if you have two CPU-bounded processes running in a computer with a single core, it will try to give them the same CPU time to both. When you use
cpulimit
you set an upper limit. Your process may use less. In order to set an almost-constant value all the time, you may need to limit the CPU not only of your process but also of all the others.
- Which percentage you try to consume: The CPU percentage reported by
top
and other tools correspond to the percentage used on each core (or thread for hyperthreading CPUs). If you use use tools such as cpulimit
to limit a process to use the 50%, you are limiting the process to the 50% of a core. If you have 8 cores, you must use the value of 400% to limit the CPU consumption to the half of the cores.
- How many cores you try to exercise: Each thread in a process is assigned to a core when it runs. If you need to exercise more than a core, you need to start more processes or threads.
Using cpulimit
cpulimit
sets an upper limit for the CPU consumption of one or more processes. It monitors the process and send signals to the process to suspend their execution if it starts to consume more than the limit. It resumes the process when the CPU consumption goes below the limit.
Consider that you run a CPU-bounded process such as md5sum /dev/zero &
, you may use top
to verify that the process uses the 100% of a CPU and use cpulimit
to limit the CPU consumption. Note that the command returns the process id (pid) of the process. It is 77
in the example
$ md5sum /dev/zero &
[1] 77
To limit the CPU consumption, you may use cpulimit
and the process id reported by the system. The following is an example. You can use -v
to get verbose messages. Note that, even if you set 25% as the limit, the CPU consumed is not 25% all the time, sometimes it goes below (21.30%) and sometimes it goes further (36.87%)
$ sudo cpulimit --verbose --limit=25 --pid=77
4 CPUs detected.
Priority changed to -10
Process 77 detected
%CPU work quantum sleep quantum active rate
26.99% 46144 us 53855 us 49.83%
21.30% 65714 us 34285 us 55.98%
28.47% 47762 us 52237 us 54.39%
36.45% 39202 us 60797 us 57.16%
36.87% 37513 us 62486 us 55.33%
:
The process id (pid) can be used to send signals to the process too. For instance, you can use kill
to send a SIGSTOP
signal and suspend its execution. You can send a SIGCONT
signal to resume the execution.
$ kill -s SIGSTOP 77 # suspend the execution of process 77 (it will use 0% CPU)
$ kill -s SIGCONT 77 # resume the execution of process 77
How cpulimit works
You can get the source code for cpulimit
in Github.
$ git clone https://github.com/opsengine/cpulimit.git
$ cd cpulimit
$ make # compile the code
$ sudo cp src/cpulimit /usr/bin # install the command
Basically, cpulimit
creates a process group whith all the process it controls. You may check the process_group.c
file. It includes functions to create and update that linux process group. In addition, there are other functions to find a process by pid or by name and add them to the group. The update_process_group
function is used to update constantly the CPU consumption of the processes in the group.
In the cpulimit.c
, the limit_process
does all the work. There is an while(1) { ... }
infinite loop that checks the CPU consumed by each process. If the process is consuming more than the limit, it sends a SIGSTOP (suspend) signal. If the process is suspended and using less then the limit, it sends a SIGCONT (resume) signal.
An idea: how to implement your program
I have already seen the source code of "cpulimit" but I didn't find out how to make my c program waste exactly and always for example 60% of the processor!
To create a process that use the 50% of a CPU all the time, you must monitor the other processes running in the same core and limit the time consumed by all these processes. The sum of the CPU used by the other processes in the same core must not exceed 50%. You may define a CPU affinity to set which processes will run on the same core all the time.
$ taskset -p -c 0 77 # make that process 77 use the core 0
You may find some shell scripts that take all the running processes that comply with some criteria and limit their CPU consumption by using cpulimit
. The following is an example that limits all the processes that use more than 20% of the CPU.
#!/bin/bash
while sleep 3 # execute each 3 seconds
do
# get the processes that use more than 20% of CPU
PIDS=`top -b -n1 | tail -n +8 | gawk '$9>20 {print $1}'`
for i in $PIDS
do
# limit the new violating processes to 20%
cpulimit -p $i -l 20 -z &
done
done
Another idea: Using cgroups (?)
As an alternative to cpulimit
, you may explore the use of Process Control Groups (cgroups). These groups are different than the process groups used by the cpulimit
. The cgroup is a feature of the Linux kernel that allows you to set limits to groups of processes. It can be used, for instance, to limit the CPU and network used by administrative processes and reduce the interference of these tasks to the servers running in the same machine.
You may check a solution that limits the CPU usage using cgroup.