性能之巅:洞悉系统、企业与云计算——CPU


CPU推动了所有软件的运行,因而通常是系统性能分析的首要目标。现代系统一般有多个CPU,通过内核调度器共享给所有运行软件。当需求的CPU资源超过了系统力所能及的范围时,进程里的线程(或者任务)将会排队,等待轮候自己运行的机会。等待给应用程序的运行带来严重延时,使得性能下降。

我们可以通过仔细检查CPU的用量,寻找性能改进的空间,还可以去除一些不需要的负载。从上层来说,可以按进程、线程或者任务来检查CPU的用量。从下层来看,可以剖析并研究应用程序和内核里的代码路径。在底层,可以研究CPU指令的执行和周期行为。

术语

  • 处理器:插到系统插槽或者处理器板上的物理芯片,以核或者硬件线程的方式包含了一块或者多块CPU。
  • :一个多核处理器上的一个独立CPU实例。核的使用是处理器扩展的一种方式,又称为芯片级多处理。
  • 硬件线程:一种支持在一个核上同时执行多个线程的CPU架构,每个线程是一个独立的CPU实例。这种扩展的方法又称为多线程
  • CPU指令:单个CPU操作,来源于它的指令集。指令用于算术操作、内存I/O,以及逻辑控制
  • 逻辑CPU:又称为虚拟处理器,一个操作系统CPU的实例(一个可调度的CPU实体)。处理器可以通过硬件线程(这种情况下又称为虚拟核)、一个核,或者一个单核的处理器实现。
  • 调度器:把CPU分配给线程运行的内核子系统
  • 运行队列:一个等待CPU服务的可运行线程队列。

模型

CPU架构

下图展示了一个CPU架构的示例,单个处理器内共有四个核和八个硬件线程。物理架构如下图右侧所示,而右侧图则展示了从操作系统角度看到的景象。
在这里插入图片描述
每个硬件线程都可以按逻辑CPU寻址,因此这个处理器看上去有八个CPU。对这种拓补结构,操作系统可能有一些额外信息,如哪些CPU在同一个核上,这样可以提高调度的质量。

CPU内存缓存

为了提高内存I/O性能,处理器提供了多种硬件缓存。下图展示了缓存大小的关系,越小则速度越快(一种权衡),并且越靠近CPU。

缓存存在与否,以及是在处理器里(集成)还是在处理器外,取决于处理器的类型。早期的处理器集成的缓存层次较少。
在这里插入图片描述

CPU运行队列

下图展示了一个由内核调度器管理的CPU运行队列
在这里插入图片描述
正在排队和就绪运行的软件线程数量是一个很重要的性能指标,表示了CPU的饱和度。在上图中(在这一瞬间)有四个排队线程,加上一个正在CPU上运行的线程。花在等待CPU运行上的时间又被称为运行队列延时或者分发器队列延时。

在于多处理器系统,内核通常为每个CPU提供了一个运行队列,并尽量使得线程每次都被放到同一队列之中。这意味着线程更有可能在同一个CPU上运行,因为CPU缓存里保存了它们的数据。(这些缓存被称为热度缓存,这种选择运行CPU的方法被称为CPU关联)。

概念

时钟频率

时钟是一个驱动所有处理器逻辑的数字信号。每个CPU指令都可能会花费一个或者多个时钟周期(称为CPU周期)来执行。CPU以一个特定的时钟频率执行,例如,一个5GHz的CPU每秒运行五十亿个时钟周期。

有些处理器可以改变时钟频率,升频以改进性能或者降频以减少能耗。频率可以根据操作系统请求变化,或者处理器自己进行动态调整。例如内核空闲线程,就可以请求CPU降低评率以节约能耗。

时钟频率经常被当作处理器营销的主要指标,但这有可能让人误入歧途。即使你系统里的CPU看上去已经完全利用(达到瓶颈),但更快的时钟评率并不一定会提供性能——它取决于快速CPU周期里到底在做些什么。如果它们大部分时间是停滞等待内存访问,那更快的执行实际上并不能提高CPU指令的执行效能或者负载吞吐量。

指令

