85

在我的桌面上,我有一个小部件可以告诉我当前的 CPU 使用率。它还显示了我的两个核心中的每一个的使用情况。

我一直想知道,CPU 是如何计算出它使用了多少处理能力的?此外,如果 CPU 在进行一些密集计算时挂起,它(或处理此活动的任何东西)如何检查使用情况而不会被挂起?

4

8 回答 8

74

当没有其他任务可以运行时,有一个称为空闲任务的特殊任务运行。% 使用率只是我们没有运行空闲任务的时间百分比。操作系统将保持运行空闲任务所花费的总时间:

  • 当我们切换到空闲任务时,设置 t = 当前时间
  • 当我们从空闲任务切换时,将(当前时间 - t)添加到运行总数中

如果我们将运行总 n 秒的两个样本分开,我们可以计算这 n 秒用于运行空闲任务的百分比为 (第二个样本 - 第一个样本)/n

请注意,这是操作系统所做的,而不是 CPU。任务的概念在 CPU 层面是不存在的!(实际上,空闲任务会使用 HLT 指令使处理器进入睡眠状态,因此 CPU 确实知道何时不使用它)

至于第二个问题,现代操作系统是抢先式多任务的,这意味着操作系统可以随时从你的任务中切换出来。操作系统实际上是如何从您的任务中窃取 CPU 的?中断:http ://en.wikipedia.org/wiki/Interrupt

于 2010-09-20T02:27:38.540 回答
33

CPU 不会自己进行使用率计算。它可能具有使该任务更容易的硬件功能,但这主要是操作系统的工作。所以显然实现的细节会有所不同(尤其是在多核系统的情况下)。

一般的想法是查看 CPU 需要做的事情的队列有多长。操作系统可能会定期查看调度程序以确定它必须做的事情的数量。

这是 Linux 中的一个函数(从 Wikipedia 中提取),它执行所述计算

#define FSHIFT   11  /* nr of bits of precision */
#define FIXED_1  (1<<FSHIFT) /* 1.0 as fixed-point */
#define LOAD_FREQ (5*HZ) /* 5 sec intervals */
#define EXP_1  1884  /* 1/exp(5sec/1min) as fixed-point */
#define EXP_5  2014  /* 1/exp(5sec/5min) */
#define EXP_15 2037  /* 1/exp(5sec/15min) */

#define CALC_LOAD(load,exp,n) \
    load *= exp; \
    load += n*(FIXED_1-exp); \
    load >>= FSHIFT;

unsigned long avenrun[3];

static inline void calc_load(unsigned long ticks)
{
    unsigned long active_tasks; /* fixed-point */
    static int count = LOAD_FREQ;

    count -= ticks;
    if (count < 0) {
        count += LOAD_FREQ;
        active_tasks = count_active_tasks();
        CALC_LOAD(avenrun[0], EXP_1, active_tasks);
        CALC_LOAD(avenrun[1], EXP_5, active_tasks);
        CALC_LOAD(avenrun[2], EXP_15, active_tasks);
    }
}

至于您问题的第二部分,大多数现代操作系统都是多任务的。这意味着操作系统不会让程序占用所有的处理时间,并且它自己没有任何处理时间(除非你让它这样做)。换句话说,即使应用程序出现挂起,操作系统仍然可以为自己的工作占用一些时间。

于 2010-09-20T01:22:14.390 回答
20

要获取 CPU 使用率,请定期对处理时间进行采样,并找出差异。

例如,如果这些是进程 1 的 CPU 时间:

kernel: 1:00:00.0000
user:   9:00:00.0000

然后你在两秒钟后再次获得它们,它们是:

kernel: 1:00:00.0300
user:   9:00:00.6100

您减去内核时间(差为0.03)和用户时间(0.61),将它们加在一起(0.64),然后除以 2 秒的采样时间(0.32)。

所以在过去的两秒内,该进程平均使用了 32% 的 CPU 时间。

获取此信息所需的特定系统调用(显然)在每个平台上都不同。在 Windows 上,您可以使用GetProcessTimesGetSystemTimes ,如果您想要获取已用或空闲 CPU 时间的快捷方式。

于 2010-09-20T01:38:36.817 回答
8

一种方法如下:

选择一个采样间隔,比如每 5 分钟(300 秒)的实际经过时间。你可以从gettimeofday.

获取您在那 300 秒内使用的处理时间。您可以使用times()调用来获取此信息。那将是,您从上一个时间间隔保存的处理时间new_process_time - old_process_time在哪里。old_process_time

你的 cpu 百分比是(process_time/elapsed_time)*100.0 你可以设置一个警报,每 300 秒向你发出信号以进行这些计算。

我有一个进程,我不想使用超过某个目标 cpu 百分比。这种方法效果很好,与我的系统监视器非常吻合。如果我们使用过多的 cpu,我们会睡一会儿。

于 2012-10-06T21:18:22.193 回答
2

有很多方法可以做到:

处理器维护了几个衡量性能的计数器,您可以使用 Papi 接口访问它们。例如这里是一个简单的介绍:http: //blogs.oracle.com/jonh/entry/performance_counter_generic_events

也:http ://www.drdobbs.com/tools/184406109

您可能想要的计数器是 PAPI_TOT_CYC,它是繁忙周期数(如果我没记错的话)

于 2010-09-20T01:22:11.287 回答
2

这是我对类似代码的一点接触的基本理解。任务管理器之类的程序或您的小部件访问系统调用(例如 NtQuerySystemInformation())并使用从操作系统收集的信息来简单计算 CPU 空闲或被使用的时间百分比(在标准时间内)。CPU 知道它什么时候是空闲的,因此它可以确定它什么时候不是空闲的。这些程序确实会被阻塞……当我的笔记本电脑的任务管理器在计算 CPU 使用率达到 100% 时,它会一直冻结。

可以在 MSDN 网站上找到一段很酷的示例代码,其中显示了用于计算一组指令的 CPU 使用率的函数调用:http: //msdn.microsoft.com/en-us/library/aa364157 (VS.85).aspx

这些系统调用所做的是访问我相信的内核代码......这超出了我的理解范围。

于 2010-09-20T01:28:13.627 回答
1

嗯,据我所知,有一个巨人

while(true){}

操作系统启动的循环。您的流程是在该循环中管理的。它允许外部代码以块的形式直接在处理器上执行。毫不夸张地说,这是对实际情况的超级简化。

于 2010-09-20T01:24:05.807 回答
0
  1. CPU 不会“挂起”,它只是以峰值容量运行,这意味着它每秒处理的指令数量与它的物理能力一样多。计算 CPU 使用率的进程是其中的一些指令。如果应用程序试图以比 CPU 能力更快的速度执行操作,那么它们只会被延迟,因此会“挂起”。

  2. CPU 利用率的计算基于总可用利用率。所以如果一个 CPU 有两个核心,一个核心有 30% 的使用率,另一个是 60%,那么整体的利用率是 45%。您还可以查看每个单独核心的使用情况。

于 2018-01-03T18:01:42.367 回答