简介
CPU 性能监视器跟踪提供程序可让用户使用 Fuchsia 跟踪系统访问内置于 CPU 中的性能计数器。
目前,只有 Intel 芯片组支持此功能。
在 Intel 上,性能监视器可向用户提供有关 CPU 的许多方面统计信息。如需查看可用于(例如Skylake 芯片:请参阅 Intel 第 3 卷第 19.2 章“第 6 代和第 7 代处理器的性能监控事件”。目前并非所有事件(或“计数器”)都可用,有很多事件可供选择,但希望当前存在许多有用的事件。
示例如下:
- 每个 L1、L2、L3 的缓存命中/未命中次数
- 因缓存未命中而停止的周期
- 分支错误预测
- 已弃用说明
跟踪系统使用“类别”来让用户指定要收集哪些轨迹数据。Cpuperf 使用这些类别来简化指定要启用的 H/W 事件的规范。您可以在该目录中的 .inc
文件中找到完整的类别。下面介绍了一些代表性的类别。
如需收集轨迹数据,请在宿主机上运行 ffx trace start
,或直接在 Fuchsia 设备上运行 trace
。
示例:
$ categories="gfx"
$ categories="$categories,cpu:fixed:unhalted_reference_cycles"
$ categories="$categories,cpu:fixed:instructions_retired"
$ categories="$categories,cpu:l2_lines,cpu:sample:10000"
$ ffx trace start --buffer-size 64 --duration 2 --categories $categories
将 .fxt
文件保存到桌面后,您可以将其加载到 Perfetto 查看器中。
基本操作
性能数据收集的基本操作是,为每个 CPU 分配一个跟踪记录缓冲区,然后设置一个计数器(在每个 CPU 上),以便在发生预指定数量的事件后触发中断。此中断称为 PMI 中断(性能监视器中断)。在 Intel 上,当计数器溢出时会触发中断,此时中断服务例程会将各种信息(例如时间戳和程序计数器)写入跟踪缓冲区,重置计数器以便在预先指定数量的事件后重新触发另一个中断,然后返回。
跟踪停止时,Cpuperf Trace Provider 会读取缓冲区,并将其转换为 Trace Manager 使用的轨迹格式。
当缓冲区填满时,跟踪也会停止。请注意,系统会使用内部缓冲区,因此(目前)不支持循环模式和流式传输模式。可收集的轨迹数据量取决于多种因素:
- 轨迹时长
- 缓冲区空间
- 采样频率
- 计数器溢出的频率
- 是否将程序计数器信息写入缓冲区
数据收集类别
如前所述,Fuchsia 跟踪系统使用“类别”来让用户指定要收集的数据。对于 CPU 跟踪,您可以使用类别来指定要启用哪些计数器、是否跟踪操作系统和/或用户空间,以及指定采样频率。
如需详细了解每个性能计数器,请参阅 Intel 文档。本文档不会尝试提供有关每个计数器的详细信息。
采样率
系统会按照用户指定的速率收集每个计数器的数据。最终,我们将能够指定随机费率。在此期间,我们支持以下一组费率:
- cpu:sample:100
- cpu:sample:500
- cpu:sample:1000
- cpu:sample:5000
- cpu:sample:10000
- cpu:sample:50000
- cpu:sample:100000
- cpu:sample:500000
- cpu:sample:1000000
独立采样
默认情况下,系统会独立对每个计数器进行抽样。例如,如果以 10000 的采样率请求“cpu:fixed:instructions_retired”和“arch:llc”(最后一级缓存 - L3),系统将每隔 10000 个“指令停用”事件对已停用的指令进行采样,并且对于前者,每 10000 个“LLC”事件的采样频率将高于前者。系统会随每个样本收集时间戳,以便用户了解执行某项操作(例如退回 10,000 条指令)所花费的时间。
基于时间的采样
有一些计数器可用作“时基”。在时基模式下,一个计数器用于驱动所有计数器的数据收集,而不是按自己的速率收集每个计数器。这样可以更一致地了解正在发生的情况。另一方面,这样做意味着我们会放弃收集每个事件的统计 PC 数据(因为我们将获得的唯一 PC 值是基准时间事件的 PC 值)。除了时间基准计数器之外,还必须提供采样率。
请参阅下文,了解本文撰写时的一组时间基准计数器,以及当前集的源代码树中的 src/performance/cpuperf_provider/intel-timebase-categories.inc
。
统计模式
统计模式是采样模式的更简单替代方案,它会在整个轨迹运行期间收集每个事件的计数,然后进行报告。
通过“cpu:tally”类别(而非“cpu:sample:*”类别)启用统计模式。
示例:
$ categories="cpu:l2_summary"
$ categories="$categories,cpu:fixed:unhalted_reference_cycles"
$ categories="$categories,cpu:fixed:instructions_retired"
$ categories="$categories,cpu:mem:bytes,cpu:mem:requests"
$ categories="$categories,cpu:tally"
$ ffx trace start --buffer-size 64 --duration 2 --categories $categories
选项
cpu:os - 收集在内核空间中运行的代码的数据。
cpu:user - 收集在用户空间中运行的代码的数据。
cpu:pc - 收集与每个事件关联的 PC 数据
例如,如果您想知道缓存缺失通常发生在哪里(从统计学角度而言,取决于抽样率),这会很有用。轨迹输出中包含每个采样点的地址空间和程序计数器。不过,这样做会使每个轨迹记录的大小翻倍,因此需要权衡利弊。
固定计数器
Intel 架构提供了三个“固定”计数器:
cpu:fixed:instructions_retired
cpu:fixed:unhalted_core_cycles
cpu:fixed:unhalted_reference_cycles
这些计数器是“固定”的,因为它们不使用可编程计数器。其中有三个,每个都有固定用途。它们的优点是不会耗尽一个可编程计数器:有数十个计数器,但根据模型,通常一次最多只能使用四个计数器。
可编程计数器
Skylake(和 Kaby Lake)芯片上有数十个可编程计数器。如需查看完整列表,请参阅 Intel 第 3 卷第 19.2 章“第 6 代和第 7 代处理器的性能监控事件”。如需查看目前支持的平台列表,请参阅源代码树中的 zircon/system/ulib/zircon-internal/include/lib/zircon-internal/device/cpu-trace/intel-pm-events.inc
和 zircon/system/ulib/zircon-internal/include/lib/zircon-internal/device/cpu-trace/skylake-pm-events.inc
。
为了简化指定可编程计数器的过程,在源代码树中,我们将可编程计数器划分到了 src/performance/cpuperf_provider/intel-pm-categories.inc
和 src/performance/cpuperf_provider/skylake-pm-categories.inc
中定义的类别。如需查看完整列表,请参阅这些文件。
一次只能指定其中一个类别。[稍后,我们将提供更多数据收集控制选项。]
以下是一些实用类别:
cpu:arch:llc
- 最后一级缓存 (L3) 引用
- 最后一级缓存 (L3) 未命中
cpu:arch:branch
- 分支指令已停用
- 分支指令预测错误
cpu:skl:l1_summary
- 每个周期的未处理 L1D 缺失次数
- 此处理器核心上任何逻辑线程的未处理 L1D 缺失次数
- 提取到 L1 数据缓存的行数
cpu:skl:l2_summary
- 错失 L2 的需求请求
- 所有未命中 L2 的请求
- 对 L2 的所有需求数据读取请求
- 对 L2 的所有请求
cpu:skl:l3_summary
- 来自引用 L3 中缓存行的核心的请求
- 对 L3 的引用的缓存未命中条件
cpu:skl:offcore_demand_code
- 将 SQ 中未处理的离线需求代码读取事务的数量在每个周期递增到 uncore
- 在 SQ 中至少有 1 个非核心待处理需求代码读取事务的周期
cpu:skl:offcore_demand_data
- 将 SQ 中每个周期的离核心未处理需求数据读取事务数量递增到 uncore
- 在 SQ 中至少有 1 个未处理的离核心需求数据读取事务的周期
- 在 SQ 中至少有 6 个未处理的离核心需求数据读取事务的周期
cpu:skl:l1_miss_cycles
- 在 L1 数据缺失需求加载时所经历的周期
- 在 L1 数据缺失需求加载待处理时,执行会暂停
cpu:skl:l2_miss_cycles
- L2 缺失需求载荷待处理时的周期
- 在 L2 缺失需求加载未处理完毕时,执行会暂停
cpu:skl:l3_miss_cycles
- L3 缺失需求载荷未处理时的周期
- 在 L3 缺失需求加载未处理完毕时,执行会暂停
cpu:skl:mem_cycles
- 内存子系统有未处理的负载时的周期
- 当内存子系统有未完成的负载时,执行会停止
时间基准计数器
这些计数器可用作时间基准。我们会及时添加更多产品。
cpu:timebase:fixed:instructions_retired
- 计数器与 cpu:fixed:instructions_retired 相同
cpu:timebase:fixed:unhalted_reference_cycles
- 与 cpu:fixed:unhalted_reference_cycles 相同的计数器