CPU执行指令集中的指令。一个指令包括以下步骤,每个CPU的一个叫作功能单元的组件处理:

  1. 指令预取
  2. 指令解码
  3. 执行
  4. 内存访问
  5. 寄存器写回

这里每一步都至少需要一个时钟周期来执行。内存访问经常是最慢的,因为它通常需要几十个时钟周期读或写主存,在此期间指令执行陷入停滞(停滞期间的这些周期称为停滞周期)。这就是CPU缓存如此重要的原因:它可以极大地降低内存访问需要的周期数。

指令流水线

指令流水线是一种CPU架构,通过同时执行不同指令的不同部分,来达到同时执行多个指令的结果。这类似于工厂的组装线,生产的每个步骤都可以同时执行,提高了吞吐量。

指令宽度

我们还能更快。同一种类型的功能单元可以有好几个,这样每个时钟周期里就可以处理更多的指令。这种CPU架构被称为超标量,通常和流水线一起使用以达到高指令吞吐量。

指令宽度描述了同时处理的目标指令数量。现代处理器一般为宽度3或者宽度4,意味着它们可以在每个周期里最多完成3~4个指令。如何取得这个结果取决于处理器本身,每个环节都有不同数量的功能单元处理指令。

CPI,IPC

每指令周期数(CPI)是一个很重要的高级指标,用来描述CPU如何使用它的时钟周期,同时可以用来理解CPU使用率的本质。这个指标也可以被表示为每周期指令数(instructionsper cycle, IPC),即CPI的倒数。

CPI 较高代表CPU经常陷入停滞,通常都是在访问内存。而较低的CPI则代表CPU基本没有停滞,指令吞吐量较高。这些指标指明了性能调优的主要工作方向。

内存访问密集的负载,可以通过下面的方法提供性能,如使用更快的内存(DRAM)、提高内存本地性(软件配置),或者减少内存I/O数量。使用更高时钟频率的CPU并不能达到预期的性能目标,因为CPU还是需要为等待内存I/O完成而花费同样的时间。换句话说,更快的CPU意味更多的停滞周期,而指令完成速率不变。

CPI的高低与否实际上和处理器以及处理器功能有关,可以通过实验方法运行已知的负载得出。例如,你会发现高CPI的负载可以使CPI达到10或者更高,而在低CPI的负载下,CPI低于1(收益于前述的指令流水线和宽度技术,这是可以达到的)。

值得注意的是,CPI代表了指令处理的效率,但不代表指令本身的效率。假设有一个软件改动,加入了一个低效率的循环,这个循环主要在操作CPU寄存器(没有停滞周期):这种改动可能会降低总体CPI,但会提高CPU的使用和利用度。

使用率

CPU使用率通过测量一段时间内CPU实例忙于执行工作的时间比例获得,以百分比表示。它也可以通过测量CPU未运行内核空闲线程的时间得出,这段时间内CPU可能运行一些用户态应用线程,或者其他的内核线程,或者处理中断。

高CPU使用率并不一定代表着问题,仅仅表示系统正在工作。有些人认为这是ROI的指示器:高度利用的系统被认为有着较好ROI,而空闲的系统则是浪费。和其他类型的资源(磁盘)不同,在高使用率的情况下,性能并不会出现显著下降,因为内核支持优先级、抢占和分时共享。这些概念加起来让内核决定了什么线程的优先级更高,并保证它优先运行。

CPU使用率的测量包括了所有符合条件活动的时钟周期,包括了内存停滞周期。虽然看上去有些违反直觉,但CPU有可能像前面描述的那样,会因为停滞等待I/O而导致高使用率,而不仅是在执行指令。

CPU使用率通常会被分成内核时间和用户时间两个指标。

用户时间/内核时间

CPU花在执行用户态应用程序代码的时间称为用户时间,而执行在内核代码的时间称为内核时间。内核时间包括系统调用、内核线程和中断的时间。当在整个系统范围内进行测量时,用户时间和内核时间之比揭示了运行的负载类型。

计算密集的应用程序几乎会把大量的时间用再用户态代码上,用户/内核时间之比接近99/1。这类例子有图像处理、基因组学和数据分析。

