【问题标题】:How to monitor CPU utilization using POSIX clock() function during runtime?如何在运行时使用 POSIX clock() 函数监控 CPU 利用率?
【发布时间】:2011-08-22 11:24:19
【问题描述】:

是否有任何可靠的方法可以让程序在运行时测量其 CPU 利用率?

我可能必须使用来自time.h 的 POSIX clock() 函数。这个想法是首先使用一些毫秒来设置空闲 CPU 负载(步骤 A),然后设置完整的 CPU 负载(步骤 B),然后启动程序并不断调用 clock()。因此,我可以计算相对于在步骤 A 和步骤 B 上计算的 CPU 利用率,以监控 CPU 利用率的百分比。我假设所有其他后台进程都被忽略了。

但是,我不确定如何仅使用 C89 和 POSIX 正确实现这些步骤 A 和步骤 B,比如 idle() 和 full_load() 函数?

【问题讨论】:

  • 你是在测量你所在进程的CPU利用率,还是单独的进程?
  • @Spudd86:我自己的过程

标签: c time embedded posix clock


【解决方案1】:

当您说“full_load”时,您只需要一个负载下的 CPU 或虚拟内核,一个简单的紧密循环就可以解决问题。当然,它不会使用芯片上的所有晶体管(即,我们不是在谈论“满载”的老化测试),但它会在预定的时间片内使用 CPU ,使用所有可用的时钟周期,没有系统调用会放弃对内核的控制,并可能导致稍后重新调度正在执行的线程。您也可以使用带有信号处理程序的警报来退出循环。这样一来,您就可以在大约一秒钟的执行时间内运行循环(警报的时间并不完全准确......它们很接近,但不会精确到时钟周期)。

此外,对于“空闲”负载部分,您可以执行相同的操作,但使用 sigsuspend() 而不是紧密循环,这将等待警报响起。

所以您的代码可能如下所示:

#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>

static sig_atomic_t alarm_flag = 1;

void alarm_handler(int arg)
{
    alarm_flag = 0;
}

clock_t idle()
{
    //setup the alarm flag
    alarm_flag = 1;

    //setup the signal masks
    sigset_t old_signal_set;
    sigset_t new_signal_set;

    sigemptyset(&old_signal_set);
    sigemptyset(&new_signal_set);

    //block the alarm signal
    sigaddset(&new_signal_set, SIGALRM);
    sigprocmask(SIG_BLOCK, &new_signal_set, &old_signal_set);

    //setup the alarm
    alarm(1);

    clock_t time_before = clock();

    //sit idle while we wait for the alarm to go off
    while(alarm_flag)
        sigsuspend(&old_signal_set);

    clock_t time_after = clock();

    //restore the old signal mask
    sigprocmask(SIG_SETMASK, &old_signal_set, NULL);

    return time_after - time_before;
}

clock_t full_load()
{
    //set the alarm signal
    alarm_flag = 1;

    //set the 1-second alarm
    alarm(1);

    clock_t time_before = clock();

    //loop until the alarm goes off
    while(alarm_flag);

    clock_t time_after = clock();

    return time_after - time_before;
}

int main()
{
    //setup the signal handler for the alarm
    sigset(SIGALRM, alarm_handler);

    //call the functions
    clock_t idle_time = idle();
    clock_t load_time = full_load();

    //... do whatever else you need to-do with this info
    printf("Idle Time: %d\n", (int)idle_time);
    printf("Load Time: %d\n", (int)load_time);

    return 0;
}

请记住,根据 POSIX 标准,clock_t 值的时基应为每秒 100 万个时钟,因此您应该看到“full_load”返回的数字接近这个数字,因为我们要“满载”大约一秒钟。空载应该非常小(当然)。这是我在 Mac Pro 上生成的数字:

Idle Time: 31
Load Time: 1000099

因此,就您可能看到从clock() 返回的时钟周期数而言,这似乎与您正在寻找的内容有些一致。我当然会多次运行此程序并取平均值,以便更好地指示您可能会看到的差异。

【讨论】:

    【解决方案2】:

    我认为这被 CLOCK_VIRTUAL (BSD/HP-UX) 或 Linux 上的 CLOCK_PROCESS_CPUTIME_ID 用于clock_gettime(2) 所涵盖。

    【讨论】:

    • 你不是说CLOCK_PROCESS_CPUTIME_ID
    • 不,我的意思是 CLOCK_VIRTUAL。显然,您只能根据SusV2 指望 CLOCK_REALTIME,而我正在查看 BSD 并选择了错误的。 Linux 使用你的常量,HP-UX 也使用 CLOCK_VIRTUAL。编辑答案。
    【解决方案3】:

    您没有指定 POSIX 的版本,但如果您使用的是 C89,那么它一定很旧。 POSIX.1-2001 aka SUSv3 需要 C99,还有 POSIX.1-2008。

    校准似乎没有必要;只需比较返回单调(更好,但可能不可用)或挂钟时间的值。对于clock(),使用CLOCKS_PER_SEC 定义(如果系统支持XSI 选项,则保证为一百万,但如果仅支持POSIX,则不会)。

    考虑使用getrusage() 而不是clock() 以获得更高的准确性和灵活性。

    getrusage() 函数在早期 POSIX 版本中的 XSI 选项下;更改历史表明它是在第 4 版第 2 版 (SUSv1) 中引入的,并在第 5 版 (SUSv2) 中移至基础,但上面仍然有 XSI 标记。无论如何,它很常见,因为它是 4.2BSD 功能。

    另一个选项是times() 函数。

    【讨论】:

      猜你喜欢
      • 2018-08-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-08
      • 1970-01-01
      相关资源
      最近更新 更多