离奇的CPU利用率

接到一个黑盒的case:一套双志强的服务器上,运行一个典型的索引服务,通过taskset命令将改服务的CPU绑定到socket1之后,理论上socket0应该没有工作负载,但实际上的结果是socket0非但有负载,而且对于一颗24core的CPU来说,CPU利用率接近100%——比socket1的负载还高!且更加头疼的是无论怎么对server端施加压力,serve的CPU利用率和性能不会有太大的提升。

其实我在拿到这个case之后,看了这个描述之后对根本原因已经有了预估。但无奈是黑盒,没有办法从代码里求证,只能靠从监控数据上推论。

首先拿到的一个重要指标是IPC(instruction per cycle)。这个指标的定义是:每时钟周期执行的非空闲指令数。

IPC = CPU_CLK_UNHALTED.THREAD/INS_RETIRED.ANY

利用perf可以直接抓取IPC。
Socket 0 IPC为0.08;Socket 1 IPC 为0.3。这意味着尽管Sokcet0的CPU utilization更高,但大多数的时间内Socket0仅仅只是执行一个“HALT”指令而已,大多数情况下这个指令理解为空指令就好了,不做任何有效的操作。所以公式中的这个“UNHALTED”很妙,只要不是“HALT”指令,都被记作“UNHALTED”,而如果是”.thread”,unhalted还要排除“MWAIT”指令数量。而有效指令在所有指令中的占比就是IPC。

问题来了:到底是什么原因导致的socket 0占用了大量的CPU时间去做没有意义的操作?第一反应就是等待操作,结合这个server的数据文件巨大(80G+),沿着IO方向去找不会错。这就牵扯到了Socket 上的PCIe bus的总带宽指标:

PCIeBW_read = 4 * sum(UNC_IIO_PAYLOAD_BYTES_IN.MEM_READ)
PCIeBW_write = 4 * sum(UNC_IIO_PAYLOAD_BYTES_IN.MEM_WRITE)

注:
x4是因为PCIe的请求都是4byte(double words)对齐。
部分平台的 UNC_IIO_PAYLOAD_BYTES_IN被改名为UNC_IIO_DATA_REQ_OF_CPU。

这个指标也可以通过PCM之类的工具直接获取。测得PCIe的写带宽很低,K级别水平就直接忽略不计了,但PCIe读带宽超过400MB/s。经确认,该服务器仅有一个480G SATA SSD硬盘,考虑到主流的SATA SSD硬盘一般最大写带宽都在500MB/s以下,这个数据已经可以定位到遭遇到了磁盘IO瓶颈。是磁盘的访问瓶颈导致了服务性能无法提升。

好了,大致上问题定位了,那怎么解释Socket0的CPU利用率高于Socket1呢?

接下去就是如何区分CPU utilization的来源了,这又牵扯两个重要指标:

CPUUtilization = CPU_CLK_UNHALTED.REF_TSC / TSC
CPUUtilization_kernel = CPU_CLK_UNHALTED.REF_TSC:SUP / TSC

分别是系统全局的CPU利用率和kernel的CPU利用率,当然两者的差代表的是User space的CPU利用率。不同于“.thread”,这里的“.ref_tsc”并不排除x86 SIMD中的”MWAIT” 指令。区分kernel态的方法则是看当前的指令的ring级别。其实通过系统工具vmstat以及top等命令都可以查看对应的sys/user CPU utilization读数。

重点:仅靠一个CPU的利用率指标并不能很好的反映出CPU的真实使用状况。

统计了Socket0的kernel CPU利用率为99.9%,结合前面的IPC结果推断socket0在内核态执行了大量的mwait用于做IO返回等待导致了CPU高负载的现象,从而断定了最初的猜测。而kernel态中大量的mwait(mwait本身就是一个ring0指令,即只能通过kernel调用)是由于用户态的密集系统调用请求。

逻辑链还原:

  1. 尽管所有的socket都可以安装PCIe设备,但在大多数的主板上,SATA控制器、集成网卡、USB等各种板载设备统统无脑连接到Socket0,实验中的服务器主板也不例外。这种设计的优势在于即便在只有一个socket0的产品配置时,板载的各种设备也不会受到影响,本身没有什么错。
  2. Linux以及NUMA设定的优化配置,导致了系统在使用这些设备的时候,优先绑定Sokcet0处理请求。通过系统调用的方式打开文件句柄——比如本例的操作更是如此。尽管服务被绑死在了socket1上,但大量的系统调用还是依赖于socket0对其下属的板载SATA控制器下SATA设备的访问。
  3. 死就死在SATA的带宽是瓶颈。大量的文件访问无法及时返回数据,逐渐的越来越多的CPU时间就无意义的消耗在了“等待数据返回”上。这也就是为什么Socket0的CPU利用率奇高但IPC不高的直接原因。
  4. IO是瓶颈,服务器性能自然提升不了,简单的方法是升级磁盘到NVMe,并下挂到socket1。

PS:其实就是一个vmstat就能看出来的问题,我居然啰嗦了这么多……

推荐阅读:
经常会通过一些通用的测试工具测
首先,提个问题:64bit x
去年的DCDC,我主要介绍了基

发表评论

电子邮件地址不会被公开。 必填项已用*标注

请补全下列算式: *

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据