【问题标题】:Limit CPU use of C program限制 C 程序的 CPU 使用
【发布时间】:2014-04-25 12:25:58
【问题描述】:

我需要编写一个消耗固定部分处理器的程序,我正在考虑更改优先级,但这种方法不会将 CPU 使用限制为固定百分比,例如 60%。 谢谢!

【问题讨论】:

  • 只是澄清一下,比如 VBox 的执行上限?
  • 这不是您在 C 代码中控制的东西 - 执行时间完全取决于操作系统。您已将此帖子标记为 unix - 我假设您在谈论 Linux,在这种情况下,这可能是一个骗局:stackoverflow.com/questions/386945/…
  • @Oliver Matthews,是的,我说的是 Linux(抱歉打错了标签),我需要的是在没有任何其他外部命令或程序的情况下限制我的程序的 CPU 使用。 @ mypal125,我想让运行我的程序(我的程序)的进程浪费 CPU 的固定部分/分数,所以我不想定义最大使用分数,但我总是需要一个固定使用分数...
  • 随着多处理器、多核机器的广泛可用性,您不能在 1 个虚拟 CPU 上使用 100%CPU 吗?那么它就是main(){while(1){}}。祝你好运。
  • 我想知道为什么这个问题被否决了?这似乎是一个合理的问题,但对谷歌来说并不一定是一件容易的事情!

标签: c linux cpu-usage


【解决方案1】:

取决于您希望此限制的时间段 - 如果您希望绝对限制永远不会使用超过 60%(或更少),那么它无法可靠地满足您的要求(不使用任何其他外部命令或程序)——归根结底,操作系统会决定您获得多少时间。

但是,如果您平均而言只想要它,那么您可能会这样做(有几个限制)。 基本上,设置一个循环,在系统启动时记录系统时间,执行少量工作,然后记录新系统时间。现在让进程休眠 2/3(60%)的差异。您将需要维护一个缓冲区,因为无法确保您不会睡得更久。 此外,如果您正在运行一个可抢占的内核(现在大多数都是这样),那么您就会遇到麻烦,因为循环执行本身可能会被接管。

tl;dr:你可以在没有外部代码的情况下大致做到这一点,但它充其量只是大致正确。

【讨论】:

  • 这是我的代码#include<stdio.h> 987654322 int main(){ 987654324 struct timeval tv1, tv2; 987654326 while(1){ 987654328 ms = (tv2.tv_sec-tv1.tv_sec)*1000000+(tv2.tv_usec-tv1.tv_usec); 987654330 //puts("*\n"); 987654332 return EXIT_SUCCESS; } 但是top总是显示0%的CPU使用率
  • @user3192021;欢迎来到stackoverflow。你的评论属于你上面的问题,粘贴格式化代码,用鼠标选择,点击编辑框左上角的{}工具。不要指望读者会在 cmets 中关注一长串(尚未)消息。祝你好运。
  • 当您的程序执行sleep 时,它不会使用 CPU,并且会显示 0% 的 CPU 使用率。
【解决方案2】:

要运行一个消耗几乎恒定值 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

【讨论】:

    【解决方案3】:

    这是一个讨论获取 CPU 统计信息的几种方法的线程:http://www.cyberciti.biz/tips/how-do-i-find-out-linux-cpu-utilization.html。至少,您可以通过读取 /sys/devices/xxx/cpuN 以编程方式获取 CPU 利用率。

    有很多方法可以做你想做的事,但你没有给我们足够的细节来说明你的目标。如果您想影响能源消耗,您可以简单地最大化一个处理器(减少其他应用程序的负载)。如果你想影响一个应用程序的执行,你需要更聪明。如果您想在处理器上放置一个通用的固定负载而不管您的应用程序套件是什么,它可能会变得非常复杂,我们需要了解更多关于您的用例的信息。

    除此之外,您在尝试时还应该注意其他一些事项。首先是你需要决定你希望你的利用率有多细。这就是我的意思。 CPU 利用率在一个窗口内进行评估。平均利用率可能为 60%,但如果您的利用率计算窗口为 2 秒,您可能正在计算 0.6*2 或 1.2 秒,空闲时间为 0.8 秒。在现代处理器上,0.8 秒是 long 时间。在弄清楚你想要什么谷物之后,你就可以使用 Oliver 建议的技术了。另一种技术是测量当前的 CPU 利用率,然后计算您需要睡眠与工作的毫秒数之比。然后执行一个简单的循环并调用你最喜欢的睡眠函数。 (关于计算循环的警告。现代编译器擅长优化,可能会显着减少计算循环所需的时间长度。)您还需要确保这种利用率分布在所有处理器上。我不会涉及由于超线程而可能出现的并发症。

    当您确定粒度时,请注意大多数 Linux 系统(或任何其他系统)上的时间分辨率都是 >10 毫秒,无论 API 允许什么。

    Re:最大化一个 CPU 上的负载。我怀疑这对你有用。如果您的应用程序是单线程的,那么将负载放在另一个 CPU 上不会影响您的应用程序的性能。如果您的应用程序的线程非常重,它可能仍然无法运行,因为某些操作系统会尝试平衡 CPU 之间的负载,这意味着它可能仍会将您的线程从负载更重的 CPU 移开,并且再次不会影响您的应用程序以你想要的方式。

    总之,我们必须了解更多才能有机会提供解决方案。

    PS I 您在对 Oliver 的评论中使用的代码不起作用,因为您没有进行任何处理。

    【讨论】:

    • 感谢您的帖子,但我的目标根本不是获取 CPU 统计信息,我需要的是开发一个 c 程序并执行它,然后去看看我的程序消耗了多少 CPU,我会一旦我选择了这个百分比,就得到“总是”(由于抢占)一个固定的百分比。该程序只是浪费CPU(循环),无需开发特殊的东西,只希望它程序浪费固定百分比的CPU
    • 一种“CPU Burner”。
    【解决方案4】:

    我猜https://github.com/opsengine/cpulimit 可以为您完成这项工作。它是开源的,所以也请查看源代码并 fork 它!

    【讨论】:

    • 我已经看过 "cpulimit" 的源代码,但是我没有找到如何让我的 c 程序准确且总是浪费例如 60% 的处理器!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 2017-01-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-26
    • 1970-01-01
    相关资源
    最近更新 更多