高效可靠的处理器微体系结构性能测量技术

简介: 本次分享的主题是高效可靠的处理器微体系结构性能测量技术,由华东师范大学系统优化实验室的博士研究生刘通宇分享。主要分为两个部分:1. 关于Core PMU的工作2. ARM架构下的的内存带宽质量问题

高效可靠的处理器微体系结构性能测量技术

内容分析:

1. 关于Core PMU的工作

2. ARM架构下的的内存带宽质量问题

 

image.png

今天分享的主题主要侧重于处理器微体系结构的性能测量。先简单介绍我们实验室的工作。

image.png

主要做数据驱动和系统优化。整个系统优化的过程是一个三步走的闭环,从可靠的性能开始通过一些工作负载分析,包括一些 Monitoring、Profiling、Tracing 手段收集性能数据,再通过一些具有可解性的性能分性能分析方法,包括 Iron law、TMAM、CPI Breakdown 分析方法得到性能瓶颈。再针对性能瓶颈做一些特定的优化,包括编译器层面的一些优化,以及二进制翻译以及 PGO/LTO 方面的一些优化。这些是我们实验室整体的方向。

image.png

如果要对软硬件全栈做一个全量的性能分析,从上层的工作负载开始,包括一些 Benchmark、Real-life Application,然后到系统软件各类资源的利用率,再到底层的硬件。要做整个全量分析需要考虑一个很关键的问题就是如何去适应多样化的硬件。可以看到数据中心中,可能有不同型号的不同代机的不同架构的处理器。可能会同时存在于数据中心内,所以怎么去应对硬件碎片化的问题是我们需要特别关注的一个问题。

image.png

今天分享的主要有以下几个方面。如果使用架构处理,主要还是在PMU 中。PMU 分为 Core PMU 和 Uncore PMU。Core PMU 主要是在处理器和内部的一些 PMU。Core PMU 是一些多个和直接共享的一些组件,包括 System Level Cache 以及 Memory Controller 和I/O Device 相关的一些组件,上面也会有一些 PMU。今天我分享两个工作,一个是关于 Core PMU 的工作,怎么样才能更高效的复用这些硬件性能计数器,针对 Core PMU,主要解决问题是解决不同架构之间处理器的碎片化问题。然后,第二个工作是 ARM 架构下的内存带宽质量问题。在 ARM 架构上去看设备碎片化问题。

 

01.关于 Core PMU 的工作

image.png

先介绍 Core PMU 的高效复用。

image.png

Redis 跑在 Arm 架构上有如图的性能报告,有很多指标包括指令集流水线、Cache、Memory access、Instruction Mix 方面的一些性能指标。

image.png

这些性能指标都是通过 PMU 采的一些性能事件,通过性能事件的计数值去导出这些性能指标。图上列了一些性能指标如何来的。

image.png

PMU 面临一个最关键的问题是要测事件太多但是计数器很少。上图是一个 Arm v8的结构,分为两种性能计数器。下面六个叫通用型的计数器,可以通过旁边的控制寄存器去决定这些寄存器监测哪一种事件。上面的是专用计数器,只能监测一个特定的性能事件。主要有两种。但是大体上由于计数器本身是处理器内部的寄存器,所以数量不会很多,与上一张图上的需要采的性能事件相比还是太少。

image.png

通常做法是做复用,做分组,在不同的时间片让这些事件调度到计数器上做测量。可以在一次测量中拿到所有需要测量的事件。上图例如有十个时间要测,但是只有四个计数器可以用,可以把十个计数器分成三组,每组各占用三分之一的时间去做测量。

image.png

复用实际上还是需要用户态时间的测量工具与操作系统内核,包括底层的硬件性能计数器共同工作。最上一层是用户态的测量工具,会根据需要测量的指标去定义事件组,将事件组送到操作系统的内核中Perf_Event Subsystem 负责,Perf_Event Subsystem 会负责不同事件组的调度,不同时间内把事件组放到计数器上做测量。该流程需要硬件以及操作系统内核以及底层的工具进行工作。在复用过程中因为有些事件并不是全程在做测量,所以拿到事件的计数值,并不代表整个程序的运行期间真实发生的事件数量,所以接着需要做一个估计。例如每个事件只采了三分之一的事件,会将原始的计数值除以三分之一放大得到一个估计值。三分之一称为采样比,采样比越高,对于得到的数据更加准确。

image.png

