Skip to content

UHI Host-Interface DMA

本页中的所有地址均适用于来自 libtpu-0.0.40-cp314 wheel 的 libtpu.so(构建 libtpu_lts_20260413_b_RC00,build-id md5 89edbbe81c5b328a958fe628a9f2207d)。该映像剥离符号;反混淆后的 C++ 符号名按原文引用。.text VMA 等于文件偏移(.text 基址 0xe63c000.rodata 基址 0x84a0000);.data.rel.ro 带有 0x200000 的 VMA→文件增量。所有地址都是 VMA。其他版本会不同。

摘要

UHI(Universal/Unified Host Interface)band 是 pxc(Pufferfish / BarnaCore)一代在设备 trace stream 中的 host↔device DMA 消息族。每个跨边界 DMA,无论是向 TensorCore queue 供给的 infeed、从中排出的 outfeed、host direct-write,还是 physical-address bridge response,都会表现为一串 UHI 消息,其 packageasic_sw.driver.deepsea.pxc.profiler。UHI 消息类型共有七种:一个 transaction startUhiHostDmaTransactionStartedAddressTranslation)、携带 host physical address 的 read/write request 对(UhiHostPhysicalRequest{Read,Write})、结束传输的 read/write response 对(UhiHostPhysicalResponse{Read,Write}),以及携带 on-chip byte address 的 read/write OCI bridge request 对(UhiOciRequest{Read,Write})。每种都接入 pxc::profiler::TraceEntry oneof,并由生成的 DecodeUhi… bit-unpacker 解码。

本页负责逐消息字段映射(field number、name、proto type、C++ struct offset、on-wire bit width、嵌入的 TraceIdHeader)、22 值 QueueIdValues enum 及其每个 queue name 的 host-DMA role,以及 UHI 消息如何框定 host↔device transfer(begin/end identity-pairing surface)。将 start+response 对重组为渲染 span 的逻辑,即 DeriveHostDmaTransfers 和 tag-6/7 H2D/D2H selector,见 Host↔Device DMA;共享的 DmaTransfer record + per-span XStats 以及 local-leg descriptor 见 Intra-Chip DMA Descriptor。本页是那两页回链的 wire-format reference。

对重实现而言,契约是:

  • 七种 UHI 消息类型 — 它们的 pxc::profiler::TraceEntry oneof cases(trace-point ids 0–6 / oneof cases 2–8),以及 host-DMA timeline 实际用作 key 的三种({0, 2, 4})。
  • id-0 STARTED 字段映射{trace_id_header, queue_id, sequence_number, dva, size},byte-exact C++ offsets 和 on-wire widths,由 DecodeUhiHostDmaTransactionStartedAddressTranslation 解码(consumed-bit CHECK 0xd8 = 216)。
  • id-2 / id-4 RESPONSE 字段映射 — 相同的 3 字段 {trace_id_header, is_l2_pte_fetch, chunk_id} 形态,END marker(CHECK 0x76 = 118)。
  • 嵌入的 TraceIdHeader{transaction_id, core_id, chip_id},是每个 UHI 消息的 field 1;只有 transaction_id 是逐 DMA pairing key。
  • 22 值 QueueIdValues enum — 每个值 0..21 均解析到其 host-DMA role(debug / magic / direct-write / infeed / outfeed / reserved),以及为什么此 enum 只属于 pxc(更新的 HDE 一代用方向命名的 ThreadIdValues 取代它)。
  • request / OCI-bridge siblings — 该 band 中未被消费的 address half(dpa_upper_bitsdva_middle_bitsf_on_chip_byte_address),timeline 会解码但丢弃它们。
