欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

ARM中国马闯:详解在Arm架构下的性能检测与提升技巧

最编程 2024-02-21 20:11:13
...

为了更好方便各位开发者和用户了解并应用ECS倚天实例,由阿里云弹性计算联合基础软件团队 & 平头哥 & 安谋科技(Arm China)共同发起的【倚天实例迁移课程】正式上线,本次系列课程共计10节,共分为基础篇架构迁移篇性能优化篇等三个篇章,从不同角度为用户带来更加丰富和专业的讲解。

2023年919日,系列课程第节《Arm®架构下性能分析与优化介绍》正式上线,由安谋科技 (Arm China)主任工程师马闯主讲,内容涵盖:Arm架构下性能监控单元 (PMU) 介绍、Arm统计性能分析扩展 (SPE) 介绍、Arm性能分析工具介绍、Arm架构下性能优化案例分享,本期节目在阿里云官网、阿里云微信视频号、阿里云钉钉视频号、InfoQ官网、阿里云开发者微信视频号、阿里云创新中心直播平台 & 微信视频号同步播出,同时可以点击【https://developer.aliyun.com/topic/ecs-yitian】进入【倚天实例迁移课程官网】了解更多内容。

以下内容根据马闯的演讲整理而成,供阅览:

一、基于性能监控单元 (PMU) 的分析

首先我们介绍基于CPU微架构的硬件事件 (Event) 进行分析的方法。通常软件在服务器上运行的时候,我们想了解软件的运行状态有多种方式,比如可以通过软件的日志了解它的运行状态、错误信息等等。同时,我们还可以监控这台服务器上各种资源的使用情况,包括CPU的使用率、内存、网络、磁盘IO等等数据。这些数据相结合就可以评估服务器整体程序时的监控状况。

那么这些资源是否得到了充分利用呢?我们通常可以通过调整软件或者系统的参数进行优化,但如果我们想要更深入地了解CPU在软件运行中的状态是否存在瓶颈,就需要知道底层硬件的信息。

在这种情况下,我们就需要用硬件的监控技术来实现了,也就是我们通常说的Hardware to Monitor Hardware。现代处理器通常都配备了性能监控单元 (Performance Monitoring Unit, PMU) 来监控硬件的运行状态。

PMU可以跟踪底层的硬件事件,比如跟CPU相关的事件、执行的指令个数、时钟周期数等等;还有一些与缓存相关的事件,比如指令缓存 (ICache) 缺失、ICache的访问次数等等;还有跟TLB相关的事件。这些事件结合在一起就可以反映出程序执行期间CPU的行为,帮助我们更好地对程序进行分析和调优。

Arm平台的PMU主要包括三个部分:

  • 配置寄存器,它允许用户或者软件自己配置,监控我们想要获得的硬件事件。
  • 记录事件的计数器 (Counter),记录特定事件的发生次数。通常每个核心都有多个PMU的计数器,方便我们在同一时间监控多个事件。
  • 专用的计数器,用来记录CPU周期 (Cycle)。

下面介绍一下Arm平台上事件的三种分类,这里会涉及到Arm架构和微架构的概念。架构可以理解为一个指令集,包括内存模型 (Memory model)、行动规范等等,可以理解为是一个标准,它会定义CPU怎么工作或者一种对工作行为的预期,并不会限制或者去定义怎么设计以及实现。微架构是实际的CPU的设计,包括流水线、前端、后端的具体设计,这个由各个芯片厂商自行开发。

接下来介绍一下事件,它大致可以分为三种:

第一种,和架构相关,必须要实现的强制事件 (Mandatory events)。只要使用Arm架构,在设计CPU的时候这部分的事件就一定要实现。

第二种,常见可选事件 (Common optional events)。在设计CPU的时候,厂商可以根据自己的需求选择这类事件进行实现。这里还专门提到了SBSA的认证,它是针对服务器的一个规范。如果芯片厂商设计的CPU要用于服务器领域,虽然有些事件属于常见可选,但如果需要通过SBSA的认证,也必须去实现,这样可以让服务器市场有一个比较规范的统一标准。

第三种,完全依赖于微架构实现的,各个芯片厂商可以根据自己需求定义自己的事件,方便后期做事件的统计和分析。

这是Arm Neoverse™ N2平台上PMU的简要介绍。

在2021年10月,平头哥就推出了全球首个五纳米制程的倚天710芯片。这个芯片就是基于ArmNeoverse N2平台而开发核心,主要面向云数据中心服务器中高性能的CPU芯片。

从上图可以看到,在每个CPU核心上都有六个PMU计数器,也就是说我们在同一时间可以同时采集六种不同类型的硬件事件。另外,我们还有一个专门收集CPU周期的计数器,还包括一些Uncore的PMU计数器。Uncore的意思是,比如倚天710有128个核心,核心和核心之间互相相连,和外设也会相连,它们互联互通的时候会产生一些事件,Uncore的PMU的计数器就会记录这些事件。还有一个是统计分析扩展 (Statistical Profiling Extension, SPE),它是通过硬件的方式实现对指令进行采样。