I/O密集的应用程序的系统调用频率较高,通过执行内核代码进行I/O操作。例如,一个进行网络I/O的Web服务器的用户/内核时间比大约为70/30.

饱和度

一个100%使用率的CPU被称为是饱和的,线程在这种情况下会碰上调度器延时,因为它们需要等待才能在CPU上运行,降低总体性能。这个延时是线程花在等待CPU运行队列或者其他管理线程的数据结构上的世界。

另一个CPU饱和度的形式则和CPU资源控制有关,这个控制会在云计算环境下发生。尽管CPU并没有100%地被使用,但已经达到了控制的上线,因此可运行的线程就必须等待轮到它们的机会。这个过程对用户的可见度取决于使用的虚拟化技术。

一个饱和运行的CPU不像其他类型资源那样问题重重,因为更高优先级的工作可以抢占当前线程。

抢占

允许更高优先级的线程抢占当前正在运行的线程,并开始执行自己。这样节省了更高优先级工作的队列延时时间,提供了性能。

优先级反转

优先级反转指的是一个低优先级线程拥有了一项资源,从而阻塞了高优先级线程运行的情况。这降低了高优先级工作的性能,因为它被迫阻塞等待。

多进程,多线程

大多数处理器都以某种形式提供多个CPU。对于想使用这个功能的应用程序来说,需要开启不同的执行线程以并发运行。对于一个64个CPU的系统来说,这意味着一个应用程序如果同时满所有CPU,可以达到最快64倍的速度,或者处理64倍的负载。应用程序可以根据CPU数目进行有效放大的能力又称为扩展性。

应用程序在多CPU上扩展的技术分为多进程和多线程,如下图所示:
在这里插入图片描述
在Linux上可以使用多进程和多线程模型,而这两种技术都是由任务实现的。

多进程和多线程的差异如下表所示:

属性多进程多线程
开发较简单。使用fork()使用线程API
内存开销每个进程不同的地址空间消耗了一些内存资源小。只需要额外的栈和寄存器空间
CPU开销forl() / exit()的开销,另外MMU还需要管理地址空间小。API调用
通信通过IPC。导致了CPU开销,包括为了在不同地址空间之间移动数据而导致的上下文切换,除非使用共享内存区域最快。直接存储共享内存。通过同步原语保证数据一致性(例如,mutex锁)
内存使用虽然有一些冗余的内存使用,但不同的进程可以exit(),并向系统返还所有的内存通过系统分配器。这可能导致多个线程之间的CPU竞争,而在内存被重新使用之前会有些碎片化

正如表里多线程的那些优点所示,多线程一般被认为优于多进程,尽管对开发者而言更难实现。

不管使用何种技术,最重要的是要创建足够的进程或线程,以占据预期数量的CPU——如果要最大化性能,即所有的CPU。有些应用程序可能在更少的CPU上跑得更快,这是因为线程同步和内存本地性下降而吞噬了更多CPU资源。

字长

处理器是围绕最大子设计的——32位或者64位——这是整数大小和寄存器宽度。字长也普遍使用,表示地址空间大小和数据通路宽度(有时也称为位宽),取决于不同的处理器实现。

更宽的字长意味着更好的性能,虽然它并没有听上去那么简单。更宽的字长可能会在某些数据类型下因未使用的位而导致额外的内存开销。数据的大小也会因为指针大小的增加而增加,导致需要更多的内存I/O。对于64位的x86架构来说,寄存器的增加和更有效的调用约定抵消了这些开销,因此64位应用程序会比32位版本跑得更快。

处理器和操作系统支持多种字长,可以同时运行编译成不同字长的应用程序。如果软件被编译成较小的字长,它可能会成功运行但是慢得多。

编译器优化

应用程序在CPU上的运行时间可以通过编译器选项(包括字长设置)来大幅改进。编译器也频繁地更新以利用最新的CPU指令集以及其他优化。有时应用程序性能可以通过使用新的编译器显著地提高。

架构

CPU硬件包括了处理器和它的子系统,以及多处理器之间的CPU互联。

处理器

控制器是CPU的心脏,运行指令预取、解码、管理执行以及存储结果。

