baron · 7月5日

Armv9的PMU详解

快速连接

👉👉👉【精选】ARMv8/ARMv9架构入门到精通-目录 👈👈👈

目录

  • 2 概述
  • 2.1 范围
  • 3 架构和微体系结构定义
  • 3.1 Arm体系结构定义
  • 3.1.1 可归因性
  • 3.1.2 PMU版本
  • 3.1.3 技术上执行与架构上执行
  • 3.1.4 局部取出
  • 3.1.5 对齐/不对齐内存访问
  • 3.2 Neoverse N1 微体系结构信息
  • 3.2.1 CPU和DynamIQ共享单元配置
  • 3.2.2 流水线和操作
  • 3.2.3 乱序执行
  • 3.2.4 架构定义的事件
  • 3.2.5 缓存体系结构
  • 3.2.6 缓存行大小
  • 3.2.7 数据侧缓存分配
  • 3.2.8 指令侧缓存分配
  • 3.2.9 DSU L3缓存分配
  • 3.2.10 缓存术语和行为
  • 3.2.11 缓存维护操作
  • 3.2.12 缓存一致性
  • 3.2.13 L2缓存和内存接口交互
  • 3.2.14 缓存查找
  • 3.2.15 缓存逐出
  • 3.2.16 不对齐访问
  • 3.2.17 内存管理单元行为
  • 3.2.18 TLB行为
  • 3.2.19 TLB维护操作
  • 3.2.20 内存错误行为
  • 3.2.21 一致性Mesh网络配置

2 概述

本文档描述了在Neoverse N1中实现的不同性能监视单元(PMU)事件的行为。
Neoverse N1具有六个可编程的32位计数器(计数器0-5),每个独立计数器都可以被编程为在本文档描述的PMU事件之一发生时进行计数。

2.1 范围

本文档提供了对Neoverse N1 PMU事件的高层描述。其中包含对体系结构行为和Neoverse N1微体系结构行为的参考,以澄清这些事件的描述。如需更完整的Arm体系结构描述,请参考Arm®体系结构参考手册Armv8-A。如需有关Neoverse N1的更详细描述,请参考Arm® Neoverse™ N1技术参考手册。
本文档不讨论使用软件开发工具或性能分析程序(如Linux perf)来编程Neoverse N1 PMU的内容。
某些PMU事件可能在Neoverse N1软件开发人员勘误通知(SDEN)中进行讨论。鼓励用户查阅该文档以获取有关他们正在使用的事件的信息。

3 架构和微体系结构定义

本节提供有关Arm体系结构相关领域和Neoverse N1微体系结构详细信息的附加说明。该部分涵盖了影响Neoverse N1中实现的不同PMU事件行为的体系结构和微体系结构功能领域。

请注意,本节旨在不是Neoverse N1的体系结构或微体系结构行为的完整指南。有关更完整的概述,请参考:
• Arm Cortex-A Series程序员指南,针对Armv8-A,
https://Developer.Arm.com 上提供的A-Profile体系结构指南。
• Arm®体系结构参考手册中PMU事件章节的“Definitions”部分。

3.1 Arm体系结构定义

Arm®体系结构参考手册Armv8-A的术语表部分包含用于PMU事件描述的不同体系结构术语的定义。本节为其中一些术语提供了额外的解释(特别是适用于Neoverse N1的术语)。

请注意,在所有情况下,应使用Arm®体系结构参考手册Armv8-A中的实际规范。

3.1.1 可归因性

一些事件描述引用了术语“可归因性”,该术语在Arm®体系结构参考手册Armv8-A的PMU部分中有定义。通常,该术语是指一个事件是否可以归因于单个处理元素(PE)。在这个上下文中,可归因性可以指两种情况:
• 可归因于同时多线程(SMT)CPU中的硬件线程。由于Neoverse N1不支持多线程,因此在此意义上使用的“可归因性”不适用。
• 可归因于多CPU集群或系统中的特定CPU。当该术语适用于系统中的其他CPU时,它在PMU事件描述中得到了明确解释。

3.1.2 PMU版本

Neoverse N1实现了Armv8.1的PMUv3。该信息在ID_AA64DFR0_EL1寄存器中的PMUVer位中指定。

3.1.3 技术上执行与架构上执行

Arm体系结构区分技术上执行的指令和在架构上执行的指令。例如,在分支指令之后(其中CPU已经预测了分支条件),被认为是在技术上执行的,直到分支被解析。如果由先前执行的指令引发中断或异常,指令也可能被放弃。在执行结束时,架构上执行的指令将更新CPU的架构状态。