通常我们有两种分析问题的方式:

第一种,计数 (Counting),即记录某一时间段内发生的硬件事件的次数。这种方法的准确度会比较高,额外的开销也比较少。因为我们有专门的PMU硬件的组件在CPU核心里,它可以直接收集相关的事件。刚才我们提到最多是六个,如果超过六个,常用的软件可以通过复用的方式收集。

第二种,采样,也是我们常用的性能分析的方法,方便我们找到程序中的热点区域。这种方法是在PMU计数器在预设的事件数量,溢出之后会产生一个中断,这个中断会记录当前CPU的信息状态,包括指令的指针、寄存器的状态等信息,相当于在那一时刻为系统拍摄了一个快照。最终这些信息会上传给上层的软件,用于后续的分析。

这些采样数据会包含栈的跟踪、函数注释,有助于我们找到产生事件库的代码。但采样的准确性相对差一些,因为它依赖于产生的中断来收集信息,而中断的产生和执行本身也需要一些执行指令,所以会花费一些时间,也会引入一定的性能开销。尽管准确度有一定的限制,但如果是大量的事件和采样,它依然可以近似地确定代码中的热点函数。

接下来我们先了解一下Neoverse N2核心的微架构的结构图。通常指令一般分为取指、译码、执行、写回四个阶段,通常我们把指令的处理分为前端和后端。

前端负责把指令从内存中预取到CPU,并将它解码、分发和重命名等操作,最终发射到后端。在前端指令的执行都是顺序的 (In-order)。在N2核心上,一个CPU周期最多可以同时解码四条指令到后端,然后后端执行这些指令。

后端负责指令的执行,包括几个执行单元,比如整数、浮点数、Load Store以及并行计算。Arm架构的后端可以乱序执行 (Out-Of-Order)。如果这些指令之间没有依赖的话,就可以乱序执行,这样可以最大程度地提高指令执行的效率。

