导读 | 我们用来衡量cpu使用率(cpu utilization)的指标具有极大的误导性,而且一年比一年来得误人子弟。cpu使用率到底是什么?你的处理器有多忙碌?不,那不是cpu使用率衡量的方面。 |
没错,我在这里所说的是每个人在到处使用的“%cpu”这个度量指标,用于每一款性能监控产品中。用top(1)命令来查看。
你可能认为90%的cpu使用率意味着:
而实际上它可能意味着:
停滞(stalled)意味着处理器在处理指令方面没有进展,通常是由于处理器在等待内存输入/输出。我在上面划分的比例(忙碌和停滞之间)是我在实际的生产环境中经常看到的情形。你很可能基本上处于停滞状态,但浑然不知罢了。
这对你来说意味着什么呢?了解你的多少cpu处于停滞状态可以指导减少代码或减少内存输入/输出之间的性能调优工作。谁要是在关注cpu性能,尤其是在根据cpu自动扩展资源的云,如果知道%cpu中停滞的部分,那将大有益处。
我们称为cpu使用率的衡量指标其实是“非闲置时间”(non-idle time):也就是cpu未运行闲置线程的时间。你的操作系统内核(无论它是什么内核)通常在上下文切换过程中跟踪这个指标。如果非闲置进程开始运行,然后停止100毫秒,内核还是认为该cpu在那整段时间都被使用。
这个度量指标的历史与分时系统一样久远。apollo lunar module制导计算机(一种开创性的分时系统)称其闲置线程为“dummy job”,工程师们跟踪了运行该闲置线程的周期和运行实际任务的周期,将这视作是一个衡量计算机使用率的重要指标。
现如今,cpu的速度已变得比主内存快得多,等待内存在仍然所谓的“cpu使用率”中占了大头。如果你看到数值很高的%cpu,可能认为处理器是瓶颈(即散热片和风扇下面的cpu封装件),而实际上那些dram模组才是瓶颈。
这方面的情形一直变得越来越严峻。长期以来,处理器厂商提高时钟速度的幅度超过dram提高访问延迟的幅度,这就是所谓的“cpu dram缺口”(?cpu dram gap)。这种情形在3 ghz处理器面世的2005年前后趋稳;自那以后,处理器使用更多的核心和超线程来提升性能,另外使用多插座配置,这一切给内存子系统提出了更高的要求。处理器厂商试图采用更庞大、更智能的cpu缓存以及更快速的内存总线和互连技术来缓解这个内存瓶颈。但是我们仍然通常处于停滞状态。
不妨使用性能监控计数器(pmc):这是使用linux perf及其他工具可以读取的硬件计数器。比如说,将整个系统测量10秒钟:
# perf stat -a — sleep 10 performance counter?stats for ‘system wide’: 641398.723351??????task-clock?(msec)?????????#??64.116 cpus utilized?????????(100.00%) 379,651??????context-switches??????????#????0.592 k/sec?????????????????(100.00%) 51,546??????cpu-migrations???????????#????0.080?k/sec?????????????????(100.00%) 13,423,039???????page-faults??????????????#????0.021 m/sec 1,433,972,173,374??????cycles??????????????????#????2.236 ghz??????????????????(75.02%)??????stalled-cycles-frontend ??????stalled-cycles-backend 1,118,336,816,068??????instructions??????????????#????0.78??insns per cycle??????????(75.01%) 249,644,142,804???????branches???????????????#???389.218 m/sec????????????????(75.01%) 7,791,449,769???????branch-misses????????????#??3.12% of all branches??????????(75.01%) 10.003794539?seconds time elapsed
这里一个关键的度量指标是每个周期指令(即ipc),该度量指标显示了我们在每个cpu时钟周期平均完成了多少个指令。简单来说,这个值越高越好。上面例子中的0.78听起来不赖(78%的时间段处于忙碌状态);但如果你意识到该处理器的最高速度下ipc是4.0,就不这么认为了。这又叫4-wide,是指指令取出/解码路径。这意味着,cpu每个时钟周期可以retire(完成)四个指令。所以,在4-wide系统上ipc为0.78,意味着cpu的运行速度是其最高速度的19.5%。新的英特尔skylake处理器是5-wide。
你可以用来进一步钻研的pmc要多数百个:可以按不同的类型,直接测量停滞的周期。
如果你在虚拟环境中,可能无法访问pmc,这要看虚拟机管理程序是否为访客(guest)支持pmc。我最近写过一篇文章:《ec2的pmc:测量ipc》,表明了如今pmc如何可用于基于xen的aws ec2云上面的专用主机类型。
如果你的ipc < 1.0,你可能遇到了内存停滞,软件调优策略包括减少内存输入/输出,改进cpu缓存和内存局部性(memory locality),尤其是在numa系统上。硬件调优策略包括:使用cpu缓存比较大的处理器以及速度比较快的内存、总线和互连技术。
如果你的ipc > 1.0,你可能是指令密集型。想方设法减少代码执行:消除不必要的工作和缓存操作等。cpu火焰图是一款很适合开展这项调查的工具。至于硬件调优,不妨试一试更快的时钟频率和数量更多的核心/超线程。
每一款性能工具应该显示ipc以及%cpu。或者将%cpu分解成指令完成周期与停滞周期,比如%ins和%stl。
面向linux的tiptop(1)可按进程显示ipc:
tiptop?–?????????????????[root] tasks:?96 total,????3 displayed?????????????????????????????????screen???0: default ? pid?[ %cpu]?%sys??p???mcycle???minstr??ipc?%miss?%bmis??%bus?command 3897???35.3???28.5????4???274.06???178.23?0.65???0.06??0.00???0.0?????java 1319 ???5.5????2.6???6????87.32???125.55?1.44???0.34??0.26??0.0????nm-applet 900????0.9??0.0????6????25.91????55.55?2.14???0.12??0.21?????0.0?????dbus-daemo
让cpu使用率具有误导性的不仅仅是内存停滞周期。其他因素包括如下:
- 温度过高导致处理器停滞。
- 睿频加速(turboboost)导致时钟频率不一。
- 内核因speedstep导致时钟频率不一。
- 平均值方面的问题:1分钟内的使用率为80%,隐藏了100%的突发使用率。
- 自旋锁:cpu被使用,有很高的ipc,但是应用程序在处理指令方面没有合理的进展。
cpu使用率已成为一个极具误导性的度量指标:它包括了等待主内存的周期,而这类周期在现代工作负载中占了大头。如果使用额外的度量指标,你就能搞清楚%cpu到底意味着什么,包括每个周期指令(ipc)。ipc < 1.0可能意味着内存密集型,而ipc > 1.0可能意味着指令密集型。我在之前的一篇文章中介绍了ipc,包括介绍了衡量ipc所需要的性能监控计数器(pmc)。 显示%cpu的性能监控产品还应该显示pmc度量指标,解释那个值意味着什么,那样才不会误导最终用户。比如说,它们可以一并显示%cpu及ipc,以及/或指令完成周期与停滞周期。有了这些度量指标,开发人员和操作人员才能决定如何才能更好地调优应用程序和系统。