如果分支被错误地预测,并且指令被技术上执行,它们将不被视为在架构上执行。Arm®体系结构参考手册Armv8-A还将在架构上执行的指令称为“已退役”或“已提交”。技术上执行的指令如果在架构上未执行将被放弃;即它们的结果将被丢弃,并且不计入程序流的一部分。

当发现指令位于程序流的正确执行路径上时,该指令被视为在架构上执行。虽然Neoverse N1 CPU可以乱序执行指令,但在程序顺序中总是解析架构上执行的指令。请参见下文的乱序执行部分。

许多PMU事件测量技术上执行的操作。Arm®体系结构参考手册Armv8-A表示:“技术上执行的定义并不仅仅指那些技术上执行然后被放弃的操作,例如由于分支错误预测或故障。也就是说,技术上执行的操作必须计算错误和正确执行路径上的操作。”

这一定义意味着计算技术上执行的指令的事件将包括在架构上执行以及未在架构上执行的指令。

有关更多信息,请阅读Arm®体系结构参考手册Armv8-A的“Speculative”和“Architecturally executed”部分的定义。

3.1.4 局部取出

Arm®体系结构参考手册Armv8-A术语表将“局部取出”定义为在未虚拟化的情况下引发的异常;实际上,该异常是由主机内核引发的。为了将异常视为局部取出,必须满足以下条件之一:
• 内核运行在EL1
• 内核运行在EL2且启用了主机虚拟化扩展(HCR_EL2.E2H和TGE均设置为1)

请注意,某些异常事件不使用该定义。例如,HVC异常通常会在EL2中局部引发(因为超级监视器在EL2中运行),而SMC异常将在EL3中引发。

由技术上执行的指令或技术上的内存访问引起的异常将在引发导致异常条件的指令在架构上执行之前不会发生。

3.1.5 对齐/不对齐内存访问

内存访问是对齐的,如果访问的地址是数据大小的倍数。例如,一个字(32位访问)如果地址以0x00、0x04、0x08或0x0C结尾,则是对齐的。如果地址不在对齐边界上,则是不对齐的。例如,一个字访问,其地址以0x01、0x02、0x03、0x05、0x06结尾,是不对齐的。

虽然CPU可以处理对不对齐地址的数据侧访问,但CPU向内存系统发出对齐的访问。例如,对于一个32位访问位于以0x01结尾的地址,CPU将发出一个更大的访问,比如以0x00结尾的地址上的64位访问。

请注意,如果访问是可缓存的,并且数据不在缓存中,则可能将包含该数据的整个缓存行带入缓存。缓存行的对齐方式也与缓存行大小一致。

缓存行大小在第3.2.6节“缓存行大小”中有讨论。

3.2 Neoverse N1 微体系结构信息

Neoverse N1实现了Armv8-A体系结构和Armv8.2-A体系结构扩展。然而,有一些处理器特性,如流水线和缓存,是特定于实现的。本节定义了这些特性和行为。

请注意,Arm的文档可能将CPU称为“核”。本文档提到Neoverse N1 CPU,但这个术语可以与“核”术语互换使用。

3.2.1 CPU和DynamIQ共享单元配置

Neoverse N1要求具有DynamIQ共享单元(DSU)作为CPU与外部互连之间的接口。DSU是一个独立的逻辑部件,包含Neoverse N1的所有外部接口,包括总线接口、功耗管理接口、中断控制器接口,以及所有的功耗和时钟接口。
对于某些配置,DSU还包含一个可选的L3缓存,以及用于跟踪DSU集群内一致性请求的(必需的)Snoop Control Unit(SCU)。对于L3和SCU配置,DSU包含其自己的一组PMU计数器和事件。
设计者可以使用两种不同的方式实现Neoverse N1中的DSU:
• 直连方式:在这种实现中,DSU内部有一个单独的Neoverse N1,DSU没有L3缓存或SCU。到Neoverse N1的内存事务直接通过DSU包装器传递。该配置需要在关联的相干网格网络(CMN)CHI-based互连中具有特殊连接。大多数生产中的Neoverse N1设计使用这种实现方式。
• 多个CPU:在这种实现中,最多四个Neoverse N1 CPU包含在一个带有一个DSU的单个集群中,带有SCU逻辑和一个可选的共享L3缓存。这种实现方式用于Arm Neoverse N1SDP开发平台,该平台有两个集群,每个集群有两个Neoverse N1 CPU。
有关DSU的更多信息,请参阅Arm® DynamIQ™ Shared Unit Technical Reference Manual。

3.2.2 流水线和操作

以下图表显示了Neoverse N1指令处理流水线的高层级结构。