CPU缓存

多种硬件缓存往往包含在处理器内或者与处理器放在一起(外置)。这样通过更快类型的内存缓存了读并缓冲了写,提高了内存性能。下图展示了一个普通处理器是如何访问不同级别的缓存的。
在这里插入图片描述
它们包括了:

  • 一级指令缓存(I$)
  • 一级缓存数据(D$)
  • 转译后备缓冲器(TLB)
  • 二级缓存(E$)
  • 三级缓存(可选)

对于多核和多线程处理器,有些缓存会再核与线程之间共享。

除了CPU缓存在数量和大小上的不断增长,还有一种趋势是把缓存做在芯片里,而不是放在处理器的外部,因为这样可以最小化访问延时。

延时

多级缓存是用来取得大小和延时平衡的最佳配置。一级缓存的访问时间一般是在几个CPU时钟周期,而更大的二级缓存大约是几十个时钟周期。主存大概会花上60ns,而MMU的地址转译又会增加延时。

相联性

相联性是定位缓存新条目范围的一种缓存特性。类型如下:

  • 全关联:缓存可以在任意的地方放置新条目。例如,一个LRU算法可以剔除整个缓存里最老的条目
  • 直接映射:每个条目在缓存里只有一个有效的地方,例如,对内存地址使用一组地址位进行哈希,得出缓存中的地址
  • 组关联:首先通过映射(例如哈希)定位出缓存中一组地址,然后再对这些使用另一个算法(例如LRU)。这个方法通过组打下描述。例如,四路组关联把一个地址映射到四个可能的地方,然后在这四个地方中挑选最合适的一个。

CPU缓存经常使用相关联方法,这是在全关联(开销过大)与直接映射(命中过低)中间找一个平衡点。

缓存行

CPU缓存的另一个特征是缓存行大小。这是一个存储和传输的字节数量单位,提高了内存吞吐量。

缓存一致性

内存可能会同时被缓存在不同处理器的多个CPU里。当一个CPU修改了内存,所有的缓存需要知道它们的缓存拷贝已经失效,应该被丢弃,这样后续的读才会取到新修改的拷贝。这个过程叫做缓存一致性,确保了CPU用于访问正确的内存状态。这也是设计可扩展多处理器系统里最大的挑战之一,因为内存会被频繁修改。

MMU

MMU负责虚拟地址到物理地址的转换。下图展示了一个普通的MMU,附有CPU缓存类型。这个MMU通过一个芯片上的TLB缓存地址转换。主存(DRAM )里的转换表,又叫页表,处理缓存未命中的情况。页表由MMU(硬件)直接读取。
在这里插入图片描述

互联

对于多处理器架构,处理器通过共享系统总线或者专用互联连接起来。这与系统的内存架构,统一内存访问(UMA)或者NUMA。

共享的系统总线,称为前端总线。使用系统总线时,在处理器数目增长的情况下,会因为共享系统总线资源而出现扩展性问题。现代服务器通常都是多处理器,NUMA,并使用CPU互联技术。

CPU性能计数器

CPU性能计数器(CPU Performance counter,CPC)有许多别名,包括性能测量点计数器(PIC)、
性能监控单元(PMU)、硬件事件和性能监控事件。它们是可以计数低级CPU活动的处理器寄存器。通常包括下列计数器:

  • CPU周期:包括停滞周期和停滞周期类型
  • CPU指令:引退的(执行过的)
  • 一级、二级、三级缓存访问:命中,未命中
  • 内存 I/O:读、写、停滞周期
  • 资源I/O:读、写、停滞周期

软件

支撑CPU的内核软件包括了调度器、调度器类和空闲线程

调度器
内核CPU调度器的主要功能如下图所示:
在这里插入图片描述
功能如下:

  • 分时:可运行线程之间的多任务,优先执行最高优先级任务
  • 抢占:一旦有高优先级线程变为可运行状态,调度器能够抢占当前运行的线程,这样较高优先级的线程可以马上开始运行
  • 负载均衡:把可运行的线程移到空闲或者较不繁忙的CPU队列中。

方法

CPU性能方法

