gitbook/性能工程高手课/docs/183357.md
2022-09-03 22:05:03 +08:00

135 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 15 | CPU篇如何让CPU的运行不受阻碍
你好,我是庄振运。
从这一讲开始我们探讨分析几个最容易发生性能问题的领域CPU、内存、存储和网络。
这一讲先来讨论关于CPU的常见性能问题。首先我们从硬件的角度来看看CPU的性能取决于哪些因素然后分析一下CPU的内部结构。接着我们探讨和CPU性能相关的软件系统看看CPU运行时侯的调度和切换。
## CPU的性能决定因素
宏观来讲一台服务器里面的CPU性能取决于好几个因素包括有多少处理器、多少个核、时钟主频是多少、有没有Turbo模式、处理器内部的运算架构以及和CPU紧密交互的其他部件的性能。
CPU的更新换代很频繁基本上每两年就会更新一代。比如Intel的CPU最近10年已经经历了5代左右。每一代都有主频的变化而且有好几个变种。
下面的表格描述了从十年前也就是2009年的SandyBridge到后来的IvyBridge、Haswell、Broadwell直到Skylake。注意对后面的三代我分别列出了其中的两种变化——单处理器1P和双处理器2P
![](https://static001.geekbang.org/resource/image/0c/09/0ccfee296bbd3ab792b41ee0feb26209.png)
大体上我们可以看出虽然CPU更新换代但是处理器的时钟主频基本不再提高甚至变得更低了。这样的目的是降低CPU的功耗。比如SandyBridge的时钟频率是2.6GHz但是到了Skylake反而降低到了2GHz。
为了提升单个处理器的性能每个处理器里面的核数却越来越多这样就可以尽量的提升并行处理能力。比如SandyBridge的每个处理器只有8个核而Skylake则多达20个核。
而且我们也看到每一代CPU都允许Turbo模式就是让CPU的主频提高。目的是可以让处理器在特殊情况下用提高功耗的代价来增加主频从而获得更高性能。
## CPU的内部结构
CPU的性能也取决于它的内部结构设计。很多程序员对CPU的内部机构不是完全清楚尤其是对相关的术语之间的区别和联系一知半解比如多处理器和多核、逻辑CPU和硬件线程、超线程以及L1/L2/L3三级缓存等。
之所以对这些结构不甚了解主要原因是现代处理器变得复杂普遍采用多处理器多核以及内部的各种优化处理来提高CPU性能。我们今天就从外到内从宏观到微观地介绍一下。
我注意到,这方面的很多中文术语,大家有时候用法不一致,所以很容易混淆。为了清楚描述,你尤其要注意一下我用的术语(包括英文)。
### 多处理器和NUMA
现在的CPU普遍采用多处理器Socket来提高CPU性能每个处理器都有自己可以直接访问的本地内存Local Memory。一般来讲这里面每个处理器的性能和内存大小都是一样的。每个处理器也都可以访问其他处理器的内存这些内存就相当于是外地/远程内存Remote Memory
当CPU处理器访问本地内存时会有较短的响应时间称为本地访问Local Access。而如果需要访问外地/远程内存时候就需要通过互联通道访问响应时间就相比本地内存变慢了称为远端访问Remote Access。所以NUMANon-Uniform Memory Access就此得名。
下图展示了两个处理器的NUMA架构。
![](https://static001.geekbang.org/resource/image/88/33/88b6a75956af211654f2fe6c13a0c933.png)
如果处理器A访问内存A就是本地访问。如果它访问内存B就是远端访问内存的访问延迟大大增加。
采用多处理器和NUMA架构的主要原因是提高整个CPU的并行处理性能。每一台服务器可以同时运行很多程序和进程。对每一个进程和线程而言当它运行在某一个处理器上时它所对应的内存使用默认的分配方案是——优先尝试在请求线程当前所处的处理器的本地内存上分配。如果本地内存不足才会分配到外地/远程内存上去。
### 多核结构和多级缓存
我们再看看每个处理器内部的结构。我们刚刚讲到的处理器内部一般都是多核Core架构。随着多核处理器的发展CPU的缓存通常分成了三个级别L1、L2和L3。
级别越小就越接近CPU速度更快同时容量也越小。L1和L2一般在核的内部我们下一讲还会详细讲。L3缓存是三级缓存中最大的一级同时也是最慢的一级在同一个处理器内部的核会共享同一个 L3 缓存。
除了多个核以及L3缓存外处理器上一般还有非核心处理器Uncore里面含有和指令运行不直接相关的组件包括QPI控制器和存储器一致性监测组件如下图所示。
![](https://static001.geekbang.org/resource/image/35/e7/354764adfca130abdc7ae15a0fafd0e7.png)
### 超线程HyperthreadingHT
一个核还可以进一步分成几个逻辑核,来执行多个控制流程,这样可以进一步提高并行程度,这一技术就叫超线程,有时叫做 simultaneous multi-threadingSMT
超线程技术主要的出发点是,当处理器在运行一个线程,执行指令代码时,很多时候处理器并不会使用到全部的计算能力,部分计算能力就会处于空闲状态。而超线程技术就是通过多线程来进一步“压榨”处理器。
举个例子如果一个线程运行过程中必须要等到一些数据加载到缓存中以后才能继续执行此时CPU就可以切换到另一个线程去执行其他指令而不用去处于空闲状态等待当前线程的数据加载完毕。
通常一个传统的处理器在线程之间切换可能需要几万个时钟周期。而一个具有HT超线程技术的处理器只需要1个时钟周期。因此就大大减小了线程之间切换的成本从而最大限度地让处理器满负荷运转。
一个核分成几个超线程呢?
这个数字会根据CPU架构有所变化Intel一般是把一个核分成2个。
“这台计算机有多少CPU
我们经常会问这个问题,结合我们刚刚讲的知识,就很容易回答了。
比如如果一台计算机有两个处理器每个处理器有12个核而且采用了HT超线程那么总的CPU数目就是48就是2×12×2。这个数字48就是我们平时用监控软件和命令看到的CPU的数量。比如Linux的top或者vmstat命令显示的CPU个数就是这样算出来的。
## CPU性能指标和常见性能问题
我们继续探讨CPU的性能指标和常见性能问题这方面很多资料都有涉及我们提纲挈领地总结一下。
最表层的CPU性能指标就是CPU的负载情况和使用率。CPU使用率又进一步分成系统CPU、用户CPU、IO等待CPU等几个指标。你执行一下top命令就会看到。
需要注意的是因为CPU架构的复杂性以及和其他部件的交互CPU的使用率和负载的关系往往不是线性的。
也就是说如果10%的CPU使用率可以每秒处理1千个请求那么80%的CPU使用率能够处理多少请求呢不太可能处理每秒8千个请求往往会远远小于这个数字。
衡量一个应用程序对CPU使用效率时往往会考察CPICycles Per Instruction每指令的周期数和 IPCInstructions Per Cycle每周期的指令数。这两个指标有助于识别运行效率高或低的应用程序。而一台计算机的CPU性能一般用MIPSMillions of Instructions Per Second来衡量表示每秒能运行多少个百万指令MIPS越高性能越高。MIPS的计算很简单就是时钟频率×IPC。
继续往深处分析CPU常见的各种中断包括软中断和硬中断。除此之外还有一种特殊的中断上下文切换。这些指标需要和每个核挂钩理想情况下是各个核上的中断能够均衡。如果数量不均衡往往会造成严重的性能问题——有的核会超载而导致系统响应缓慢但是其他的核反而空闲。
和CPU相关的性能问题基本上就是表现为CPU超载或者空闲。
如果是CPU超载那么就要分析为什么超载。多数情况下都不一定是合理的超载比如说多核之间的负载没有平衡好或者CPU干了很多没用的活或者应用程序本身的设计需要优化等等。反之如果是CPU空闲那就需要了解为什么空闲或许是指令里面太多内存数据操作从而造成CPU停顿也或许是太多的分支预测错误等这就需要具体分析和对症下药的优化。
CPU对多线程的执行顺序是谁定的呢
是由内核的进程调度来决定的。内核进程调度负责管理和分配CPU资源合理决定哪个进程该使用 CPU哪个进程该等待。进程调度给不同的线程和任务分配了不同的优先级优先级最高的是硬件中断其次是内核系统进程最后是用户进程。每个逻辑CPU都维护着一个可运行队列用来存放可运行的线程来调度。
## CPU的性能监测工具
我们最后讲一下CPU性能监测方面的工具。和CPU监测相关的工具挺多的而且往往每个工具都包含很多不同的有用的信息。
比如在Linux上最常用的Top系统进程监控命令。Top是一个万金油的工具可以显示出CPU的使用、内存的使用、交换内存和缓存大小、缓冲区大小、各个进程信息等。
如果想要查看过去的CPU负载情况可以用uptime。也可以用mpstat和pidstat来分别查看每个核还有每个进程的情况。另一个常用的vmstat命令可以用于显示虚拟内存、内核线程、磁盘、系统进程、I/O模块、中断等信息。
对有经验的性能工程师来讲有一个类似于“瑞士军刀”一样的好工具Perf。
Perf是Linux上的性能剖析profiling工具极为有用。它是基于事件采样原理以性能事件为基础利用内核中的计数器来进行性能统计。它不但可以分析指定应用程序的性能问题也可以用来分析内核的性能问题。
## 总结
这一讲我们讨论了计算机的运算核心CPU的结构尤其是它内部的和性能相关的部件并澄清了一些术语。
![](https://static001.geekbang.org/resource/image/b7/7c/b7600ae6757369212e30aec6e829997c.png)
CPU是服务器性能的最重要的部分因为不管程序代码如何优化最后都要转换成指令让CPU来执行。不管其他部件如何和CPU交互最终目的是让CPU尽快地拿到指令并满载执行。
唐代有个诗人叫李贺,他曾经形容跨马奔驰的愿景:
“大漠沙如雪,燕山月似钩。
何当金络脑,快走踏清秋。”
我们常把CPU类比大脑CPU性能优化的目标就是让它的运行不受阻碍如千里马一样任意驰骋。
现代CPU提升性能的主要途径是并行化这方面的策略包括多处理器、多核、超线程另外还有流水线架构和超标量等等都是为了提高并行处理能力。
## 思考题
你工作中一定碰到过CPU方面的性能问题吧总结一下有几种表现形式
> 比如是总体CPU使用量太高还是计算机的几个核负载不均衡负载不均衡是什么原因导致的呢是线程数不够还是系统调度的问题
欢迎你在留言区分享自己的思考,与我和其他同学一起讨论,也欢迎你把文章分享给自己的朋友。