image.png

Neoverse N1流水线获取指令后(经过一些内部解码),通过流水线寄存器重命名和分派阶段进行处理。这些解码后的指令在分派阶段可能会进一步分为两个微操作(uops)。一旦分派,uops 就等待其操作数,并且以无序方式发射到八个执行流水线中的一个。在发射阶段有多个发射队列,但每个执行流水线每个周期只能接受和完成一个 uop。

请注意,虽然一些较为简单的指令(例如 ADD 或 MOV)可能会被拆分为一个单一的微操作,其他指令可能会被分解为多个微操作。Arm 不公开微操作的列表。

对于 PMU 事件的定义,一些事件明确计数指令,而其他事件计数微操作(称为操作)。请注意在事件描述中使用“操作”或“指令”这一术语。

3.2.3 乱序执行

Neoverse N1流水线可以乱序发射和执行指令。只要不同指令之间不存在数据依赖关系,它们可以以无序方式进行推测执行并保存其结果。这允许流水线将指令发射到不同的后端流水线,以便流水线尽可能执行尽量多的指令。

这些推测执行的指令可以被提交或解析为在架构上执行。在架构上执行的指令总是按程序顺序解析(即实际软件指定的顺序)。

由于程序控制流的变化,推测执行的指令可能不会被架构上执行。例如,如果在误预测的分支指令之后推测执行了指令,那么这些推测执行的指令将被放弃。如果发生异常,指令也可能被放弃。当发生异常时,CPU 将确定在程序流中最后一个架构上的指令在哪里,然后将剩余的指令放弃(即使其中一些已经推测执行)。这些推测执行的(但被放弃的)指令可以在异常返回后再次执行。

对于正常内存的内存加载指令也可以进行推测执行。根据架构定义,对正常内存的读访问可以重复。如果CPU发出的内存加载操作后来被放弃,与内存相关的 PMU 事件可能会计数(如果实际内存访问已完成)。具体的 PMU 事件描述将提供这些条件。

3.2.4 架构定义的事件

本指南中列出的大多数 PMU 事件是经过架构定义的,并列在Arm®体系结构参考手册Armv8-A的性能监视器扩展部分。然而,Neoverse N1上并未实现一些经过架构定义的事件。

3.2.5 缓存体系结构

Neoverse N1实现了独立的指令(I-side)和数据(D-side)一级缓存,以及一个统一的二级缓存。Neoverse N1的缓存特性包括:
• 读/写分配:任何可缓存的内存访问都会尝试在Neoverse N1缓存中分配一个缓存行。
• 写回缓存:写入缓存的数据不会更新外部内存,除非缓存行被逐出或通过缓存维护操作进行显式请求。

image.png

3.2.6 缓存行大小

Neoverse N1和其他v8-A CPU中的缓存行大小为64字节(16个字长)。无论何时数据被分配到缓存中,或者从缓存写回或逐出,都将读取整个缓存行或写出整个缓存行。虽然可以首先将单个32位字或64位双字读入缓存(这些称为关键字 - 即负载或存储指令指定的直接字),但围绕该字的整个缓存行将被分配到缓存中。在整个缓存行被读入之前,CPU将能够首先访问关键字。

Neoverse N1缓存是组相联缓存;也就是说,缓存中有多个缓存行的方式,一个特定地址可以存储在其中。两个L1缓存都是4路组相联缓存,而L2缓存是8路组相联的。当PMU事件描述中使用术语“full”时,指的是缓存中一个特定地址可以存储的路已满。

例如,在完整的64K缓存中,一个L1缓存只能分配给其中4个缓存行。如果这4个缓存行都在同一组中,并且还需要在该组中分配另一个缓存行,那么其中一个缓存行将需要被逐出。

3.2.7 数据侧缓存分配

L1数据缓存相对于L2统一缓存是强制包含的。强制包含意味着存在于L1数据缓存中的任何缓存行也将存在于L2统一缓存中。然而,L2缓存也可能包含在L1数据缓存中不存在的缓存行。

3.2.8 指令侧缓存分配

L1指令缓存相对于L2统一缓存是弱制包含的。弱制包含意味着缓存行最初会被分配到L1指令缓存和L2缓存中,但可以后来从L2缓存中逐出。

3.2.9 DSU L3缓存分配

如果Neoverse N1在具有DSU L3缓存的系统中,L3缓存将按以下方式分配缓存行:
• 如果缓存行仅存在于DSU集群内的一个CPU中,则L3使用专有分配;也就是说,直到该缓存行从包含该缓存行的CPU中逐出之前,缓存行不会分配到L3中。
• 如果缓存行存在于DSU集群内多个CPU中,则L3使用包容分配;也就是说,如果缓存行被多个CPU共享,则将在L3缓存中分配该行。

