当谈到cpu利用率时,我在说什么

先来看,p->utime和p->stime分别是update_processtime里打点得到的用户态、内核态次数,是计算cpu利用率的关键。

if (hardirq_count() - hardirq_offset || (p->flags & PF_HARDIRQ))
		cpustat->irq = cputime64_add(cpustat->irq, tmp);
	else if (softirq_count() || (p->flags & PF_SOFTIRQ))
		cpustat->softirq = cputime64_add(cpustat->softirq, tmp);
	else if (p != rq->idle) {
		cpustat->system = cputime64_add(cpustat->system, tmp);
		cpuacct_charge(p, cputime);
	} else if (atomic_read(&rq->nr_iowait) > 0)
		cpustat->iowait = cputime64_add(cpustat->iowait, tmp);
	else
		cpustat->idle = cputime64_add(cpustat->idle, tmp);
	/* Account for system time used */
	acct_update_integrals(p);
如果被时钟中断打断时进程处于用户态,则累加此次tick到p->user, 如果p的nice比较好,则将其加到cpu的
nice统计里,否则就加到本cpu的user字段。 也就是说如果p的优先级比较高,那么就统计到cpu
的user字段,这样可以排除一些init,swapper进程的影响,即只统计有效用户进程。

如果进程被时钟中断打断时,处于内核态,则累加p->system。p可能在多种情况下,被时钟中断打断。
第一种是p处于硬中断时(包括p本身是线程化的硬中断,以及中断嵌套),则累加本次tick到本cpu的irq字段;
否则,再检查是不是处于软中断上下文(softirq_count()不为0,或者p本身就是线程化的软中断),如果是的话
就累加到系统软中断上下文;如果上述两个情况都不满足,再检查当前进程是否为idle,不是的话,就说明
是在系统调用上下文,累加到当前cpu的system字段里;如果是idle,则检查当前cpu是否处于iowait状态导致的sleep
,如果是的话则累加到iowait,最后如果都不是,那就累加到idle里。

再提出一个概念,反应到/proc/stat或者/proc/pid/stat中的运行时间,都是clock_t单位。
也就是说,都是用户tick数。什么是用户tick数?假设USER_HZ为100,那么1秒中来的用户tick数就应该是10个。
具体应用场景是,在规定时间内,假设进程执行了sum_exec_runtime毫秒,那么用户态就应该经历了sum_exec_runtime/10
个tick。

1)将p->utime,p->stime转换为clock_t单位的utime。
2)然后通过将p->se.sum_exec_runtime纳秒转换成以USER_HZ(一般为100)为单位的tick数(即clock_t)。
3)根据utime和total的比例,算出实际进程的进程时间(还是clock_t单位)
实际上,个人觉得,第1步没有必要将其转换为clock_t格式,而直接算比例就可以了。

clock_t task_utime(struct task_struct *p)
{
	clock_t utime = cputime_to_clock_t(p->utime),
		total = utime + cputime_to_clock_t(p->stime);
	u64 temp;

	/*
	 * Use CFS's precise accounting:
	 */
	temp = (u64)nsec_to_clock_t(p->se.sum_exec_runtime);

	if (total) {
		temp *= utime;
		do_div(temp, total);
	}
	utime = (clock_t)temp;

	p->prev_utime = max(p->prev_utime, clock_t_to_cputime(utime));

	return cputime_to_clock_t(p->prev_utime);
}


你可能感兴趣的:(当谈到cpu利用率时,我在说什么)