方法类型
工具法观察分析
USE方法观察分析,容量规划
负载特征归纳观察分析
剖析观察分析
周期分析观察分析
性能监控观察分析,容量规划
静态性能调优观察分析,容量规划
优先级调优
资源控制调优
CPU绑定调优
微型基准测试实验分析
扩展容量规划,调优

工具法

工具法就是把可用的工具全用一遍,检查它们提供的关键项指标。虽然这个方法简单,但由于在某些情况下工具提供的帮助有限,它也会忽视一些问题,另外它也较为耗时。

对于CPU,工具法可以检查以下项目:

  • uptime:检查负载平均数以确认CPU负载是随时间上升还是下级。负载平均数超过了CPU量通常代表CPU饱和
  • vmstat:每秒运行vmstat,然后检查空先列,看看还有多少余量。少与10%可能是一个问题
  • mpstat:检查单个热点(繁忙)CPU,挑出一个可能的线程扩展性问题
  • top/prstat:看看哪个进程和用户是CPU消耗大户
  • pidstat/prstat:把CPU消耗大户分解成用户和系统时间
  • perf/dtrace/stap/oprofile:从用户时间或者内核时间的角度剖析CPU使用的堆栈跟踪,以了解为什么使用这么多CPU
  • perf/cpustat:测量CPI

USE方法

USE方法可以在性能调查的早期,在更深入和更耗时的其他策略之前,用来发现所有组件内的瓶颈和错误。

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

  • 使用率:CPU繁忙的时间(未在空闲线程中)
  • 饱和度:可运行线程排队等待CPU的程度
  • 错误:CPU错误,包括可改正错误

错误可以优先检查,因为检查通常较快,并且最容易理解。有些处理器和操作系统可以改正错误的上升,并在不可改正错误造成CPU失效前关闭一个CPU作为警示。检查错误包括检查是否所有CPU都在线。

使用率通常可以从操作系统工具中的繁忙百分比中获得。这个指标应逐个进行CPU检查,以发现扩展性能问题。也可以逐个检查,以发现某个核的资源严重消耗而空闲硬件线程无法执行的情况。可以通过剖析和周期分析理解为什么有如此高的CPU和核使用率。

对于实现了CPU限制或配额(资源控制)的环境,列如一些云计算环境,CPU使用率需要按照这些人为限制进行检查,而不仅仅是物理限制。你的系统可能已经在物理CPU达到100%使用率之前就耗光了它的CPU配额,比预期更正遇到饱和。

饱和的指标通常是系统全局的,包含在系统负载里。这个指标量化了CPU过载或者CPU配额消耗的程度。

负载特征归纳

对施加的负载进行特征归纳是容量规划、基准测试和模拟负载中立重要的步骤。它也可以通过发现可剔除的无用工作而带来最大的性能收益。

CPU负载特征归纳的基本属性有:

  • 平均负载(使用率+饱和度)
  • 用户时间与系统时间之比
  • 系统调用频率
  • 自愿上下文切换频率
  • 中断频率

工作的目的在于归纳施加负载的特征,而不是性能结果。虽然分解后的使用率/饱和度展示了性能结果,但平均负载反映了CPU的请求负载,因此更为适合归纳负载特征。

频率指标理解起来稍难,因为它们即反映了施加的负载,也在某种程度上反映了能够降低频率的性能结果。

高级负载特征归纳/检查清单
归纳负载特征还需要一些额外的细节。下面这些问题需要好好考虑,在深入研究CPU问题时也可以作为检查清单使用:

  • 整个系统范围内的CPU使用率是多少?每个CPU呢?
  • CPU负载的并发程度如何?是单线程吗?有多少线程?
  • 哪个应用程序或者用户在使用CPU?用了多少?
  • 哪个内核线程在使用CPU?用了多少?
  • 中断的CPU用户量是多少?
  • CPU互联的使用率是多少?
  • 为什么CPU被使用(用户和内核级别调用路径)?
  • 遇到什么类型的停滞周期?

剖析