现在的工具存在一些问题。一些工具的实践 LIKWID(x86上的性能测量工具)、Arm Top-down Tool(Arm 官方提供的开源的测量工具),事件组定义包含的事件数量不多。事件组只包含2-4个事件,数量低于可用的性能计数器数量。如果将这些事件组送入 Predefined event 中做调度,可能会出现这样情况:对计数器利用率不高,有些计数器会空洞,没有利用到。第二是整个调度器会产生不公平的现象,第一个事件组在一个周期中被调用1或两次,但是第二个第三个事件组只被调用一次。

image.png

上图列出了一些工具的事件组。包含的数量是两个到四个。

image.png

第二个问题是操作系统在做复用计数器的调度时,调度的策略存在一些问题。如果将八个事件送入 Perf_Event 中做调度,最后的采样比数据如图。前三个事件使用专用计数器做测量,但是采样率不是百分之一百。第二个是45678事件使用通用计数器做测量,但是第八个事件采样率远远低于其它同样使用通用计数器的事件。第三个是8个事件进入后,计数器的利用率反而下降。7个事件时计数器都可以百分百利用,但是如果放8个事件,平均用到6.25个性能计数器。所以 Linux 内核对事件复用的调度计数器存在一些缺陷。

image.png

第三个问题是处理器内部到底有多少个性能计数器不容易得知。首先x86上如果将 NMI Watchdog 进程打开,会占用一个通用性能计数器,所以并不是所以存在的性能计数器都可以用来测量。第二是 Arm 架构的处理器,厂商可以做一些定制化操作,实际上处理器到底做了多少个计数器与架构的定义存在偏差。例如 Kunpeng920基于 Armv8 实现,Armv8 官方文档中写明每个核上的计数器是6个,但是 Kunpeng920 实现了12个。所以到底有多少计数器可用值得探讨。

上述讲了 Core PMU 上复用的三个问题。

image.png

第一个是到底有多少计数器可用,第二是 Perf_event 调用机制的问题,第三是上层用户态的事件分组效率高不高效。针对这三个问题形成了一套解决方案:在 Arm 和x86上都适用的一套框架。

第一个方案是到底有多少计数器可用。

image.png

如果想知道有多少性能计数器可用,只要找到能被同时测量的事件最大值。例如一个事件放入是100%,两个事件也是100%,到5个事件时每个事件发生复用,每个事件只有80%能够用于测量。复用触发后可以得知现在有4个计数器可用,是一种压力测试的思路。

image.png

但是事件之间存在一些性能约束。有的事件不能放在一起采,所以需要考虑这方面因素。在每一步加的过程中需要做一些检测。查看新加的事件是否和原有的事件产生冲突,保证在加的过程中可以顺利进行。通过这样的方法找到 Kunpeng920上有12个计数器可以用。这是关于计数器探测的问题。

下一个是 Linux 内核如何调用性能事件。

image.png

右侧是算法描述,左侧是八个事件在操作系统中调用的示意图。调度分为两层,一个是平台无关层调度,一个是平台相关层调度。平台无关层调度会将事件顺序调换,让每个事件用到底层计数器。平台相关层将事件分配到相关计数器上。第一行最开始8个事件放入后,在平台无关层按照顺序一个个向相关层送性能事件。平台相关层将事件塞入某个计数器上。到第八个事件送到平台相关层分配计数器时,会发现所有计数器已经用满。第八个事件无法塞入,就会向平台无关层通知分配已经失败,调度结束。

在第二轮调度时就会出现问题,第二轮调度时会更改每一轮事件的顺序,将第一个事件挪到最后,事件就会变为23456781,按照顺序逐个往相关层送性能事件,到第八个事件后会产生问题。第八个事件需要通用型计数器,但此时通用型计数器都被占满,所以第八个事件还是不能塞入。该轮调动失败,不会再对后面事件进行分配,调度结束。会导致在该轮调度中,计数器会空,345依次往后,导致第八个事件的采样率远远低于其他事件。这就是调度内核缺陷的成因。概括就是操作系统不会使用专用计数器做事件的测量。

image.png

这是用户态的解决方案。既然操作系统内核对于使用专用计数器的性能事件处理不够好,就不让使用专用计数器的性能事件参与调度。在用户态固定住这些事件,不让这些事件送到内核做调度。

image.png

