在我的桌面上,我有一个小部件可以告诉我当前的 CPU 使用率。它还显示了我的两个核心中的每一个的使用情况。
我一直想知道,CPU 是如何计算出它使用了多少处理能力的?此外,如果 CPU 在进行一些密集计算时挂起,它(或处理此活动的任何东西)如何检查使用情况而不会被挂起?
在我的桌面上,我有一个小部件可以告诉我当前的 CPU 使用率。它还显示了我的两个核心中的每一个的使用情况。
我一直想知道,CPU 是如何计算出它使用了多少处理能力的?此外,如果 CPU 在进行一些密集计算时挂起,它(或处理此活动的任何东西)如何检查使用情况而不会被挂起?
当没有其他任务可以运行时,有一个称为空闲任务的特殊任务运行。% 使用率只是我们没有运行空闲任务的时间百分比。操作系统将保持运行空闲任务所花费的总时间:
如果我们将运行总 n 秒的两个样本分开,我们可以计算这 n 秒用于运行空闲任务的百分比为 (第二个样本 - 第一个样本)/n
请注意,这是操作系统所做的,而不是 CPU。任务的概念在 CPU 层面是不存在的!(实际上,空闲任务会使用 HLT 指令使处理器进入睡眠状态,因此 CPU 确实知道何时不使用它)
至于第二个问题,现代操作系统是抢先式多任务的,这意味着操作系统可以随时从你的任务中切换出来。操作系统实际上是如何从您的任务中窃取 CPU 的?中断:http ://en.wikipedia.org/wiki/Interrupt
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);
}
}
至于您问题的第二部分,大多数现代操作系统都是多任务的。这意味着操作系统不会让程序占用所有的处理时间,并且它自己没有任何处理时间(除非你让它这样做)。换句话说,即使应用程序出现挂起,操作系统仍然可以为自己的工作占用一些时间。
要获取 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 上,您可以使用GetProcessTimes或GetSystemTimes ,如果您想要获取总已用或空闲 CPU 时间的快捷方式。
一种方法如下:
选择一个采样间隔,比如每 5 分钟(300 秒)的实际经过时间。你可以从gettimeofday
.
获取您在那 300 秒内使用的处理时间。您可以使用times()
调用来获取此信息。那将是,您从上一个时间间隔保存的处理时间new_process_time - old_process_time
在哪里。old_process_time
你的 cpu 百分比是(process_time/elapsed_time)*100.0
你可以设置一个警报,每 300 秒向你发出信号以进行这些计算。
我有一个进程,我不想使用超过某个目标 cpu 百分比。这种方法效果很好,与我的系统监视器非常吻合。如果我们使用过多的 cpu,我们会睡一会儿。
有很多方法可以做到:
处理器维护了几个衡量性能的计数器,您可以使用 Papi 接口访问它们。例如这里是一个简单的介绍:http: //blogs.oracle.com/jonh/entry/performance_counter_generic_events
也:http ://www.drdobbs.com/tools/184406109
您可能想要的计数器是 PAPI_TOT_CYC,它是繁忙周期数(如果我没记错的话)
这是我对类似代码的一点接触的基本理解。任务管理器之类的程序或您的小部件访问系统调用(例如 NtQuerySystemInformation())并使用从操作系统收集的信息来简单计算 CPU 空闲或被使用的时间百分比(在标准时间内)。CPU 知道它什么时候是空闲的,因此它可以确定它什么时候不是空闲的。这些程序确实会被阻塞……当我的笔记本电脑的任务管理器在计算 CPU 使用率达到 100% 时,它会一直冻结。
可以在 MSDN 网站上找到一段很酷的示例代码,其中显示了用于计算一组指令的 CPU 使用率的函数调用:http: //msdn.microsoft.com/en-us/library/aa364157 (VS.85).aspx
这些系统调用所做的是访问我相信的内核代码......这超出了我的理解范围。
嗯,据我所知,有一个巨人
while(true){}
操作系统启动的循环。您的流程是在该循环中管理的。它允许外部代码以块的形式直接在处理器上执行。毫不夸张地说,这是对实际情况的超级简化。
CPU 不会“挂起”,它只是以峰值容量运行,这意味着它每秒处理的指令数量与它的物理能力一样多。计算 CPU 使用率的进程是其中的一些指令。如果应用程序试图以比 CPU 能力更快的速度执行操作,那么它们只会被延迟,因此会“挂起”。
CPU 利用率的计算基于总可用利用率。所以如果一个 CPU 有两个核心,一个核心有 30% 的使用率,另一个是 60%,那么整体的利用率是 45%。您还可以查看每个单独核心的使用情况。