剖析构建了研究目标的一副图像。CPU用量可以通过定期取样CPU的状态进行剖析,按照以下步骤进行:

  • 选择需要采集的剖析数据以及频率
  • 开始每隔一定时间进行取样
  • 等待兴趣事件的发生
  • 停止取样并收集取样数据
  • 处理数据

CPU剖析数据的类型基于以下因素:

  • 用户级别、内核级别,或者两者
  • 功能和偏移量(基于程序计数器),仅功能,部分栈跟踪信息,或者全栈跟踪

选择全栈跟踪加上用户和内核级别可以采集到完整的CPU用量。然而,这样做通常会生成超大量的数据。仅仅采集用户或者内核级别、部分栈(例如五层栈),或者甚至仅仅是执行函数可能就能从更少的数据中推断CPU的用量。

周期分析

通过使用CPU性能计数器(CPC),我们能够以周期级别理解CPU使用率。这可能会展示消耗在一级、二级或者三级缓存未命中,内存I/O以及资源I/O上的停滞周期,亦或是花在浮点操作及其他活动上的周期。拿到这项信息后,可以通过调整编译器选项或者修改代码以取得性能收益。

周期分析从测量CPI开始。如果CPI较高,继续调查停滞周期的类型;如果CPI较低,就要寻求减少指令数量的办法。CPI的“高”或“低”取决于处理器:低可能是小于1,而高可能是大于10。可以事先执行一些已知的负载以感知这个值的范围。已知负载可以是内存I/O密集型或者指令密集型,然后测量每一个的CPI结果。

除了测量计数器的值之外,还可以配置CPC,在超出某个值时中断内核。

性能监控

性能监控可以发现一段时间内活跃的问题和行为模式。关键的CPU指标如下:

  • 使用率:繁忙百分比
  • 饱和度:从系统负载推算出来的运行队列长度,或者是线程调度器延时的数值

使用率应该对每个CPU分别监控,以发现线程的扩展性问题。对于实现了CPU限制或者配额的环境(资源控制),例如一些云计算环境,还要记录相对于这些限制的CPU用量。

监控CPU用量的一个挑战在于挑选合适的测量和归档时间间隔。有些监控工具采用5分钟,可能会忽视短时间内CPU使用率的突然爆发。更理想的是每秒测量,但是也要知道,爆发可能在1秒内发生。这些信息可以从饱和度中得知。

静态性能调优

静态性能调优关注配置环境的问题。关于CPU性能,检查下列方面的静态配置:

  • 有多少CPU可以?是核吗?还是硬件线程?
  • CPU的架构是单处理器还是多处理器?
  • CPU缓存的大小是多少?是共享的吗?
  • CPU时钟频率是多少?是动态的吗?这些动态特性在BIOS启用了吗?
  • BIOS里启用或者禁用了其他什么CPU相关的特性?
  • 这款型号的处理器有什么性能问题?出现在处理器勘误表上了吗?
  • 这个BIOS固件版本有什么性能问题吗?
  • 有软件的CPU使用限制(资源控制)吗?是什么?

优先级调优

UNIX一直都提供nice() 系统调用,通过设置nice值以调整进程优先级。正nice值代表降低进程优先级(更友好),而负值——只能由超级用户(root)设置——代表提高优先级。nice(1) 命令可以指定nice值以启动程序,而后来加上的renice(1M) 命令用来调整已经在运行的进程。

资源控制

操作系统可能为给进程或者进程组分配CPU资源提供细粒度控制。这可能包括CPU使用率的固定限制和更灵活的共享方式——允许基于一个共享值,消耗空闲CPU周期。

CPU绑定

另一个CPU性能调优的方法是把进程和线程绑定在单个CPU或者一组CPU上。这可以增加进程的CPU缓存温度,提高它的内存I/O性能。

这个方法有以下两个实现方式:

  • 进程绑定:配置一个进程只跑在单个CPU上,或者预定义CPU组中的一个
  • 独占CPU组:分出一组CPU,让这些CPU只能运行指定的进程。这可以更大地提升CPU缓存效率,因为当进程空闲时,其他进程不能使用CPU,保证了缓存的温度。

微型基准测试