3.2.10 缓存术语和行为

如果数据缓存行在加载到缓存后没有被修改,则被视为“clean”;如果缓存行中的数据已更改,则被视为“dirty”。如果缓存已满,并且需要分配新的缓存行,那么将逐出一个现有的缓存行 - PMU事件中使用的术语是“refill”。

3.2.11 缓存维护操作

Arm®体系结构参考手册Armv8-A定义了一系列缓存维护操作(CMOs)的指令。这些操作的示例包括将数据写回到外部内存,以及使缓存行失效(清空)。在某些情况下,由于这些操作影响到基于缓存的PMU事件的行为,PMU事件中会有明确的提及。请注意,没有缓存维护操作可以强制缓存分配;这适用于所有与缓存补充相关的PMU事件。

3.2.12 缓存一致性

Neoverse N1缓存逻辑和缓存一致的互连会自动在标记为正常、可缓存和内部共享的任何内存中保持一致性。

有关内存类型的概述,请参阅https://Developer.Arm.com网站上的Learn The Architecture Guides。

缓存一致性的操作方式包括:
• 在本地CPU缓存未命中内存访问时,通过在系统中“窥探”不同缓存之间进行操作。
• 在一个CPU写入现有缓存行时,使其他缓存中的缓存数据失效。

请注意,在Neoverse N1上,I-cache可以配置为一致性。I-cache的一致性通过将I-cache与统一的L2缓存强制包含来实现。如果CPU更新代码/指令(例如,通过某种及时编译器),这将导致对新指令进行数据写入。该写入将像任何一致性数据写入一样工作,并使系统中任何其他缓存中的该数据的副本失效。这种失效将自动使指令缓存中的该缓存行的副本失效,因此新的指令获取将不得不窥探更新的(正确的)副本。
请注意,未在I-cache中命中的指令获取将首先查找D-cache和L2缓存。

如果I-cache是一致性的,则CTR_EL0.DIC位将设置为1。

3.2.13 L2缓存和内存接口交互

Neoverse N1的外部接口称为L2内存系统;它提供CPU与DSU中的CHI总线接口之间的接口。Neoverse N1没有与互连和外部内存系统的直接接口,每个内存访问都经过Neoverse N1到DSU的CHI总线接口。L2接口也被称为load/store单元,不应与Neoverse N1流水线的load/store部分混淆。流水线的load/store部分处理内存操作,然后向L2内存系统发出内存命令。L2内存系统向CHI接口发出实际的事务。上图显示了Neoverse N1系统的不同内存接口。

3.2.14 缓存查找

每个可缓存的内存访问(在经过内存管理单元的转换后)都会尝试在L1缓存中查找(对于数据加载或存储,会查找D-cache;对于指令获取,会查找I-cache)。如果该缓存行不在L1缓存中,则Neoverse N1将尝试在L2统一缓存中查找。如果缓存行在L2统一缓存中存在,它将在L1缓存中分配(PMU事件描述使用术语“refill”)。分配也可能会逐出已经存在的缓存行。

如果在L2缓存中未命中查找,则Neoverse N1 L2内存系统尝试在下一级缓存中查找。下一级可以是DSU中的L3缓存(存在时)、不同Neoverse N1中的L2缓存或外部一致互连的系统级缓存(一致网格网络或CMN)。引用对下一级缓存的访问的PMU事件描述说明了CPU如何确定下一级是什么。

3.2.15 缓存逐出

当缓存集合满且需要将新行分配到缓存时,存在一个受害者计数器,用于选择下一个要逐出的缓存行。正如在“缓存行大小”部分讨论的那样,相关PMU事件描述中的术语“full”指的是可以分配地址的特定缓存集合。

3.2.16 不对齐访问

Neoverse N1可能对不对齐地址执行数据内存操作。由CPU单元发送到总线的实际外部内存事务将是对齐的。CPU将执行一系列对齐访问,将请求的(不对齐地址的)数据带入并传递回load/store流水线。

例如,如果Neoverse N1对地址0x8001执行了一个32位字的加载指令,它可以从地址0x8000发出一个64位读取,然后从该完整读取中提取请求的32位字。

3.2.17 内存管理单元行为

所有内存访问都将首先通过内存管理单元(MMU)进行虚拟到物理地址的转换,以及为内存事务分配内存属性。内存翻译是通过一系列存在于实际内存中并由应用程序进行编程的内存页表来定义的。请注意,当访问页表时,MMU本身可以发出内存事务。

