海思 PCIe 调优和跟踪设备

简介

海思 PCIe 调优和跟踪设备(PTT)是一个 PCIe 根复合体集成端点(RCiEP)设备,提供动态监控和调优 PCIe 链路事件(tune),以及跟踪 TLP 报头(trace)的功能。这两个功能是独立的,但建议结合使用它们来分析和提升 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 和 Core 的 ID 组成。鲲鹏 930 SoC 封装了多个 CPU 裸片(SCCL,超级 CPU 集群)和 IO 裸片(SICL,超级 I/O 集群),每个 SICL 对应一个 PCIe 根复合体。

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

调优

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

每个事件都表现为 $(PTT PMU dir)/tune 下的一个文件,可以通过简单的打开/读取/写入/关闭循环来调优该事件。

$ 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 非发布式(non-posted)TLP 的权重

  • qos_tx_p: Tx 发布式(posted)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(Requester 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 下游的 TLP 报头(‘filter’ 事件的事件代码为 0x80001),其类型为发布式 TLP 请求,方向为入站,跟踪数据格式为 8DW。

1. 过滤

要跟踪的 TLP 报头可以由位于 PTT 设备同一核心上的根端口或端点的请求者 ID 进行过滤。您可以通过指定启动跟踪所需的 filter 参数来设置过滤器。参数值为 20 位。第 19 位表示过滤器类型。1 表示根端口过滤器,0 表示请求者过滤器。Bit[15:0] 表示过滤器的值。根端口的值是核心端口 ID 的掩码,该 ID 根据其 PCI 插槽 ID 计算得出,公式为 (slotid & 7) * 2。请求者的值是请求者 ID(PCIe 功能的设备 ID)。Bit[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 的 bit[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]-+
+---------------------------------------------------------+

驱动程序将为每个 DMA 缓冲区分配 4MiB。完成的缓冲区将被复制到由 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
[...]