要运行一个消耗几乎恒定值 CPU(CPU 时间)的程序,您必须应对许多挑战。即使您使用cpulimit,您也必须考虑至少三个要素:
-
必须限制哪些进程: 当前的 Linux CFS 调度程序尝试将相同的时间分配给所有需要 CPU 且具有相同优先级的进程。然后,如果您有两个受 CPU 限制的进程在具有单核的计算机上运行,它将尝试为它们提供相同的 CPU 时间。当您使用
cpulimit 时,您设置了一个上限。您的过程可能会使用更少。为了始终设置一个几乎恒定的值,您可能不仅需要限制您的进程的 CPU,还需要限制所有其他进程的 CPU。
-
您尝试消耗的百分比:
top 和其他工具报告的 CPU 百分比对应于每个内核(或超线程 CPU 的线程)上使用的百分比。如果您使用诸如cpulimit 之类的工具来限制进程使用 50%,那么您就是将进程限制为内核的 50%。如果您有 8 个内核,则必须使用 400% 的值来将 CPU 消耗限制为内核的一半。
-
您尝试使用多少核心: 进程中的每个线程在运行时都会分配给一个核心。如果你需要锻炼的不仅仅是一个核心,你需要启动更多的进程或线程。
使用 cpulimit
cpulimit 设置一个或多个进程的 CPU 消耗上限。如果它开始消耗超过限制,它会监视进程并向进程发送信号以暂停其执行。当 CPU 消耗低于限制时,它会恢复进程。
假设您运行一个 CPU 受限的进程,例如 md5sum /dev/zero &,您可以使用 top 来验证该进程是否使用了 100% 的 CPU,并使用 cpulimit 来限制 CPU 消耗。请注意,该命令返回进程的进程 ID (pid)。示例中为77
$ md5sum /dev/zero &
[1] 77
为了限制CPU消耗,你可以使用cpulimit和系统报告的进程id。下面是一个例子。您可以使用-v 获取详细消息。请注意,即使您将 25% 设置为限制,CPU 消耗也不会一直为 25%,有时会低于 (21.30%),有时会进一步 (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%
:
进程 id (pid) 也可用于向进程发送信号。例如,您可以使用kill 发送SIGSTOP 信号并暂停其执行。您可以发送SIGCONT 信号以恢复执行。
$ 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
cpulimit 的工作原理
您可以在Github 中获取cpulimit 的源代码。
$ git clone https://github.com/opsengine/cpulimit.git
$ cd cpulimit
$ make # compile the code
$ sudo cp src/cpulimit /usr/bin # install the command
基本上,cpulimit 会创建一个包含它控制的所有进程的进程组。您可以查看process_group.c 文件。它包括创建和更新该 linux 进程组的功能。此外,还有其他功能可以通过 pid 或按名称查找进程并将其添加到组中。 update_process_group 函数用于不断更新组中进程的 CPU 消耗。
在cpulimit.c 中,limit_process 完成所有工作。有一个while(1) { ... } 无限循环检查每个进程消耗的CPU。如果进程消耗的资源超过限制,它会发送一个 SIGSTOP(挂起)信号。如果进程被挂起并且使用少于限制,它会发送一个 SIGCONT(恢复)信号。
一个想法:如何实施您的程序
我已经看过“cpulimit”的源代码,但我不知道如何让我的 c 程序准确且总是浪费例如 60% 的处理器!
要创建一个始终使用 50% CPU 的进程,您必须监视在同一内核中运行的其他进程并限制所有这些进程所消耗的时间。同一核心内其他进程使用的 CPU 总和不得超过 50%。您可以定义 CPU 亲和性来设置哪些进程将始终在同一个内核上运行。
$ taskset -p -c 0 77 # make that process 77 use the core 0
您可能会发现一些shell scripts 使用cpulimit 获取所有符合某些标准的正在运行的进程并限制它们的CPU 消耗。下面是一个限制所有使用超过 20% 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
另一个想法:使用 cgroups (?)
作为cpulimit 的替代方案,您可以探索Process Control Groups (cgroups) 的使用。这些组不同于cpulimit 使用的进程组。 cgroup 是 Linux 内核的一项功能,允许您设置进程组的限制。例如,它可以用来限制管理进程使用的 CPU 和网络,并减少这些任务对运行在同一台机器上的服务器的干扰。
您可以查看solution that limits the CPU usage using cgroup。