image.png

3.2.18 TLB行为

现有的内存翻译被缓存到Translation Look-aside Buffers(TLBs)中。TLBs作为内存翻译的小型缓存,类似于普通数据缓存(命中、未命中、分配/填充等)。
Neoverse N1有两级TLB:

L1 I-side和D-side TLBs(每个完全关联具有48个条目)。
L2统一TLB(5路组关联具有1280个条目)。
访问内存的操作会导致CPU MMU在L1 TLBs之一中查找虚拟到物理的转换(取决于是指令获取还是数据读写)。如果尝试的L1访问未命中,则MMU将在L2 TLB中查找。如果尝试的L2访问未命中,则MMU将进行页表遍历。
未命中将在L2 TLB中分配一个新条目,然后转发到L1 TLB(这也将分配一个新条目)。L2 TLB还充当walk缓存;它存储部分页表walk条目。例如,可能由多个第一阶段翻译使用的第二阶段翻译可以分配到L2 TLB中。
请注意,尽管涵盖L2 TLB行为的事件被命名为L2D_,但L2 TLB是一个统一的TLB,包含数据侧和指令侧翻译。

3.2.19 TLB维护操作

Arm®架构参考手册Armv8定义了一系列用于TLB维护的指令。这些操作用于在关联的MMU映射发生更改时使TLB条目无效。在某些情况下,基于这些操作的TLB行为不会被PMU事件计数。在TLB相关的PMU事件中适用于由TLB维护操作引起的行为时,PMU事件描述中会有明确说明。
请注意,没有TLB维护操作可以强制TLB分配。

3.2.20 内存错误行为

Neoverse N1为某些内部内存结构实现了ECC和奇偶校验。行为、控制和报告寄存器属于可靠性、可用性和服务性(RAS)架构扩展。
对这些内存的访问将检查错误状态并以以下方式做出响应:

L1指令缓存受奇偶校验保护。如果检测到错误,则内部RAS计数器将被更新。然后将使缓存行无效,以便可以获取正确的缓存行。
L1数据缓存和L2统一缓存使用ECC进行保护。如果检测到1位错误,则进行更正,并更新内部计数器。
如果检测到2位(无法更正)错误,并且内存访问已经被架构执行,则该错误被视为“已消耗”。CPU将触发同步错误异常或SError异常,并更新内部内存错误寄存器。
如果检测到2位(无法更正)错误,并且内存访问已经被推测执行但尚未被架构提交,则CPU将标记缓存行为“有毒”。毒化推迟了错误响应,直到系统中的其他设备消耗该错误。如果CPU消耗了受毒害的缓存行,那么它将触发同步错误异常或SError异常,并更新内部内存错误寄存器。
注意:在Neoverse N1上,推测执行的指令或内存访问不能直接导致异常,直到该指令或访问被架构提交。
请注意:
RAS寄存器计数与计数内存错误的任何相关PMU事件是分开的。
MEMORY_ERROR PMU事件不计算L2缓存的内存错误。

3.2.21 一致性Mesh网络配置

在几乎所有的生产系统中,Neoverse N1连接到基于AMBA一致性Hub互联(CHI)协议的内存互连。Arm对该协议的实现是一致性Mesh网络(CMN)产品。根据版本或拓扑,大量的Neoverse N1 CPU可以连接到CMN。
CMN具有内置的系统级缓存(SLC),它作为所有连接的CPU的下一级缓存。SLC基于以下之一进行逐出:

直连模式中连接的Neoverse N1 CPU的L2缓存。
DSU中的L3缓存。
还可以从外部I/O主机“stash”缓存行到SLC中。
可以连接多个Neoverse N1/CMN系统实现的实现(称为“网格”),通过一致性网络链路相互连接。每个网格有时在Arm产品文档中被称为另一个“芯片”。"Socket"是另一个行业术语,有时也被使用,但Arm通常使用单词芯片来表示多个一致性网格实现。
CMN产品包含自己的一组PMU计数器和事件。这些计数器和事件在CMN技术文档中有描述。

关注"Arm精选"公众号,备注进ARM交流讨论区。
图片1.png

推荐阅读
关注数
9457
内容数
201
以易懂、渐进、有序的方式,深入探讨ARMv8/ARMv9架构的核心概念。我们将从基础知识开始,逐步深入,覆盖最新的架构,不再纠缠于过时技术。本系列内容包含但不限于ARM基础、SOC芯片基础、Trustzone、gic、异常和中断、AMBA、Cache、MMU等内容,并将持续更新。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息