最后是如何才能做比较高效的事件分组。如果已经探测到可以有多少计数器可用,那么我们希望每个事件组尽可能包含的事件数量尽可能接近可用计数器的数量,这样在每一轮调度过程中这些事件组可用尽可能使用满计数器。通过这种思路想到一个算法,既遵循用于测量同一个性能事件在一个事件组中的约束,又尽可能合并这些事件组,让每个事件组尽包含的事件数量尽可能接近可用计数器的数量。

image.png

具体做法如图,优化效果使用 Arm Top-Down Tool 定义的事件分组进行一些优化。可用看到这么多指标只需要三个分组就可用进行测量。这样定义分组可以有效提高事件采样率。

image.png

在复用计数器做测量的情况下,事件采样率在 Arm 和 LIKWID 上都有50%的提高,极大改善计数器的数量。

以上是关于 Core PMU 复用的问题。

 

02.ARM 架构下的的内存带宽质量问题

image.png

第二部分是内存带宽测量的问题。内存带宽是一个重要的性能指标。

image.png

CPU 和内存之间存在一些差距。大模型模型的数据量很大,内存带宽会成为性能瓶颈。做工作负载分析时也需要看内存带宽。

image.png

但是在Arm上是否容易做呢?先来看x6。Intel 上有一份详细文档UnCore Performance Monitoring,介绍了所有 UnCore 组件的 PMU 的情况以及 PMU 上每个性能事件的情况,每个事件都有详细的说明。例如做内存带宽时,可用在文档中找到 CAS_COUNT.WR event获取内存控制器读和写的次数。CAS_COUNT.RD 中可以看到64bit的读或写,用这个计数值乘 Time 可以得到读写的带宽。

image.png

操作系统对于 Intel 上 Uncore 设备的支持比较好,例如现在有一个 Cas Cache 处理器在内核4.5后就有默认的支持,在5.7后对 Imc Cache 也支持。内核直接升到对应版本后就可以在操作系统的设备数下看到 Uncore_Imc 的设备,对应的是控制器。设备中会暴露一些定义好的性能事件,如图可以看到 Cas_Count_Read 和Cas_Count_Write。之后在 Perf 中调用两个事件可以很轻松测出带宽,也可以得知是 Socket0 或 Socket1 上的带宽,区分读写。最终根据数据计算带宽。

在 Intel 上并不复杂,所以在 Arm 上也使用该想法。

image.png

在 Arm 上的 Memory Controller 中找到定义的性能事件,查看官方文档使用哪些进行测量。第一是如何访问到 Arm 下的内存控制器。此处使用了一个 Ampere Altra 控制器。

image.png

首先在 Ampere Altra 下将内核升到最新版本,发现内核设备数量还是没有内存控制器的设备,然后查看了内核编译的参数,发现是需要打开 CONFIG_ARM_DMC620_PMU Kernel 内核选项,才能重新编到内核才能看到 Arm_DMC620 设备。点开设备可以看到定义了很多性能事件。此处会出现无法知道使用哪个事件做测量,Arm 官方 DMC 文档中也没有提及。下面是可以测量的公式:使用 Clkdiv2_rdwr 事件。在该事件后增加两个字段来区分读写。并且需要在每个内存控制器上对事件进行采样,对采样时间做求和再乘64,最后得到读写的带宽。

但是这样会很复杂。

image.png

首先 Arm 架构的芯片的内存控制器很多样, Ampere Altra 使用的是 DMC620 ,但是 Yitian710、Amazon Gravition2 等机器寄存控制器都是不同的。如果想要测量这些芯片的带宽是否需要每个处理器都单独提供一套方案,这是非常复杂的。此外如果每台机器都提供一套方案,也会遇到以下几种阻碍:首先内核是否有驱动的支持,使用哪个性能事件。即便知道使用哪个性能事件,如何才能使用性能事件导出带宽的数据。

image.png

虽然内存控制器使用的都不同,但是有一定数量的芯片使用 Arm 公版的 CMN 线上网络,例如 Ampere Altra、Yitian、Gravition2。所以使用 Arm 公版的线上网络机制来提出一套通用化的内存带宽通用方法是可行的。

image.png

线上网络的结构可以理解为一个芯片是一整个 Mesh 形状,右侧中间的框为XP节点,可以用来放不同的设备,例如 Core、内存控制器或与I/O相关的设备等。XP 节点本身有 PMU Controller,可以监控XP 节点连接的设备的流量。所以如果可以找到内存控制器的 XP 节点,通过对应的 XP 节点的PMU去监控和内存控制器相连的流量,就可以用另一种方式拿到内存带宽。这就是以一个通用的方式测量内存带宽。但这种也存在问题:如何知道是哪一个 XP 节点连接的是Memory Controller,这是一个需要讨论的问题。