CPU的微型基准测试有多种工具,通常测量一个简单操作的多次操作时间。操作可能基于下列元素:

  • CPU指令:整数运算、浮点操作、内存加载和存储、分支合其他指令
  • 内存访问:调查不同CPU缓存的延时和主存吞吐量
  • 高级语言:类似CPU指令测试,不过使用高级解释或者编译语言编写
  • 操作系统操作:测试CPU消耗型系统库和系统调用函数,例如,getpid() 和进程创建

扩展

下面是一个基于资源的容量规划简单的扩展方法:

  1. 确定目标用户数或者应用程序请求频率
  2. 转化成每用户或每请求CPU使用率。对于现有系统,CPU用量可以通过监控获得,再除以现有用户数或者请求数。对于未投入使用系统,负载生成工具可以模拟用户,以获得CPU用量
  3. 推算出当CPU资源达到100%使用率时的用户或者请求数。这就是系统的理论上线。

分析

CPU分析工具

Linux描述
uptime平均负载
vmstat包括系统范围的CPU平均负载
mpstat单个CPU统计信息
sar历史统计信息
ps进程状态
top监控每个进程/线程CPU用量
pidstat每个进程/线程CPU用量分解
time给一个命令计时,带CPU用量分解
DTrace,perfCPU剖析和跟踪
perfCPU性能计数器分析

uptime

[root@node1 ~]# uptime
 15:57:57 up 177 days, 20:30,  1 user,  load average: 0.01, 0.02, 0.00

最后三个数字是1、5和15分钟内的平均负载。通过比较这三个数字,可以判断负载在15分钟内(或者其他时间段)是在上升、下降,还是平稳。

平均负载

平均负载表示了对CPU资源的需求,通过汇总正在运行的线程数(使用率)和正在排队等待运行的线程数(饱和度)计算得出。计算平均负载的一个新方法是把使用率加上相册调度器延时得出,而不是去取样队列长度,从而提高精度。

这个值的意义为,平均负载大于CPU数量表示不足以服务线程,有些线程在等待。如果平均负载小于CPU数量,这(很可能)代表还有一些余量,线程可以在它们想要的时候在CPU上运行。

这三个平均负载值是指数衰减移动平均数,反映了1、5和15分钟以上(时间时间上是指数移动总和里使用的常数)的负载。

Linux平均负载

Linux目前把在不可中断状态执行磁盘I/O的认为也计入了平均负载。这意味着平均负载再也不能单用来表示CPU余量或者饱和度,因为不能单从这个值推断出CPU或者磁盘负载。由于负载可能会在CPU和磁盘之间不断变化。比较这三个平均负载数值也变得困难了。

另外一种包含其他资源负载的方法是为每一种类型的资源分别使用不同的平均负载。

vmstat

虚拟内存统计信息命令,在最后几列打印了系统全局范围的CPU平均负载,另外在第一列还有可运行线程数。