此外,在微服务架构里还有两个非常重要的部分,一个是缓存 (Cache),另外一个是转译后备缓冲区 (Translation Lookaside Buffer, TLB

缓存分为两种,一种是指令缓存 (ICache,位于前端,用来存储指令;还有一种是数据缓存 (DCache,位于后端,用来存储数据。访问缓存的延迟/命中率,对整体CPU运行的效率有非常大的影响。

TLB是虚拟地址向物理地址转换的映射表,它用来加速内存地址的转换,帮助CPU快速找到虚拟内存到物理内存的地址的映射,从而减少内存的访问。TLB也分为ITLB和DTLB,针对指令的TLB在前端,针对数据的TLB在后端。

一条指令在前端准备好,后端执行完之后最终会成功退役,这是我们最希望看到的结果。

上图中罗列了一些Neoverse N2上主要的硬件事件,大概有150多种事件。不过这些只是一些数字,也就是原始数据,直接看的话很难理解性能是好是坏。所以为了更好地理解这些事件并评估CPU的性能,通常会定义一些指标,通过这些指标判断原始事件是否可以提供有意义的性能分析。

从上图可以看到,我们针对不同的类别,包括缓存的使用效率、TLB的使用效率等定义了一系列指标,这些指标就是一个个的公式,你可以根据指标判断CPU的行为以及性能的特征。有了这些指标之后,我们就可以自己写分析工具了。举个简单的例子,是用Json文件看一下Branch MKPI这个指标,这个指标是(BR_MIS_PRED_RETIRED/INST_RETIRED)*1000,即每1000条指令中有多少条出现了BR_MIS

通过收集事件,再通过工具把它计算出来。有了这些指标之后,就可以看到一些相对直观的数据,比如缓存缺失率是多少,命中率是多少。那么有了这些指标之后,实际上我们还是需要有一个更合适且合理的方法,来利用它们找到系统的瓶颈。

这里我们就要提到一种常用的分析方式叫Top-Down,它是一种基于CPU微架构的性能分析方法。核心思想是通过自顶向下的方式去关注性能优化的目标,并找到性能瓶颈。这个方法最早由Intel的一位工程师提出,并演化成了一套方法论,适用于各种CPU环境上的分析。它将CPU的资源和指令操作联系在一起,提供了一个通用的评估框架。

通过对CPU微指令的分析,可以将应用程序的特征分为不同的倾向性。Top-Down分为两个阶段,阶段一也叫Top-Down的Level 1,Level 1IntelTop-Down解决方案是一致的,它分为四个部分,也就是一个应用程序在运行时它会有四种不同的倾向性,分别是前端bound、后端bound、错误的分支预测、指令的退役。

我们看一下上面这张图,为了找到CPU的瓶颈,重点是要分析出CPU流水线上它有多少时间没有真正地在处理指令,也就是CPU流水线上的利用率。然后分析一下没有处理指令时,是因为哪些方面没有协调好,导致它出现了流水线空转。

我们通常把这种空转叫stall,所以我们经常说前端stall或者后端stall。比如分支预测失败之后,导致了一些指令没有正常的退役。针对空转,需要分析是前端的原因还是后端的原因,前端stall可能和相关的资源有关,比如ICache、ITLB等等;后端stall一般和DCache、DTLB有关,但也包括其他原因。所以通过微架构的结构图,再结合Top-Down的方式,就可以一步一步地定位到系统的瓶颈,这些最终还依赖于PMU提供的基础数据。

刚才提到出现stall后分析stall的原因有前端和后端。还有一部分叫错误的分支预测,它代表了一种特定的性能的瓶颈类型,与其他的类型有明显的区别。

分支预测一般出现在CPU中非常关键的组成部分,它用于指导程序的一种执行的流程。但当分支预测失败的时候,CPU就必须回退到之前的状态,并重新开始执行不同分支上路径的指令。这种回退和重新开始通常会引入额外的时钟周期和指令执行,会导致性能的下降。因此,过高的错误分支预测会导致性能的损失。

所以我们专门有一个性能错误的分支预测的指标来判断分支预测,有助于我们识别程序中分支预测的问题,并指导我们进行性能优化的工作。例如我们可以去代码里看看相关的热点,是否是分支错误产生的热点,是否有更好的算法和代码结构,减少分支预测失败的发生。

此外,还有一个我们最希望看到的退役的指令的占比,理想情况下我们希望所有的指令都可以在运行过程中正常退役,因为它与我们后面要提到的每周期指令数 (Instruction Per Cycle, IPC) 是密切相关的。但退役比例过高是不是就没有优化空间呢?这个也是可以探讨的,它依赖于程序的运行状态或程序的运行场景。通过后面例子可以看到即使退役的指令占比较高,也还是有一定的优化空间。

上图中阶段二是微架构层面的指标,也是Arm Top-Down完整的解决方案的一部分。另外,IPC也是一个比较重要的指标,每个CPU最多可以有多少条指令正常的退役。因为我刚才提到N2上前端同时最多可以解码四条指令,所以理想的状态下是IPC=4是它的最高值。

这里我们可以想一下,如果IPC真的达到4了,是不是就表示程序的性能非常好呢?答案是不一定的,要看在IPC=4的时候,程序到底在做什么工作。比如它在做一个死循环或者自旋锁 (Spin lock),虽然看起来CPU非常忙,而且运行也非常顺利,所有的指令都退役了,但它陷入了一种循环的状态,并没有执行软件本身想要做的工作,这也是对CPU的一种浪费。所以这里再次强调,这些指标都要结合实际情况分析,单独某个指标,比如IPC过高也不一定表示它的性能更好。

下一个是Pipeline Stalls,可以看到前端Stall rate和后端Stall rate,后面是对应阶段二的一些指标。前端bound、后端bound、错误的分支预测、指令的退役这四个就是我们刚才说的Top-Down的四个指标。我们发现了这个软件的前端Bound、后端Bound、错误的分支预测、指令的退役它的占比哪一个倾向性更高,都可以到阶段二的微架构里查看相关的指标,是什么原因导致占比过高。比如前端我们可以看ITLB 事件和ICache相关的指标,后端是数据相关的,可以看一些和系统内存相关的事件。

我们有了这些分析方法,还需要相关的工具。接下来简单介绍一下Linux Perf,它是一个使用非常广泛的开源工具。它用来收集PMU的事件,Linux内核里面有一个叫Perf事件的子系统,这个子系统可以捕捉来自不同来源的性能事件,包括软件的事件,也包括处理器的硬件的性能事件。PMU所产生的事件都可以通过它捕捉到。

从上图可以看到,每个核心里都有一个PMU的硬件,想要捕捉到这些硬件事件,还需要提供相关的驱动。比如Arm Neoverse N2的核心,我们就会提供相关的驱动程序并提交到内核里面,芯片厂商制作自己的芯片之后,也会实现自己PMU相关的驱动并提交到内核中。这样的话在内核层面有了完善的配置和支持之后,Perf才能顺利地采集到相关的事件。

Perf的使用也是基于我们之前说的几种方式。计数是perf stat –e加上我们想要收集的事件;采样是perf record –e加上想要收集的事件,这里还可以设置采样的频率等等参数。SPE一会儿我们专门去讲,Perf也可以直接支持。

基于Perf还有一些非常实用的衍生工具,便于我们进行性能分析。比如火焰图,它是一种可视化的性能分析工具,通常它可以和Perf结合使用。火焰图层级的结构的方式展示的函数的调用关系,每一个长条代表一个函数,宽度代表函数在执行期间占总执行时间的占比,不同颜色代表不同的函数或者类别。

火焰图还有一定的交互性,点击每一个相关的函数,它会提供相关的交互操作,可以放大、缩小、过滤、深入地分析性能数据等等,帮助我们快速直观地定位到性能问题。

二、统计分析扩展

上一篇: 创建一个新的Flask应用项目

下一篇: 中国飞腾推出全新ARM v8架构服务器处理器,与Intel性能相当