思考: 如何统计Trustedfirmware的性能数据? tee的呢?uboot的呢?
如何统计cache命令率?
如何计算 IPC:Instructions Per Cycle?
Armv8-A CPU 中的性能监控单元 (PMU) 提供硬件级性能监控和分析功能。PMU 通过计数器收集硬件事件计数。计数器包括周期计数器和事件计数器。您可以配置:
- 每个事件计数器对指定的硬件事件进行计数。
- 每个计数器从各种 CPU 异常级别和状态的工作负载收集硬件事件。
perf 等工具使用 PMU 来分析在 Armv8-A CPU 上运行的 Linux 应用程序。然而,没有通用的方法来使用 PMU 来分析固件,因为它运行在裸机环境中。
要使用 PMU 分析固件,一种简单的方法是以库的形式添加 PMU 支持。在这篇博文中,我们提供了一个 PMU 库作为参考实现。该库已在基于Armv8.0-A CPU的平台上得到验证。我们还描述了如何在固件中添加 PMU 支持以及如何使用 PMU 分析固件。Trusted Firmware-A (TF-A) 和 U-Boot 用作示例固件。
下表列出了 PMU 库的组件
第 1 阶段: 向固件添加 PMU 支持
使用以下命令将PMU库的所有文件解压到固件 lib/pmu 中的 路径。 unzip armv8_pmuv3_library.zip-d ${FIRMWARE_PATH}/lib/pmu
根据您使用的固件,您需要对文件进行如下特定更改。Makefile
(1)、TF-A
Makefile 如下修改位于 TF-A 根路径中的现有文件。
BL_COMMON_SOURCES += lib/pmu/armv8_pmuv3_fn.c lib/pmu/armv8_pmuv3_events.c
INCLUDES += -Ilib/p
(2)、uboot
修改Makefile U-Boot 根路径下的现有文件,如下所示。
UBOOTINCLUDE += -Ilib/pmu
Makefile 在与 PMU 库相同的目录中创建一个文件。按如下方式填写文件。
obj-y += armv8_pmuv3_fn.o armv8_pmuv3_events.o
现在,您可以重建固件。如果构建成功,请进入第 2 阶段。
第 2 阶段:选择 PMU 事件进行分析
首先,获取运行固件的 Armv8-A CPU 的支持 PMU 事件。有关 PMU 事件,请参阅 CPU 技术参考手册 (TRM)。
jevents.py在 PMU 库中,您还可以使用按以下步骤命名的 Python 脚本。
(1)、获取指定CPU支持的PMU事件 GitHub Machine-readable data 维护每个 Arm CPU 支持的 PMU 事件。它采用JSON格式存储PMU事件的事件助记符、事件编号等信息。该信息与CPU TRM中的信息一致。
jevents.pyPMU 库中 命名的 Python 脚本克隆 Machine-readable data
, 将 JSON 格式转换为 C 格式,并生成名为armv8pmuv3events.c. 您可以按如下方式使用它。
首先,使用以下命令列出所有支持转换的CPU名称。
python3 jevents.py--list
然后,使用以下命令指定要转换的CPU的名称。该命令将生成名为armv8pmuv3events.c. 该文件包含两种类型的数组。一种是针对指定CPU的支持PMU事件。另一个是针对选定的 PMU 事件进行分析。 python3 jevents.py--cpu<cpu name>
armv8_pmuv3_events.c生成的文件示例 jevents.py 如下。我们将 cpu 名称指定为cortex-a53。名为的数组pmu_events_map包含 Cortex-A53 的所有支持 PMU 事件。这与 Cortex-A53 TRM 相同。您可以从此处选择 PMU 事件并将所选事件放入名为 的数组中evt_select。
(2)、选择 PMU 事件进行分析 在初始分析中,通常您需要选择各种 PMU 事件。这将使您全面了解要分析的代码。
对于 Armv8-A CPU,每个 CPU 的可用事件计数器是有限的。您可以参考 CPU TRM 以获取该编号。如果所需的 PMU 事件数量超过可用计数器,可以使用以下方法。
- 将所有要选择的 PMU 事件分组。每组中的事件数量不得超过 PMU 的可用计数器。
- 创建多个pmu_event_selected 结构数组并将每一组放入一个数组中。
- 多次分析相同的代码,一次选择一个阵列,然后重复该过程,直到测量所有事件。
例如,我们 在.c文件中创建两个名为 和 的pmu_event_selected 结构体数组。对于 Cortex-A53,可使用 1 个周期计数器和 6 个事件计数器。每个数组中的 PMU 事件数量不超过此数量。此外,在每个阵列中,PMU 事件都是相关的,以确保分析数据具有可比性。
我们将这两个数组用于以下分析示例。
第 3 阶段: 使用 PMU 分析固件
现在,您可以使用 PMU 来分析固件。对要分析的固件中的特定代码使用以下过程。
- 将开始分析点放在代码之前。这将配置、启用并读取每个 PMU 计数器的当前值作为预分析值。
- 将停止分析点放置在代码后面。这将禁用每个 PMU 计数器值并将其读取为分析后值。
- 重建固件并再次运行代码。计算每个 PMU 计数器的分析前值和分析后值之间的差异。这将收集统计分析结果。
在PMU库中,armv8pmuv3fn.c 提供了参考实现。
(1)、将分析点放置在固件中
您只需在要分析的代码之间添加两个名为pmuv3startProfiling 和的函数即可。pmuv3stopProfiling对于每个分析,传递一个pmueventselected 结构数组作为参数。
根据您想要分析的 PMU 事件数量,您需要分析一次或多次。以下是两个分析示例。
例一
要分析 TF-A 中的函数并重点关注缓存行为,您只能选择 为单个分析命名enablemmuel3 的数组 。evtselectcache
例二
要了解U-Boot 中的工作负载特征,您可以选择名为 和 的crc32 阵列 。这样,您需要对同一代码进行多次分析才能收集所有分析数据。evtselectcacheevtselectwlc
由于该domemcrc 函数是通过命令调用的,因此您可以对固件进行一次编程,然后通过多次输入相同的命令来重复分析。
(2)、了解 PMU 分析的实现
该函数startProfiling 执行以下操作。
- 为 PMU 执行必要的初始化。它检查CPU PMU 支持的事件计数器数量是否适合所选事件。然后,它设置MDCREL2 或 MDCREL3 以在当前异常级别启用 PMU 分析。这是因为固件通常在 EL2/EL3 或安全状态下运行,其中禁止分析以防止信息泄漏。
- 配置每个 PMU 计数器以分析当前异常级别和选定的 PMU 事件。
- 启用每个 PMU 计数器。
- 读取每个 PMU 计数器的当前值作为预分析值。
该函数stopProfiling 执行以下操作。
- 禁用每个 PMU 计数器。
- 读取每个 PMU 计数器的当前值作为分析后值。
- 转储此分析的结果。
- 对 PMU 执行必要的去初始化。这会禁用工作在 EL2/EL3 或安全状态的 PMU。
对于上一部分提到的示例,在 Juno r2 平台上执行分析。分析的输出如下。
例一
从输出中可以看到,它记录了此分析中每个选定 PMU 事件和周期的预分析和后分析值。此外,它还计算差异,并将它们记录在名为 的列中DELTA。
对于 Cortex-A53 CPU,PMU 事件L1DTLBREFILL 包含在 的计数中L1DCACHEREFILL。因此,您可能会发现 的计数值L1DCACHEREFILL 大于 的计数值L1D_CACHE。
示例二
正如您在上面看到的,cycles 两个分析会话的结果几乎相同。
从第一个分析结果中,您可以参考Arm架构参考手册来抽象出一些有意义的指标,如下所示。
根据第二个分析结果,您可以计算 Instructions Per Cycle (IPC) as follows.
IPC = INST_RETIRED / CYCLES
The IPC of this workload is 0.23. This is caused by many MEM_ACCESS operations. You might determine the workload as the computation-intensive one.
作者:baron
文章来源:Arm精选
推荐阅读
欢迎关注ARM精选专栏, 欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。