海思 PCIe 调优和追踪设备

介绍

海思 PCIe 调优和追踪设备 (PTT) 是一种 PCIe 根联合体集成端点 (RCiEP) 设备,提供动态监控和调优 PCIe 链路事件(调优)以及追踪 TLP 头部(追踪)的能力。这两个功能是独立的,但建议一起使用以分析和增强 PCIe 链路的性能。

在鲲鹏 930 SoC 上,PCIe 根联合体由多个 PCIe 核心组成。每个 PCIe 核心包括多个根端口和一个 PTT RCiEP,如下所示。PTT 设备能够调优和追踪 PCIe 核心的链路。

      +--------------Core 0-------+
      |       |       [   PTT   ] |
      |       |       [Root Port]---[Endpoint]
      |       |       [Root Port]---[Endpoint]
      |       |       [Root Port]---[Endpoint]
Root Complex  |------Core 1-------+
      |       |       [   PTT   ] |
      |       |       [Root Port]---[ Switch ]---[Endpoint]
      |       |       [Root Port]---[Endpoint] `-[Endpoint]
      |       |       [Root Port]---[Endpoint]
      +---------------------------+

PTT 设备驱动程序为每个 PTT 设备注册一个 PMU 设备。每个 PTT 设备的名称由 “hisi_ptt” 前缀以及 SICL 和核心的 ID 组成。鲲鹏 930 SoC 封装了多个 CPU 芯片 (SCCL, Super CPU Cluster) 和 IO 芯片 (SICL, Super I/O Cluster),每个 SICL 都有一个 PCIe 根联合体。

/sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>

调优

PTT 调优旨在监控和调整 PCIe 链路参数(事件)。目前,我们支持 2 类事件。事件的范围涵盖 PTT 设备所属的 PCIe 核心。

每个事件都表示为 $(PTT PMU dir)/tune 下的一个文件,并且将使用一个简单的 open/read/write/close 循环来调优事件。

$ cd /sys/bus/event_source/devices/hisi_ptt<sicl_id>_<core_id>/tune
$ ls
qos_tx_cpl    qos_tx_np    qos_tx_p
tx_path_rx_req_alloc_buf_level
tx_path_tx_req_alloc_buf_level
$ cat qos_tx_dp
1
$ echo 2 > qos_tx_dp
$ cat qos_tx_dp
2

事件的当前值(数值)可以直接从文件中读取,并将所需的值写入文件以进行调优。

1. Tx 路径 QoS 控制

提供以下文件以调优 PCIe 核心的 tx 路径的 QoS。

  • qos_tx_cpl:Tx 完成 TLP 的权重

  • qos_tx_np:Tx 非发布 TLP 的权重

  • qos_tx_p:Tx 发布 TLP 的权重

权重影响 PCIe 链路上特定数据包的比例。例如,对于存储场景,增加链路上完成数据包的比例以增强性能,因为会消耗更多的完成。

这些事件的可用调优数据为 [0, 1, 2]。写入负值将返回错误,超出范围的值将转换为 2。请注意,事件值仅指示一个可能的级别,但并不精确。

2. Tx 路径缓冲区控制

提供以下文件以调优 PCIe 核心的 tx 路径的缓冲区。

  • rx_alloc_buf_level:Rx 请求的水印

  • tx_alloc_buf_level:Tx 请求的水印

这些事件影响为每种类型分配的缓冲区的水印。Rx 表示入站,而 Tx 表示出站。数据包将首先存储在缓冲区中,然后在达到水印或超时时传输。对于繁忙的方向,您应该增加相关的缓冲区水印,以避免频繁发布,从而提高性能。在大多数情况下,只需保留默认值即可。

以上事件的可用调优数据为 [0, 1, 2]。写入负值将返回错误,超出范围的值将转换为 2。请注意,事件值仅指示一个可能的级别,但并不精确。

追踪

PTT 追踪旨在将 TLP 头部转储到内存中,可用于分析 PCIe 链路的事务和使用情况。您可以选择按请求者 ID 或 PTT 设备同一核心上一组根端口的下游来过滤追踪的头部。还支持追踪特定类型和方向的头部。

您可以使用 perf 命令 perf record 来设置参数、启动追踪并获取数据。还支持使用 perf report 解码追踪数据。追踪的控制参数作为每个事件的事件代码输入,稍后将进一步说明。一个示例用法如下

$ perf record -e hisi_ptt0_2/filter=0x80001,type=1,direction=1,
  format=1/ -- sleep 5

这将追踪下游根端口 0000:00:10.1 (事件 'filter' 的事件代码为 0x80001) 的 TLP 头部,类型为已发布的 TLP 请求,方向为入站,追踪数据格式为 8DW。

1. 过滤器

要追踪的 TLP 头部可以通过根端口或端点的请求者 ID 进行过滤,它们位于 PTT 设备的同一核心上。您可以通过指定 filter 参数来设置过滤器,这是启动追踪所必需的。参数值为 20 位。位 19 指示过滤器类型。1 表示根端口过滤器,0 表示请求者过滤器。位 [15:0] 指示过滤器值。根端口的值是核心端口 ID 的掩码,该掩码从其 PCI 插槽 ID 计算为 (slotid & 7) * 2。请求者的值是请求者 ID(PCIe 功能的设备 ID)。位 [18:16] 当前保留用于扩展。

例如,如果所需的过滤器是端点功能 0000:01:00.1,则过滤器值为 0x00101。如果所需的过滤器是根端口 0000:00:10.0,则过滤器值计算为 0x80001。

驱动程序还通过 sysfs 显示每个支持的根端口和请求者过滤器。每个过滤器将是一个单独的文件,其名称与其相关的 PCIe 设备名称 (domain:bus:device.function) 相同。根端口过滤器的文件位于 $(PTT PMU dir)/root_port_filters 下,请求者过滤器的文件位于 $(PTT PMU dir)/requester_filters 下。

请注意,可以一次指定多个根端口,但一次追踪只能指定一个端点功能。不支持同时指定根端口和功能。驱动程序维护可用过滤器的列表,并将检查无效的输入。

可用过滤器将动态更新,这意味着当发生热插拔事件或您手动删除/重新扫描设备时,您将始终获得正确的过滤器信息。

2. 类型

您可以通过指定 type 参数来追踪特定类型的 TLP 头部,这是启动追踪所必需的。参数值为 8 位。当前支持的类型和相关值如下所示

  • 8'b00000001:已发布的请求 (P)

  • 8'b00000010:未发布的请求 (NP)

  • 8'b00000100:完成 (CPL)

在追踪入站 TLP 头部时,您可以指定多种类型,但在追踪出站 TLP 头部时,只能指定一种类型。

3. 方向

您可以通过指定 direction 参数来追踪来自特定方向的 TLP 头部,该方向相对于根端口或 PCIe 核心。这是可选的,默认参数是入站。参数值为 4 位。当所需的格式为 4DW 时,支持的方向和相关值如下所示

  • 4'b0000:入站 TLP (P, NP, CPL)

  • 4'b0001:出站 TLP (P, NP, CPL)

  • 4'b0010:出站 TLP (P, NP, CPL) 和入站 TLP (P, NP, CPL B)

  • 4'b0011:出站 TLP (P, NP, CPL) 和入站 TLP (CPL A)

当所需的格式为 8DW 时,支持的方向和相关值如下所示

  • 4'b0000:保留

  • 4'b0001:出站 TLP (P, NP, CPL)

  • 4'b0010:入站 TLP (P, NP, CPL B)

  • 4'b0011:入站 TLP (CPL A)

入站完成分为两种类型

  • 完成 A (CPL A):CHI/DMA/本机非发布请求的完成,CPL B 除外

  • 完成 B (CPL B):DMA remote2local 和 P2P 非发布请求的完成

4. 格式

您可以通过指定 format 参数来更改追踪的 TLP 头部的格式。默认格式为 4DW。参数值为 4 位。当前支持的格式和相关值如下所示

  • 4'b0000:每个 TLP 头部 4DW 长度

  • 4'b0001:每个 TLP 头部 8DW 长度

追踪的 TLP 头部格式与 PCIe 标准不同。

当使用 8DW 数据格式时,将记录整个 TLP 头部(下面显示的头部 DW0-3)。例如,具有 64 位地址的内存读取的 TLP 头部显示在 PCIe r5.0 的图 2-17 中;配置请求的头部显示在图 2.20 中,等等。

此外,8DW 追踪缓冲区条目包含时间戳,并可能包含 PASID TLP 前缀的前缀(参见 PCIe r5.0 的图 6-20)。否则,此字段将全部为 0。

DW0 的位 [31:11] 始终为 0x1fffff,可用于区分数据格式。8DW 格式如下所示

bits [                 31:11                 ][       10:0       ]
     |---------------------------------------|-------------------|
 DW0 [                0x1fffff               ][ Reserved (0x7ff) ]
 DW1 [                       Prefix                              ]
 DW2 [                     Header DW0                            ]
 DW3 [                     Header DW1                            ]
 DW4 [                     Header DW2                            ]
 DW5 [                     Header DW3                            ]
 DW6 [                   Reserved (0x0)                          ]
 DW7 [                        Time                               ]

当使用 4DW 数据格式时,追踪缓冲区条目的 DW0 包含 TLP 的 DW0 的选定字段,以及时间戳。追踪缓冲区条目的 DW1-DW3 直接包含来自 TLP 头部的 DW1-DW3。

4DW 格式如下所示

bits [31:30] [ 29:25 ][24][23][22][21][    20:11   ][    10:0    ]
     |-----|---------|---|---|---|---|-------------|-------------|
 DW0 [ Fmt ][  Type  ][T9][T8][TH][SO][   Length   ][    Time    ]
 DW1 [                     Header DW1                            ]
 DW2 [                     Header DW2                            ]
 DW3 [                     Header DW3                            ]

5. 内存管理

追踪的 TLP 头部将写入驱动程序分配的内存中。硬件接受 4 个大小相同的 DMA 地址,并按如下所示顺序写入缓冲区。如果 DMA 地址 3 已完成且追踪仍在进行中,它将返回到地址 0。

+->[DMA addr 0]->[DMA addr 1]->[DMA addr 2]->[DMA addr 3]-+
+---------------------------------------------------------+

驱动程序将分配每个 4MiB 的 DMA 缓冲区。完成的缓冲区将被复制到 perf 核心分配的 perf AUX 缓冲区。一旦 AUX 缓冲区已满,而追踪仍在进行中,驱动程序将首先提交 AUX 缓冲区,然后申请一个大小相同的新缓冲区。AUX 缓冲区的大小默认为 16MiB。用户可以通过指定 perf 命令的 -m 参数来调整大小。

6. 解码

您可以使用 perf report -D 命令解码追踪的数据(目前仅支持转储原始追踪数据)。追踪的数据将根据先前描述的格式进行解码(以 8DW 为例)

[...perf headers and other information]
. ... HISI PTT data: size 4194304 bytes
.  00000000: 00 00 00 00                                 Prefix
.  00000004: 01 00 00 60                                 Header DW0
.  00000008: 0f 1e 00 01                                 Header DW1
.  0000000c: 04 00 00 00                                 Header DW2
.  00000010: 40 00 81 02                                 Header DW3
.  00000014: 33 c0 04 00                                 Time
.  00000020: 00 00 00 00                                 Prefix
.  00000024: 01 00 00 60                                 Header DW0
.  00000028: 0f 1e 00 01                                 Header DW1
.  0000002c: 04 00 00 00                                 Header DW2
.  00000030: 40 00 81 02                                 Header DW3
.  00000034: 02 00 00 00                                 Time
.  00000040: 00 00 00 00                                 Prefix
.  00000044: 01 00 00 60                                 Header DW0
.  00000048: 0f 1e 00 01                                 Header DW1
.  0000004c: 04 00 00 00                                 Header DW2
.  00000050: 40 00 81 02                                 Header DW3
[...]