计算 App 用户态和内核态占用的 CPU 时间
前言
在之前的文章 EarlGrey 源码阅读(二) 中整理了 iOS 中几种常见的测量程序运行时间的方法,末尾提到了希望有更科学的测量方法——可以计算当前进程分别在用户态和内核态占用 CPU 多长时间。使用 times 或者 getrusage 这两个操作系统提供的方法可以办到了。
正文
times 方法提供一个结构体参数,查询的结果放里面。这个结构体包含当前进程在用户态、内核态占用的 CPU 时间,以及其所有子进程对应的时间。函数的返回值是真实世界的时间值,就是包含了别的进程的时间的意思。精确到 0.01 s。
struct tms {
clock_t tms_utime; /* [XSI] User CPU time */
clock_t tms_stime; /* [XSI] System CPU time */
clock_t tms_cutime; /* [XSI] Terminated children user CPU time */
clock_t tms_cstime; /* [XSI] Terminated children System CPU time */
};
getrusage 功能类似,它还提供了一些别的信息,时间只是一部分。它要更精确些,可以达到 us 级别。
void doWork(void) {
for (int i = 0; i < 10000; i++) {
printf("A\n");
}
}
int test(void) {
struct tms start_tms, end_tms;
clock_t start, end;
long clktck = sysconf(_SC_CLK_TCK);
struct rusage start_usage, end_usage;
getrusage(RUSAGE_SELF, &start_usage);
start = times(&start_tms);
doWork();
getrusage(RUSAGE_SELF, &end_usage);
end = times(&end_tms);
printf("real time is %f\n", (end - start) / (double)clktck);
printf("user time is %f\n", (end_tms.tms_utime - start_tms.tms_utime) / (double)clktck);
printf("sys time is %f\n", (end_tms.tms_stime - start_tms.tms_stime) / (double)clktck);
printf("getrusage user time is %f\n", (end_usage.ru_utime.tv_usec - start_usage.ru_utime.tv_usec) / (double)1000000);
printf("getrusage sys time is %f\n", (end_usage.ru_stime.tv_usec - start_usage.ru_stime.tv_usec) / (double)1000000);
return 0;
}
统计出来的结果:
real time is 0.040000
user time is 0.010000
sys time is 0.010000
getrusage user time is 0.009294
getrusage sys time is 0.010072
用 times 得到的结果是当前进程用了 0.02s,真实世界流逝了 0.04s,那还有 0.02s 就是进程调度的时候调度给别的进程了。
用 getrusage 得到 us 级别的统计。
总结
关于时间计算这块儿几个方法
NSDate
单位 秒CFAbsoluteTimeGetCurrent
单位 秒times
单位 百分之一秒(但是可以只计算当前进程时间也可以计算客观时间,以及时间在用户态、内核态的分布)getrusage
单位 微秒(只计算当前进程时间以及在用户态、内核态的分布)mach_absolute_time
单位 纳秒