jasper的技术小窝

关注DevOps、运维监控、Python、Golang、开源、大数据、web开发、互联网

性能调优之CPU篇

作者:jasper | 分类:Linux | 标签:   | 阅读 968 次 | 发布:2016-10-23 4:33 p.m.

CPU推动了所以软件的运行,因而通常是性能分析的首要目标,特别是现在硬件的性能越来越好,CPU的核数也是越来越多,系统通过内核调度器来调度运行的任务,当所需的CPU资源超过了所提供的时,进程里的线程就会排队,等待轮询的机会。而这样等待就给应用程序的运行带来了延时,使性能下降。所以我们希望可以在CPU上面能有所优化,让应用的性能提升。

1、CPU模型

1.1、CPU架构

核心数可以分为物理核与逻辑核,每个硬件线程都是可以选择按照逻辑CPU寻址,而且操作系统可以获取到哪些CPU在同一个核上,这样就可以提高调度的质量。

1.2、CPU内存缓存

为了提高内存IO性能,处理器提供了多种硬件缓存,按照靠近CPU的先后顺序:CPU寄存器——>一级缓存——>二级缓存——>三级缓存——>主存——>存储设备,当然也是速度快慢的顺序。缓存器的存在与否,以及是集成在处理器里还是处理器外,取决于处理器的类型。

1.3、CPU运行队列

正在排队和就绪运行的线程数量是一个很重要的性能指标,表达了CPU的饱和度。

对于多处理器的系统,内核通常为每个CPU提供了一个运行队列,并尽量使得线程每次都被放到同一个队列之中。这意味着线程更有可能在同一个CPU上运行,因为CPU缓存里保留了它们的数据,再NUMA系统中,这回提高内存本地性,从而提供系统性能,这同样避免了队列操作的线程同步开销(mutex锁),如果运行队列是全局的并被所有的CPU共享,这种开销会影响扩展性。

2、概念

下面看一些性能相关的概念:

2.1、时钟频率

时钟是一个驱动所有处理器逻辑的数字信号。每个CPU指令都可能花费一个或是多个时钟周期来执行。CPU以一个特定的时钟频率来执行,例如,一个5GHz的CPU每秒运行50亿个时钟周期。但是更快的的时钟频率并不一定会提高性能,这取决于CPU周期里在做些什么,如果大部分时间在停滞等待内存访问,那么更快的执行并不能提高CPU指令的执行效率。

2.2、指令

指令包括的步骤:指令预取、指令解码、执行、内存访问、寄存器写回;里面的每一步都至少需要一个时钟周期来执行,内存访问是最慢的,因为它通常需要几十个时钟周期来读或是写主存,在此期间指令陷入停滞,这也是CPU缓存重要的原因。

2.3、指令流水线

通过同时执行不同指令的不同部分,来达到同时执行多个指令的结果。

2.4、指令宽度

在每个时钟周期处理更多的指令,这种CPU架构成为超标量,现在计算机一般宽度是三个或是四个。

2.5、使用率

CPU使用率通过测量一段时间CPU实例忙于执行工作的时间比例获得。高CPU并不一定代表着问题,仅表示系统在工作,高度利用的CPU被认为有着较好的ROI,在高使用率的情况下,性能并不会出现显著的下降,因为内核支持了优先级、抢占和分时共享。

2.6、用户时间、内核时间

CPU花在执行用户态应用程序代码的时间成为用户时间,而执行内核态代码的时间称其为内核时间。内核时间包括系统调用、内核线程和中断时间。计算密集型应用程序时间大把会花在用户态代码上,而IO密集型的系统调用频率会高,通过内核代码进行IO操作。

2.7、抢占

优先级高的线程可以抢占当前正在运行的线程。

2.8、优先级反转

指一个低优先级线程用于资源从而阻塞了高优先级线程的运行,这样就降低了高优先级的工作性能,linux从2.6.18起提供了一个支持优先级继承的用户态mutex,用于实时负载。

2.9、多进程、多线程

应用程序在CPU上的扩展技术分为多线程和多进程:

多线程一般被认为由于多进程,但是对开发者而言更难实现,比如并发控制、资源锁。但是有些应用可能在更少的CPU上跑的更快,因为线程同步和内存本地性下降,反而会吞噬更多CPU资源。

2.10、字长

处理器是围绕最大字长设计的,32位或是64位,这是整数大小和寄存器宽度。更宽的字长意味着更好的性能,但也不是绝对的,更宽的字长可能在某些数据类型下因未使用的位而导致额外的内存开销。对于64位的x86架构来说,寄存器的增加和有效调用的约定抵消了这些开销,因此64位应用程序会比32位版本跑得快。

3、架构

3.1、硬件

  • 处理器:运行指令预取、解码、管理执行以及存储结果
  • CPU缓存:包括指令存储和数据存储
  • MMU:负责虚拟地址到物理地址的转换
  • 互联:多处理器架构中,通过共享系统总线或是专用互联连接起来
  • CPU性能计数器:可以计数低级CPU活动的处理器寄存器

3.2、软件

  • 调度器:功能有分时、抢占和负载均衡
  • 调度类:管理可运行线程行为,特别是优先级还有CPU时间是否分片,以及这些时间片的长度。
  • 空闲线程:只在没有其他科运行的线程的时候才在CPU上运行,优先级尽可能低。
  • NUMA分组:NUMA系统上的性能可以通过使内核感知NUMA而得到极大提高,这样可以做出更好的调度和内存分配决定。

4、方法

4.1、工具法

对于CPU,可以用下面的命令方法检查:uptime、vmstat、top等,这些是linux的基本命令,我就不详说了。

4.2、USE方法

对于每个CPU,检查以下内容:

  • 使用率:CPU繁忙的时间
  • 饱和度:可运行线程排队等待CPU的程度
  • 错误:CPU错误

4.3、负载特征归纳

基本属性有:平均负载、用户时间和系统时间之比、系统调用频率、自愿上下文切换频率、中断频率

4.4、性能监控

使用率和饱和度,其中使用率应该对每个CPU分别监控,以发现线程的扩展性问题,对于限制CPU的环境,还要记录相对于这些限制的CPU用量。

4.5、静态资源调优

有多少CPU可用,是物理核还是逻辑核?
CPU缓存大小是多少,可以共享么?
CPU时钟频率是多少?
BIOS启动或是禁用了其他什么CPU相关特性?
……

4.6、优先级调优

Unix一直都提供nice系统调用,通过设置nice值来调整进程优先级。正nice值代表降低进程优先级,而负值只能由root用户设置,代表提高优先级。

4.7、CPU绑定

把进程和线程绑定在单个CPU或是一组CPU上,可以增加进程的CPU缓存温度,提高它的内存IO性能,对NUMA系统可以提高内存本地性,同样提高性能。

5、分析

linux下的分析工具大体有uptime、vmstat、mpstat、sar、ps、top、pidstat、time、perf;具体怎么用,以及所表达的意思不细说了,多用就知道了。

其他的还包括oprofile、htop、atop、/proc/cpuinfo。

这些都是命令行,也有可视化的工具,linux可以用火焰图来表达。

6、实验

6.1、Ad Hoc

这个方法可以创建一个单线程的CPU密集型负载,例如:# whiled:; do :; done &

6.2、Sysench

这个命令可以执行多个线程,可以通过配置来决定。

7、调优

  • 编译器选项:编译器及其提供的优化代码选项,对CPU性能有很大影响。一般选项包括了编译为64位而非32位程序,以及优化级别。
  • 调度优先级和调度类:通过nice来调整优先级。
  • 调度器选项:提供参数控制调度器行为。
  • 进程绑定:linux中,通过taskset命令实现。
  • 独占CPU:给CPU编组并为其分配进程。
  • 资源控制:用cgroup实现。
  • BIOS调优:启用或是禁用调优处理器级别的特性。


转载请注明出处:http://www.opscoder.info/cpu_performance.html

【上一篇】 性能调优之开篇
【下一篇】 性能调优之内存篇
其他分类: