1.CPU时间分类
vmstat可以显示cpu使用时间的分类统计:
执行指令:vmstat -s 时,实际从/proc/stat节点读取cpu显示,然后进行回显:
内核对应的CPU时间类型有以下几种:
类别 | 说明 |
CPUTIME_USER | 用户空间占用CPU时间 |
CPUTIME_NICE | 高nice进程(低优先级),用户空间占用时间 |
CPUTIME_SYSTEM | 内核态占用CPU时间 |
CPUTIME_SOFTIRQ | 软件中断占用CPU时间 |
CPUTIME_IRQ | 硬中断占用CPU时间(这个没搞懂) |
CPUTIME_IDLE | CPU空闲时间 |
CPUTIME_IOWAIT | CPU等待IO时间 |
CPUTIME_STEAL | Guest OS等待real cpu的时间(虚拟机查看) |
CPUTIME_GUEST | Guest OS 消耗的时间(物理机里查看) |
CPUTIME_GUEST_NICE |
2.内核实现
/*account_process_tick会在每个TICK中断被调用,user_tick从当前CPU工作模式决定
主要计算了各种CPU使用时间
*/
void account_process_tick(struct task_struct *p, int user_tick)
{
u64 cputime, steal;
struct rq *rq = this_rq();
cputime = TICK_NSEC;
if (user_tick)/*统计userspace时间 */
account_user_time(p, cputime);
else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET))
account_system_time(p, HARDIRQ_OFFSET, cputime);/*内核态运行时间 */
else
account_idle_time(cputime);/*CPU空闲时间 */
}
/* 用户时间统计
这里把高nice(低优先级)进程时间进行区分。
*/
void account_user_time(struct task_struct *p, u64 cputime)
{
int index;
/* 把时间累加到当前进程. */
p->utime += cputime;
account_group_user_time(p, cputime);//account_process_tick-
index = (task_nice(p) > 0) ? CPUTIME_NICE : CPUTIME_USER;
/* 把cpu时间累计到当前CPU */
task_group_account_field(p, index, cputime);
/* Account for user time used */
acct_account_cputime(p);
}
/*
系统CPU时间实际分三种
Hardirq:硬中断时间
softirq:软中断运行时间
system:内核运行时间
*/
void account_system_time(struct task_struct *p, int hardirq_offset, u64 cputime)
{
int index;
/*hardirq的计算没理解,Linux中断不可重入,也就是这里一直是0(除非NMI抢占了hardirq) */
if (hardirq_count() - hardirq_offset)
index = CPUTIME_IRQ;
else if (in_serving_softirq())/* 软中断时间*/
index = CPUTIME_SOFTIRQ;
else
index = CPUTIME_SYSTEM;/* 内核运行时间*/
account_system_index_time(p, cputime, index);/*更新对应的运行时间 */
}
/*
idle时间分类纯idle和iowait时间
iowait的一点理解:当前CPU存在iowait的进行,且当前cpu处于idle状态
nr_iowait在schedule函数累加.
*/
void account_idle_time(u64 cputime)
{
u64 *cpustat = kcpustat_this_cpu->cpustat;
struct rq *rq = this_rq();
if (atomic_read(&rq->nr_iowait) > 0)
cpustat[CPUTIME_IOWAIT] += cputime;
else
cpustat[CPUTIME_IDLE] += cputime;
}
3.统计精度
由于CPU统计时间是在每个TICK中断中,而且把整个TICK时间,都计算到当前进程,那么在一个TICK周期,可能发生:
1. 一个进程多次在用户态和内核态切换,而最终会把整个tick时间计算在用户态或者内核态
2.多个进程在TICK周期内运行过.而最终会把真个tick时间计算在当前进程.
结论:各种CPUTIME的统计精度是TICK,且并不准确, 只能大体反应CPU运行情况.但是这种统计,并不影响我们分析问题.