Proto packageasic_sw.driver.deepsea.pxc.profilerpxc = Pufferfish)
UHI message typesUhiHostDmaTransactionStartedAddressTranslation, UhiHostPhysicalRequest{Read,Write}, UhiHostPhysicalResponse{Read,Write}, UhiOciRequest{Read,Write}(共 7 种)
id-0 STARTED decoderDecode…UhiHostDmaTransactionStartedAddressTranslation… @ 0xf5b0b80(consumed-bit CHECK 0xd8 = 216
id-2 RESPONSE_READ decoderDecode…UhiHostPhysicalResponseRead… @ 0xf5b1300CHECK 0x76 = 118
Host-DMA timeline keys仅 UHI ids {0, 2, 4}(STARTED + RESPONSE_READ + RESPONSE_WRITE)
Pairing keytrace_id_header.transaction_id(32-bit,每个 host DMA 一个)
QueueIdValues22 个值:DEBUG / MAGIC / DIRECTWRITE0-1 / INFEED0-9 / OUTFEED0-6 / RESERVED
Enum-name renderproto2::internal::NameOfDenseEnum<…QueueIdValues_descriptor, 0, 21>queue XStat
Cross-gen successorHDE ThreadIdValuesTHREAD_ID_HOST2CHIP/CHIP2HOST)显式命名方向
证据等级可重实现级 / 已按 IDA 反编译 + FDP descriptor pool 字节确认

1. UHI 消息族和 TraceEntry Oneof

pxc device trace stream 是一串 pxc::profiler::TraceEntry records,每个 record 都是 trace-point message types 上的 proto2 oneof。UHI host-interface band 占用 oneof cases 2..8(trace-point ids 0..6);下面七种消息类型都以反混淆符号形式存在于二进制中(UhiHost…UhiOci…,以及它们生成的 Decode…/DefaultConstruct… helpers)。

idUHI message (pxc::profiler::)oneof case形态在 host-DMA chain 中的角色
0UhiHostDmaTransactionStartedAddressTranslation25 fieldsBEGIN — 打开 transfer;携带 queue + size + dva
1UhiHostPhysicalRequestRead37 fieldsread request — host physical / device-VA address(未消费)
2UhiHostPhysicalResponseRead43 fieldsEND (read) — 关闭 read transfer
3UhiHostPhysicalRequestWrite57 fieldswrite request — host physical / device-VA address(未消费)
4UhiHostPhysicalResponseWrite63 fieldsEND (write) — 关闭 write transfer
5UhiOciRequestRead75 fieldsUHI↔OCI bridge read — on-chip byte address(未消费)
6UhiOciRequestWrite85 fieldsUHI↔OCI bridge write — on-chip byte address + flags(未消费)

NOTE — 只有三个 ids 驱动 timeline。 DeriveHostDmaTransfers host-DMA producer 用恰好 {0, 2, 4}(STARTED + 两个 RESPONSE 消息)初始化其 merged trace-point set;参见 Host↔Device DMA §2.1。REQUEST(1/3)和 OCI-bridge(5/6)events 会完整解码进 proto,它们的 Decode… functions 也是真实符号,但 libtpu.so 中没有 XPlane pass 消费它们。这里将它们记录为 reimplementer 恢复 host↔device address mapping 所需的 address-carrying half(§5)。置信度:CONFIRMED(七个消息符号 + 仅 {0,2,4} 的 producer seed)。

Proto-type 图例FieldDescriptorProto.type,用于字段映射表):4 = UINT648 = BOOL11 = MESSAGE13 = UINT3214 = ENUM


2. 嵌入的 TraceIdHeader — 每个 UHI 消息的 Field 1

每个 UHI 消息,实际上每个 pxc trace 消息,都以 field 1 = 一个 TraceIdHeader submessage 开头。它是逐 event identity tuple;host-DMA producer 只读取其中一个字段。

f#nameproto typeC++ offon-wirerole
1transaction_idUINT32 (13)+0x1821dma_id pairing key — 由 producer 读取
2core_idENUM TraceIdHeaderCoreIdValues (14)+0x1c3issuing core identity(解码后丢弃)
3chip_idUINT32 (13)+0x2012issuing chip identity(解码后丢弃)

TraceIdHeaderCoreIdValues enum(8 个值,pxc 子集):