image.png

微架构性能测量本身需要底层硬件、用户测量工具以及操作系统内核去共同完成,可靠性能数据关系到后续的性能分析。本次没有提到的一些细节可以在上图中的一些论文中查看,这些已经发布的论文中讲解 Core PMU 如何进行复用以及一套性能分析工具,能够朝着跨平台的性能测量和性能分析去努力。

目录
打赏
0
0
0
0
1007
分享
相关文章
探索后端技术:构建高效、可扩展的系统架构
在当今数字化时代,后端技术是构建任何成功应用程序的关键。它不仅涉及数据存储和处理,还包括确保系统的高效性、可靠性和可扩展性。本文将深入探讨后端开发的核心概念,包括数据库设计、服务器端编程、API 开发以及云服务等。我们将从基础开始,逐步深入到更高级的主题,如微服务架构和容器化技术。通过实际案例分析,本文旨在为读者提供一个全面的后端开发指南,帮助大家构建出既高效又具有高度可扩展性的系统架构。
114 14
构建高效可扩展的后端系统架构
【2月更文挑战第9天】本文将介绍如何构建一种高效可扩展的后端系统架构,以满足不断增长的用户需求和应对大规模并发请求。我们将讨论关键的技术要点,包括分布式计算、负载均衡、缓存和数据库优化等,帮助读者在设计和开发后端系统时做出明智的决策。
159 7
NServiceBus:打造企业级服务总线的利器——深度解析这一面向消息中间件如何革新分布式应用开发与提升系统可靠性
【10月更文挑战第9天】NServiceBus 是一个面向消息的中间件,专为构建分布式应用程序设计,特别适用于企业级服务总线(ESB)。它通过消息队列实现服务间的解耦,提高系统的可扩展性和容错性。在 .NET 生态中,NServiceBus 提供了强大的功能,支持多种传输方式如 RabbitMQ 和 Azure Service Bus。通过异步消息传递模式,各组件可以独立运作,即使某部分出现故障也不会影响整体系统。 示例代码展示了如何使用 NServiceBus 发送和接收消息,简化了系统的设计和维护。
85 3
探索微服务架构:构建灵活、可扩展的后端系统
【8月更文挑战第25天】 本文将引导您理解微服务架构的核心概念,探讨其对现代后端系统设计的影响。我们将从基础讲起,逐步深入到微服务的高级应用,旨在启发读者思考如何利用微服务原则优化后端开发实践。
57 4
传统架构与RISC-V架构有什么区别?
计算机架构的发展经历了多个阶段,从最早的CISC(复杂指令集计算机)到后来的RISC(精简指令集计算机)。RISC-V作为一种新兴的RISC架构,以其开放性和模块化设计受到广泛关注。
124 2
构建高效后端系统:面向未来的架构设计原则
【8月更文挑战第8天】在技术飞速发展的今天,后端系统的架构设计显得尤为关键。本文将探讨如何通过采用微服务、容器化及自动化等现代技术手段,来构建一个可扩展、高可用且易于维护的后端系统。我们将深入分析这些技术背后的原理及其在实际场景中的应用,同时也会讨论如何在保障数据一致性和系统安全性的前提下,提升系统的响应速度和处理能力。
世界最快硬件加速器Groq LPU的底层架构设计!
【2月更文挑战第19天】世界最快硬件加速器Groq LPU的底层架构设计!
165 1
世界最快硬件加速器Groq LPU的底层架构设计!
【优化技术专题】「底层架构原理系列」CPU处理器鲜为人知的那些秘密
【优化技术专题】「底层架构原理系列」CPU处理器鲜为人知的那些秘密
411 0
【优化技术专题】「底层架构原理系列」CPU处理器鲜为人知的那些秘密
灵活的物理层设计 | 带你读《5G系统关键技术详解》之二
本书深入介绍了 5G 无线网络的协议、网络架构和技术,包括无线接入网络、移动边 缘计算、全双工、大规模 MIMO、毫米波、NOMA、物联网、M2M 通信、D2D 通信、 移动数据分流、干扰抑制技术、无线资源管理、可见光通信和智能数据定价等关键主题。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等