[root@node ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0 190496 745044   2040 1937636    0    0     0     5    0    1 14 12 75  0  0
 0  0 190496 744952   2040 1937636    0    0     0     0 1268 2285  0  1 99  0  0
 0  0 190496 744984   2040 1937636    0    0     0     0 1196 2217  0  0 100  0  0

输出的第一行是系统启动以来的总结信息,r列除外——这个是显示当前值的。输出列如下:

  • r:运行队列长度
  • us:用户态时间
  • sy:系统时间(内核)
  • id:空闲
  • wa:等待I/O,即线程被阻塞等待磁盘I/O时的CPU空闲时间
  • st:偷取,CPU在虚拟化的环境下载其他租户上的开销

mpstat

多处理器统计信息工具mpstat,能够报告每个CPU的统计信息。

[root@webim-service-mq ~]# mpstat -P all 1
Linux 4.18.0-147.5.1.el8_1.x86_64 (webim-service-mq) 	2021年09月09日 	_x86_64_	(4 CPU)

18时19分59秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
18时20分00秒  all    0.50    0.00    0.25    0.00    0.00    0.00    0.00    0.00    0.00   99.25

18时20分00秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
18时20分01秒  all    0.00    0.00    0.75    0.00    0.00    0.00    0.00    0.00    0.00   99.25

18时20分01秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
18时20分02秒  all    0.25    0.00    0.00    0.00    0.25    0.00    0.00    0.00    0.00   99.50

18时20分02秒  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
18时20分03秒  all    0.50    0.00    0.50    0.00    0.00    0.25    0.00    0.00    0.00   98.75
^C

平均时间:  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
平均时间:  all    0.31    0.00    0.38    0.00    0.06    0.06    0.00    0.00    0.00   99.19

选项-P ALL 用来打印每个CPU的报告。mpstat(1) 默认只打印系统级别的总结信息。输出如下:

  • CPU:逻辑CPU ID,或者all表示总结信息
  • %user:用户态时间
  • %nice:以nice优先级运行的进程用户态时间
  • %sys:系统态时间(内核)
  • %iowait:I/O等待
  • %irq:硬件中断CPU用量
  • %soft:软件中断CPU用量
  • %steal:耗费在服务其他租户的时间
  • %guest:花在访客虚拟机的时间
  • %idle:空闲

调优

对于CPU而言,最大的性能收益往往源于排除不必要的工作,这也是一种有效的调优手段。

调优的具体事项——可用的选项以及设置成什么——取决于处理器类型、操作系统版本和期望的任务。

编译器选项

编译器以及其提供的优化代码选项,对CPU性能有很大影响。一般的选项包括了编译为64位而非32位程序,以及优化级别。

调度优先级和调度类

nice(1) 命令可以用来调整进程优先级。正nice值调低优先级,而负值调高优先级,后者只能由超级用户设置。范围-20 —— 19。例如

nice -1 commond

在Linux上,chrt(1) 命令可以显示并直接设置优先级和调度测试。调度优先级也可以通过setpriorty() 系统调用直接设置,而优先级和调度策略可以通过sched_setscheduler() 设置。

调度器选项

在内核上可能提供了一些控制调度行为的可调参数,虽然这些可能不需要进行调整。在Liunx系统上配置了以下配置选项。

选项默认值描述
CONFIG_CGROUP_SCHEDy允许任务编组,以组为单位分配CPU时间
CONFIG_FAIR_GROUP_SCHEDy允许编组CFS任务
CONFIG_RT_GROUP_SCHEDy允许编组实时任务
CONFIG_SCHED_AUTOGROUPy自动识别并创建任务组(例如,构建任务)
CONFIG_SCHED_SMTy超线程支持
CONFIG_SCHED_MCy多核支持
CONFIG_HZ1000设置内核时钟频率(时钟中断)
CONFIG_NO_HZy无tick内核行为
CONFIG_SCHED_HRTICKy使用高精度定时器
CONFIG_PREEMPTn全内核抢占(除了自旋锁区域和中断)
CONFIG_PREEMPT_NONEn无抢占
CONFIG_PREEMPT_VOLUNTARYy在资源内核代码点进行抢占

进程绑定

一个进程可以绑定在一个或者多个CPU上,这样可以通过提高缓存温度和内存本地性来提高性能。

在Linux,是通过taskset(1) 命令来实现的,这个方法可以使用CPU掩码或者范围设置CPU关联性:列如:

[root@webim-service-mq ~]# taskset -pc 2-3 23664
pid 23664 的当前亲和力列表:3
pid 23664 的新亲和力列表:2,3

上面设置了PID 23664 的进程只能跑在CPU2到CPU3。

独占CPU组

Linux提供了CPU组,允许编辑组CPU并为其分配进程。这和进程绑定类型,可以提高性能,但还可以通过使得CPU组独占——不允许其他进程使用——而进一步提高性能。这种权衡另一方面减少了系统其他部分的可用CPU数量。

资源控制

除了把进程和整个CPU关联以外,现代操作系统还对CPU用量分配提供了细粒度资源控制。Linux上的控制组(cgroups),通过进程或者进程组控制了资源用量。CPU用量可以使用份额进行控制,而CFS调度器允许对每段时间内分配的CPU微妙数周期,设置固定上限(CPU带宽)。

处理器选项(BIOS调优)

处理器通常提供一些设置,以启用、禁用和调优处理器级别的特性。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值