text
0 = CORE_ID_RESERVED   1 = CORE_ID_NONCORE   2 = CORE_ID_TC0   3 = CORE_ID_TC1
4 = CORE_ID_BC0        5 = CORE_ID_BC1       6 = CORE_ID_BC2   7 = CORE_ID_BC3
```text

> **GOTCHA — pairing key 仅是 `transaction_id`。** 不同于 on-chip ICR band 会把 `core_id`/`chip_id` 折入 38-bit composite `dma_id`(参见 [OCI Command DMA-id Selectors](oci-command-dma-id.md)),UHI host-DMA producer 用裸 32-bit `transaction_id`(zero-extended)作为其 `flat_hash_map<uint64, DmaTransfer>` 的 key,在三个 arm 中都以同样方式读取(`hdr+0x18`)。一个 host DMA 恰好有一个 `transaction_id`;其 STARTED 和 RESPONSE 共享它。置信度:CONFIRMED(producer 在每个 arm 中只读取 `transaction_id`;end arms 除 key + gtc 外*不*读取任何内容)。
>
> **NOTE — strings island 包含超过 8 个 `CORE_ID_*` 名称**(`CORE_ID_SC0..SC3`、`CORE_ID_RESERVEDCORE*` 等)。这些属于*其他 generation* 的 CoreId enums(SparseCore-era)。`pxc` `TraceIdHeaderCoreIdValues` 是上面的 8 值 `{RESERVED, NONCORE, TC0, TC1, BC0..BC3}` 子集。置信度:CONFIRMED-PARTIAL(8 个 `pxc` 名称已固定;generation 间精确 enum 边界未单步跟踪,cross-gen split 为 LOW)。

---

## 3. id-0 STARTED 字段映射 — Host Endpoint

`UhiHostDmaTransactionStartedAddressTranslation`(id 0,oneof case 2)是 BEGIN event,也是唯一携带 host endpoint 的 UHI 消息。其 bit-unpacker 为 `Decode…UhiHostDmaTransactionStartedAddressTranslation…` @ `0xf5b0b80`,它跨两个 on-wire packets,并以 consumed-bit `CHECK rdi, 0xd8`(= 216 bits)结束。

| f# | name | proto type | C++ off | on-wire | producer use |
|---:|---|---|---:|---:|---|
| 1 | `trace_id_header` | MESSAGE `TraceIdHeader` (11) | `+0x18` | 21,3,12 | `dma_id` = `transaction_id`(pairing key) |
| 2 | `queue_id` | ENUM `QueueIdValues` (14) | `+0x20` | 5 | KIND-tag selector(§4)**以及** `queue` XStat(enum name) |
| 3 | `sequence_number` | UINT32 (13) | `+0x24` | 16+10 | 解码后**丢弃** |
| 4 | `dva` | UINT64 (4) | `+0x28` | 56* | device virtual address — 解码后**丢弃** |
| 5 | `size` | UINT32 (13) | `+0x30` | 32 | `byte_count` = `size`(无 granule shift) |

(\* `dva` 是打包到 `uint64` 中的 56-bit 值,在 packet 边界两侧由 decoder 的 `GetBits` fragments `1,1,53…` 重组,位置在 `cmp rdi, 0x80` straddle 附近。`queue_id` 的 5-bit 宽度 = `ceil(log2(22))`。)

decoder 将每个字段连同 proto2 has-bit 写入其 C++ offset:`queue_id` → `[obj+0x20]`(has-bit `0x2`),`sequence_number` → `[obj+0x24]`(`0x4`,含跨 packet 边界的 10-bit continuation),`dva` → `[obj+0x28]`(`0x8`),`size` → `[obj+0x30]`(`0x10`)。on-wire 对账:`216 = frame+header(61) + TraceIdHeader(21+3+12=36) + payload(119)`,其中 119-bit payload = `queue_id(5) + sequence_number(16+10=26) + dva(56) + size(32)`。

> **NOTE — `size` 是 raw bytes,不是 granule。** Field 5 名为 `size`,是 raw byte count;producer 直接把它复制进 `byte_count`,**没有** shift。对比 REQUEST events 中的 `size_units_of_32B`(§5,32-byte granule)和 on-chip ICR band 的 `length << {2,9}` granule 逻辑([Intra-Chip DMA Descriptor §4](intra-chip-descriptor.md#4-the-descriptor-field-layout))。置信度:CONFIRMED(`byte_count` ← `[msg+0x30]`,无 shift)。
>
> **GOTCHA — device address 被解码后丢弃。** Field 4 `dva` 是命名 host↔device copy 的 device 端的字段,decoder 会忠实地将其解包到 `[obj+0x28]`。但 producer 从不读取 `+0x28`(也不读 `+0x24`)。只有 `trace_id_header`(key)、`queue_id`(tag + label)和 `size`(byte count)会保留到渲染 span 中,所以捕获的 `pxc` host-DMA `XEvent` 显示*多少*以及*哪个 queue*,但不显示 host 或 device address。参见 [Host↔Device DMA §2.2](host-device-dma.md)。置信度:CONFIRMED。

---

## 4. id-2 / id-4 RESPONSE 字段映射 — END Marker

`UhiHostPhysicalResponseRead`(id 2,oneof case 4)和 `UhiHostPhysicalResponseWrite`(id 4,oneof case 6)是 completion events。它们具有**相同**的 3 字段形态。read decoder 是 `Decode…UhiHostPhysicalResponseRead…` @ `0xf5b1300`(consumed-bit `CHECK rdi, 0x76` = 118 bits)。

| f# | name | proto type | C++ off | on-wire | producer use |
|---:|---|---|---:|---:|---|
| 1 | `trace_id_header` | MESSAGE `TraceIdHeader` (11) | `+0x18` | 21,3,12 | `dma_id` = `transaction_id`(PAIR — 找到 open slot) |
| 2 | `is_l2_pte_fetch` | BOOL (8) | `+0x20`† | 1 | 解码后**丢弃** |
| 3 | `chunk_id` | UINT32 (13) | `+0x24` | 20 | 解码后**丢弃** |

(† `is_l2_pte_fetch` 是带 has-bit `0x2` 存储的 1-bit bool;`chunk_id`(20 bits)→ `[obj+0x24]` has-bit `0x4`。)`UhiHostPhysicalResponseWrite`(id 4)具有 byte-for-byte 相同形态;二者都会关闭 transfer。

> **NOTE — read-response vs write-response *不是*方向信号。** 很容易把 id-2(READ response)理解为 device→host read,把 id-4(WRITE response)理解为 host→device write。producer 并不这样做:H2D/D2H lane 在 STARTED event 中由 `queue_id` 固定(见下面 §5 / [Host↔Device DMA §3](host-device-dma.md));两个 RESPONSE 变体都只提供结束时间戳。producer 从 RESPONSE message 中*只*读取 `trace_id_header.transaction_id`,设置 `end_gtc`/`end_present`,并保持 `is_l2_pte_fetch`/`chunk_id` 未触碰。置信度:CONFIRMED(end store 只写 gtc/present)。

### UHI 消息如何框定一个 transfer

timeline 消费的两个 UHI ids 以一个 identity 为 key 组成 begin/end bracket:

```text
STARTED (id 0)            transaction_id = T,  queue_id = Q,  size = N
   │  opens DmaTransfer slot[T] = { begin_gtc, byte_count=N,
   │                                queue=NameOf(Q), kind=tag(Q) }   §5

RESPONSE_READ (id 2)  OR  RESPONSE_WRITE (id 4)   transaction_id = T
      closes slot[T] = { …, end_gtc }   →  one DmaTransfer span

每个 host DMA 一个 transaction_id;STARTED 决定 lane,单个 RESPONSE 提供 close。REQUEST(1/3)和 OCI-bridge(5/6)events 落在这个 bracket 之外;它们携带 bracket 从不读取的 address detail。重组机制(slot map、flush-on-reopen、共享 renderer)见 Host↔Device DMA


5. QueueIdValues Enum — Host-DMA Roles

queue_id(id-0 field 2)是一个 QueueIdValues,即嵌套在 STARTED 消息中的 dense 22-value enum。全部 22 个 QUEUE_ID_* name strings 都存在于二进制的 read-only data 中;producer 使用 proto2::internal::NameOfDenseEnum<&…QueueIdValues_descriptor, 0, 21>(fast path 为 indices 0..21 索引 descriptor table;slow path 落到 NameOfDenseEnumSlow)将名称渲染到 queue XStat,并按分桶 H2D/D2H。

valnamehost-DMA rolelane(按 Host↔Device DMA §3
0QUEUE_ID_DEBUGQUEUEdebug / diagnostic host-interface queueD2H(tag 7,lane 64)
1QUEUE_ID_MAGICQUEUE特殊 “magic” control queueD2H(tag 7,lane 64)
2QUEUE_ID_DIRECTWRITEQUEUE0host direct-write into device memory(raw H2D)[A]H2D(tag 6,lane 63)
3QUEUE_ID_DIRECTWRITEQUEUE1host direct-write into device memory(raw H2D)[A]H2D(tag 6,lane 63)
4QUEUE_ID_INFEEDQUEUE0infeed(host→device data feed)[B]D2H(tag 7,lane 64)
5–13QUEUE_ID_INFEEDQUEUE1..9infeed 1..9 [B]D2H(tag 7,lane 64)
14QUEUE_ID_OUTFEEDQUEUE0outfeed(device→host result drain)[C]D2H(tag 7,lane 64)
15–20QUEUE_ID_OUTFEEDQUEUE1..6outfeed 1..6 [C]D2H(tag 7,lane 64)
21QUEUE_ID_RESERVEDreserved(未使用 queue slot)D2H(tag 7,lane 64)

计数:1 debug + 1 magic + 2 direct-write + 10 infeed(0..9)+ 7 outfeed(0..6)+ 1 reserved = 22,indices 0..21。

[A] Direct-write 由 pxc::plc::DirectWriteQueueHostQueueFactory 支撑(host 直接把 payload 写入 device-mapped queue,是纯 host→device write)。这是仅有的两个被分桶为 H2D 的值。 [B] Infeed 由 pxc::plc::InfeedQueueHostQueueFactory + xla::*::TransferToInfeed 支撑(host→device data feed)。 [C] Outfeed 由 pxc::plc::OutfeedQueueHostQueueFactory(+ tpu::OutfeedManager)+ xla::*::TransferFromOutfeed 支撑(device→host result drain)。QUEUE_ID_MAGICQUEUE 相应地有一个 pxc::plc::MagicQueueHostQueueFactory

GOTCHA — 只有两个 direct-write queues 是 H2D;规则位于页外。 byte-exact selector (queue_id & ~1) == 2 ? 6 : 7(仅对 queue_id ∈ {2,3} 为 true)是 .text 中唯一的 tag-6/7 位置;完整记录见 Host↔Device DMA §3。这里的后果是:infeed queues 虽然按 TransferToInfeed 在逻辑上是 host→device,但仍被分桶为 D2H,因为 timeline 只把 raw direct-write 分类为 H2D,并把每个 descriptor-managed transfer(infeed/outfeed)视为 D2H。22 个名称 + roles 为 CONFIRMED(strings island 恰好包含这些 22 个名称,且 pxc::plc::*HostQueueFactory queue factories 存在);infeed=D2H 分桶究竟反映 silicon direction 还是 trace-design convention 为 LOW(这里只解码字面 predicate,未对照 silicon 验证)。

NOTE — QueueIdValues 只属于 pxc;HDE successor 显式命名方向。 该 enum 只存在于 pxc UHI band。更新的 HDE(Host DMA Engine)一代,即以符号形式存在的 HdeHostRequest{Read,Write} / HdeHostResponse{Read,Write},用 ThreadIdValues enum 取代 host-DMA message 的 queue_id,并在值名中直接命名 host↔device 方向:THREAD_ID_HOST2CHIP_0..3(H2D)、THREAD_ID_CHIP2HOST_0..1(D2H)、THREAD_ID_RESERVED0/1。(更宽的 HDE thread family 还命名 HBM↔core engines,例如 THREAD_ID_HBM2SC{0..3}SPMEM。)因此 pxc trace 必须通过 (queue_id & ~1) == 2 heuristic 从 queue role 推断方向,而 HDE producer 直接根据 thread name 取 key。置信度:CONFIRMED(pxc QueueIdValues + HDE THREAD_ID_HOST2CHIP/CHIP2HOST/RESERVED0/1 + HdeHost… symbols 均存在)。


6. Request / OCI-Bridge Siblings — 未消费的 Address Half

四个 sibling UHI 消息会解码 timeline 丢弃的地址。它们被解码进 proto(它们的 Decode… functions 是真实符号),但没有 XPlane pass 读取它们;它们是可恢复的 host↔device address surface。

UhiHostPhysicalRequestRead(id 1)/ UhiHostPhysicalRequestWrite(id 3) — 相同的 7 字段形态,携带 host physical address:

f#nameproto typenote
1trace_id_headerMESSAGE与 STARTED transaction_id 配对
2is_l2_pte_fetchBOOLL2 page-table-entry fetch flag
3dpa_upper_bitsUINT64device/host physical address(upper bits)
4dva_middle_bitsUINT32device-VA middle bits(STARTED dva 省略的半边)
5size_units_of_32BUINT32以 32-byte granules 表示的 size(对比 STARTED size = raw bytes)
6num_chunksUINT32chunk count
7chunk_idUINT32chunk index

UhiOciRequestRead(id 5)/ UhiOciRequestWrite(id 6) — 相同的 5 字段形态,是携带 on-chip byte address 的 UHI↔OCI bridge request:

f#nameproto typenote
1trace_id_headerMESSAGEidentity
2f_on_chip_byte_addressUINT64on-chip byte address(OCI-fabric 端)
3idUINT32bridge transaction id
4write_data_type_is_instructionBOOLwrite payload 是 instruction 还是 data
5write_is_orderedBOOLordered-write flag

NOTE — address half 可恢复但未渲染。 如果 reimplementer 需要实际 host physical(dpa_upper_bits)/ device virtual(dva + dva_middle_bits)/ on-chip(f_on_chip_byte_address)地址,必须重新读取这些被丢弃字段以及 STARTED dva。多片段 UINT64 字段跨 decoder packet 边界的精确 LSB-first bit-reassembly(dva 56-bit、dpa_upper_bits)未在此单步跟踪;字段宽度和 C++ 目标已固定,每 fragment 的 shift/OR 顺序是剩余问题。置信度:字段集合 + 类型为 CONFIRMED;精确 UINT64 bit-reassembly order 为 LOW


7. 重实现说明

  • 每条消息的 decode order。 Field 1 总是 TraceIdHeader(3 个 sub-fields,on-wire 21,3,12)。对于 id-0 STARTED,剩余 payload 是 queue_id(5) + sequence_number(16+10) + dva(56) + size(32) = 119 bits,总 consumed 0xd8 = 216。对于 RESPONSE,payload 是 is_l2_pte_fetch(1) + chunk_id(20),总计 0x76 = 118。
  • Pairing surface。 要框定一个 transfer,只需要 id-0(begin)+ id-2/id-4 之一(end),按 trace_id_header.transaction_id join。方向来自 id-0 的 queue_id,从不来自哪个 RESPONSE 关闭了它。
  • queue_id semantics。 当且仅当 queue_id ∈ {2,3}(两个 direct-write queues)时分桶为 H2D;其他全部为 D2H。用 dense-enum table(indices 0..21)渲染 queue name。不要假设 infeed = H2D。
  • size 是 raw bytes。 STARTED size(f5)是无 shift 使用的 byte count。REQUEST size_units_of_32B(f5)是 32-byte granule;如果读取它,则乘以 32。
  • 地址是可选且未渲染的。 dva(STARTED f4)、dpa_upper_bits/dva_middle_bits(REQUEST f3/f4)和 f_on_chip_byte_address(OCI f2)携带完整 host↔device address mapping,但没有 libtpu.so consumer 读取它们;只有需要地址时才恢复。
  • Generation gate。 QueueIdValues 只属于 pxc。在 HDE silicon 上使用 HdeHost… messages,并依据 ThreadIdValuesHOST2CHIP/CHIP2HOST)而不是 queue heuristic 来确定方向。

交叉引用

  • Host↔Device DMADeriveHostDmaTransfers(queue_id & ~1) == 2 ? 6 : 7 tag-6/7 selector,以及消费本页所述 UHI ids {0,2,4} 的 begin/end reassembly
  • Intra-Chip DMA Descriptor — local-leg OciDescriptorCommonIssuedFromTcs§5 是 UHI spans 渲染到的共享 DmaTransfer record + per-span XStat set
  • OCI Command DMA-id Selectors — on-chip dma_id pairing key(与 UHI band 裸 32-bit transaction_id 形成对比的 38-bit composite)
  • Continuation Queue — infeed/outfeed queue managers 背后支撑 QueueIdValues roles 的 SFLAG / continuation-queue runtime model
  • Payload: UHI/OCI/ICI/DMA — 更广泛 UHI/OCI/ICI payload family 的 trace-point-id↔message-name registry 和 on-wire bit decodes
  • ICR DMA Timeline Band — on-chip ICI band(sibling pxc lambda),不同于本 host band