Host↔Device DMA
本页所有地址均适用于
libtpu-0.0.40-cp314wheel 中的libtpu.so(构建libtpu_lts_20260413_b_RC00,build-id md589edbbe81c5b328a958fe628a9f2207d)。该镜像未剥离符号;反混淆后的 C++ 符号名按原样引用。.textVMA 等于文件偏移(.text基址0xe63c000);.data.rel.ro带有0x200000的 VMA→file delta。其他版本会不同。
摘要
host↔device DMA 是一种另一端位于 host memory 的传输:向 TensorCore queue 供给数据的 infeed(host→device)、排空队列的 outfeed(device→host)、activation data 的 direct-write,或来自 host-interface bridge 的 physical-address response。这类传输的本地 leg 的片上描述符是 片上 DMA 描述符 中记录的 OciDescriptorCommonIssuedFromTcs;本页记录 profiler 中跨边界 leg 会发生什么:device trace stream 的 host-interface 事件如何被重新组装为一个 host↔device transfer span,它被归入哪个方向(H2D vs D2H),以及 host endpoint 为渲染出的事件贡献了什么。
重组逻辑是 DeriveHostDmaTransfers,即一对 timeline producer(每个 silicon generation 一个):它们扫描合并后的 device trace,按逐事务 key 将一个“started” host-DMA 事件与其“completion”事件配对,并向 host-DMA lane 发射一个 XEvent。pxc(Pufferfish/BarnaCore)generation 通过 UHI host-interface band(trace points {0, 2, 4})完成此事,并产生携带 kind tag 6(MemcpyH2D)或 7(MemcpyD2H) 的 DmaTransfer record,这是整个二进制中唯一写入这两个 tag 的位置。jxc(Jellyfish)generation 通过完全不同的机制完成此事:在 HIB(host-interface block)descriptor band 上进行 SyncFlagUpdate-deque 配对,key 是 sync-flag target,而不是 transaction id,并渲染到 Sync-Flag lanes。本页负责 derivation、tag-6/7 语义和 host endpoint;UHI message wire format 和完整 QueueIdValues enum 见 UHI Host-Interface DMA,DmaTransfer record + 逐 span XStat 集合见 片上 DMA 描述符 §5。
重新实现时,契约是:
- 两个
DeriveHostDmaTransferspass:pxcUHI host-DMA pass(MemcpyH2D/MemcpyD2Hspan 的来源)和jxcHIB host-DMA pass(SyncFlagUpdate-deque 配对),以及它们为何在结构上不同。 - tag-6/7 选择器:字节精确的
(queue_id & ~1) == 2 ? 6 : 7规则,它从 STARTED 事件的queue_id将 host DMA 分桶为 H2D vs D2H,并决定产生的 lane(63 / 64)。 - transfer 构建:STARTED 事件如何打开一个
DmaTransfer槽位(begin gtc、byte count、queue label、kind tag),RESPONSE 事件如何关闭它(end gtc),二者按trace_id_header.transaction_id配对。 - host endpoint:host 侧字段(
queue_id、dva、sequence_number)贡献什么:queue_id成为 H2D/D2H 选择器和queueXStat;dva(device virtual address)和sequence_number会被解码但丢弃,因此不会渲染任何 host↔device address。
pxc host-DMA producer | xprof::tpu::ConvertTpuTraceToXPlane<…pxc::profiler::TraceEntry>{lambda}{lambda} @ 0xf26afa0 |
pxc 片上(ICI)producer | 同一 template 的 sibling lambda @ 0xf26c6e0(不写入 tag 6/7) |
jxc host-DMA producer | DeriveHostDmaTransfers,内联 @ 0xf252f00–0xf25303b 到 jxc lambda @ 0xf252260 |
| 共享 renderer | xprof::tpu::ConvertDmaTransfersToXPlane(absl::Span<DmaTransfer>, …) @ 0xf254bc0 |
jxc populate side | xprof::tpu::ConvertDmaDescriptorToXPlane @ 0xf253620 |
jxc consume side | xprof::tpu::ConvertDmaEndsToXPlane<…jxc…> @ 0xf25c500 |
| Tag-6/7 选择器 | (((queue_id & ~1) == 2) ? 6 : 7) @ 0xf26b5a6;.text 中唯一匹配 |
| Host-DMA lanes | TpuComponent 63 MemcpyH2D,64 MemcpyD2H(pxc);17 Tensor Core Sync Flag,23 Barna Core Fabric Sync(jxc) |
| 证据等级 | 重新实现级 / 经 IDA 反编译 + FDP descriptor pool 字节确认 |
1. 两代,两种 Host-DMA Derivation
ConvertDmaTransfersToXPlane @ 0xf254bc0 是共享 renderer,会将一段 DmaTransfer record 转为 device XEvent。它有 16 个调用方(对 .text 做 e8-rel32 扫描),每个 silicon generation 有一个 host-DMA producer 和一个片上 ICI producer,另有 merge/helper 站点。其中,正好一个会写 kind tag 6 或 7:对整个 .text 扫描 tag selector pattern(83 e0 fe = and ~1,随后 83 f1 07 = xor 0x7)只返回一个命中,位于 pxc host-DMA producer 内的 0xf26b5aa。较新的 SparseCore generations(vfc/vlc/glc/gfc)会调用共享 renderer,但从不发射 MemcpyH2D/MemcpyD2H span;jxc 则完全通过另一个 pass 路由 host DMA。
| 方面 | pxc host-DMA(UHI band) | jxc host-DMA(HIB band) |
|---|---|---|
| Producer | lambda @ 0xf26afa0 | DeriveHostDmaTransfers(内联)@ 0xf252f00 |
| Trace points | UHI {0, 2, 4} | nf_descriptor_hib + 4 个 HIB band |
| 配对 key | transaction_id(32-bit) | sync_flag_target(UpdatedSyncFlagTarget) |
| Begin marker | STARTED(id 0) | nf_descriptor source-sync-flag target |
| End marker | RESPONSE_READ/WRITE(id 2 / id 4) | LastSyncForTracedDma completion |
| Byte count | size(f5,raw) | length << 10(1 KiB 单位,GetDmaSize) |
| KIND / lanes | tag 6/7 → MemcpyH2D 63 / MemcpyD2H 64 | kind → DMA Local/DMA Remote/DMA H2D |
| Render lanes | 63 / 64 | 17 Tensor Core Sync Flag / 23 Barna Core Fabric Sync |
queue XStat | QueueId enum name(FILLED) | (携带在 descriptor XEvent 上) |
| Renderer | 共享 ConvertDmaTransfersToXPlane | ConvertDmaDescriptorToXPlane + ConvertDmaEndsToXPlane |
注意 —
pxctemplateConvertTpuTraceToXPlane<…pxc::profiler::TraceEntry>实例化了两个嵌套 lambda,二者都馈入共享 renderer:第一个(@0xf26afa0,call @0xf26b9b7)是本文记录的 UHI host-DMA pass;第二个(@0xf26c6e0)是 ICR Node-Fabric 片上 pass,它将 ICI tag 2/3 发射到 lanes 54/55(见 ICR DMA Timeline Band)。它们共享 renderer 和DmaTransferrecord 形状,但 key 使用不同 trace point,并写入不同 tag。置信度:CONFIRMED(16-caller 拆分和唯一 tag-6/7 字节扫描命中)。
2. pxc UHI Host-DMA Derivation
2.1 三个 trace point
producer 构建一个 3 元素 TracePoints list(每个 UHI host-interface event 一个打包 {band, id} 条目),将其传给 GetMerged,然后迭代合并后的按时间排序 stream。该 list 在反编译中按字节可见:每个条目都是打包的 64-bit (band << 32) | id。第一个条目是 0x400000000 = (band 4) | (id 0),即 STARTED 事件;随后追加 ids 2 和 4 的条目,并在调用前将 list size 设为 3:
// xprof::tpu::ConvertTpuTraceToXPlane<pxc::…TraceEntry>{lambda}{lambda} sub_F26AFA0
*v10 = 0x400000000LL; // @0xf26afee entry[0] = (band 4)|(id 0) = STARTED
v11[2] = 2; // @0xf26b03d entry[1] id 2 (Read response)
// + entry[2] id 4 (@0xf26b04e), list size = 3 (@0xf26b063)
TpuTraceEntries<…pxc…TraceEntry>::GetMerged(&v90, v8, &ptr); // @0xf26b07f, ids {0, 2, 4}
```text
| `trace_point_id` | UHI message(`pxc::profiler::`) | oneof case | 角色 |
|---:|---|---:|---|
| 0 | `UhiHostDmaTransactionStartedAddressTranslation` | 2 | BEGIN + byte count + queue + tag |
| 2 | `UhiHostPhysicalResponseRead` | 4 | END(read response) |
| 4 | `UhiHostPhysicalResponseWrite` | 6 | END(write response) |
逐条目分派读取 `trace_point_id`(`TraceHeader+0x18`)并据此分支(反编译确认 `if (v21 == 4)` → Write-response,`if (v21 == 2)` → Read-response,fall-through `== 0` → Started),随后用标准 proto2 oneof-case guard 解析匹配的 message global(`UhiHostDmaTransactionStartedAddressTranslation_globals_` @ `0x2237ac40`、`UhiHostPhysicalResponseRead_globals_` @ `0x2237ab98`、`UhiHostPhysicalResponseWrite_globals_` @ `0x2237ab70`)。id↔name 绑定(id 0 = `UHI_HOST_DMA_TRANSACTION_STARTED_ADDRESS_TRANSLATION`,id 2 = `UHI_HOST_PHYSICAL_RESPONSE_READ`,id 4 = `UHI_HOST_PHYSICAL_RESPONSE_WRITE`)与 UHI band 的 trace-point registry 一致。置信度:CONFIRMED(字节精确 seed + `== 4 / == 2 / == 0` 分派 + 三个 message global)。
### 2.2 STARTED 事件 — 打开 transfer(host endpoint)
id-0 STARTED 事件是唯一携带 host endpoint 的事件。其字段布局(完整 wire format 见 [UHI Host-Interface DMA](uhi-host-interface.md))以及 producer 对每个字段的处理如下:
| f# | 字段 | 类型 | cpp off | Producer 用途 |
|---:|---|---|---:|---|
| 1 | `trace_id_header` | `TraceIdHeader` | `+0x18` | `dma_id` = `transaction_id`(`hdr+0x18`)— 配对 key |
| 2 | `queue_id` | `QueueIdValues` | `+0x20` | KIND-tag 选择器(§3)**以及** `queue` XStat(enum name) |
| 3 | `sequence_number` | u32 | `+0x24` | 解码,**丢弃** |
| 4 | `dva` | u64 | `+0x28` | device virtual address — 解码,**丢弃** |
| 5 | `size` | u32 | `+0x30` | `byte_count` = `size`(无 granule shift) |
begin-store 块(`@0xf26b560`,字节精确)在以 `transaction_id` 为 key 的 map 中打开一个 `DmaTransfer` 槽位(槽位是 map value 形式;偏移在该槽内):
```c
// id-0 STARTED begin store @0xf26b560
slot.begin_gtc = gtc; // [slot+0x8] = TraceHeader.timestamp (+0x20)
slot.begin_present = 1; // [slot+0x10]
slot.byte_count = msg.size; // [slot+0x28] = [msg+0x30], NO shift @0xf26b568
slot.queue.ptr = NameOfDenseEnum(queue_id); // [slot+0x30] (QueueIdValues name / SSO)
slot.queue.len = …; // [slot+0x38]
slot.kind_tag = (((queue_id & ~1) == 2) ? 6 : 7); // [slot+0x40] §3queue label 通过 proto2::internal::NameOfDenseEnum<&…QueueIdValues_descriptor, 0, 21> 取得(dense 22-value enum,索引 0..21):快路径索引 descriptor table,慢路径落到 NameOfDenseEnumSlow。这是 renderer 作为 XStat 79 附加到逐 DMA span 的 queue 字符串;它在 host-DMA span 上非空(在 ICI 片上 band 上为空)。
陷阱 — host endpoint 被丢弃。 STARTED 事件携带一个 device virtual address(
dva,f4 @+0x28),也就是命名 host↔device copy 的 device 端的字段,但 producer 从不读取它。它也不读取sequence_number。只有trace_id_header(用于 key)、queue_id(用于 tag + label)和size(用于 byte count)保留下来进入渲染的 span。因此捕获到的pxchost-DMAXEvent会显示多少字节和哪个 queue,但不显示 host 或 device address。这与片上 band 一样,后者也会丢弃其src/dstendpoint(片上 DMA 描述符 §5)。libtpu.so中没有链接任何会重新读取dva的下游 symbolizer。置信度:CONFIRMED(producer 只读取 STARTED message 的+0x18/+0x20/+0x30)。
2.3 RESPONSE 事件 — 关闭 transfer
id-2(UhiHostPhysicalResponseRead)和 id-4(UhiHostPhysicalResponseWrite)事件是 END marker。每个都携带 {f1 trace_id_header @+0x18, f2 is_l2_pte_fetch (bool) @+0x24, f3 chunk_id (u32)};producer 只读取 trace_id_header(用于查找槽位)和事件 gtc。is_l2_pte_fetch/chunk_id 字段会被解码但丢弃。end-store 块(@0xf26b0d0):
// id-2 / id-4 RESPONSE end store @0xf26b0d0
slot.end_gtc = gtc; // [slot+0x18] = TraceHeader.timestamp
slot.end_present = 1; // [slot+0x20]
```text
**配对。** 槽位 key 仅为 `trace_id_header.transaction_id`,一个完整的 32-bit 逐事务 tag,零扩展到 `flat_hash_map<u64, DmaTransfer>` key(policy @ `0x21646fe8`),**不会**像片上 ICR band 那样掩到 38-bit composite(后者会折入 `core_id`/`chip_id`)。一个 host DMA 正好有一个 `transaction_id`;它的 STARTED(id 0)和 RESPONSE(id 2 read / id 4 write)共享该 id 并写入同一槽位,产生一个 `DmaTransfer {begin, end, byte_count, queue, tag}`。如果 STARTED 到达时槽位已经填满,producer 会 flush 旧 transfer 并重新打开(`@0xf26b52f`)。置信度:CONFIRMED。
> **注意 — read-response vs write-response *不是* H2D/D2H 信号。** 直觉上可能会认为 id-2(READ response)关闭 device→host read,而 id-4(WRITE response)关闭 host→device write,但 producer 完全根据 STARTED 事件中的 `queue_id` 决定*方向*(§3),两个 response 变体都只是提供 end timestamp。重新实现者不得从关闭槽位的是哪个 RESPONSE id 推断方向。置信度:CONFIRMED(end store 只写 gtc/present;tag 在 begin 时固定)。
---
## 3. Tag-6/7(H2D vs D2H)选择器
host-DMA 路径的核心行是 kind-tag 计算,字节精确位于 `0xf26b5a6`,且是 `.text` 中**唯一**这样的站点:
```c
// @0xf26b5a6 — the sole tag-6/7 producer in the binary
// asm: mov eax, queue_id ; and eax, 0xFFFFFFFE ; cmp eax, 2 ; sete cl ; xor ecx, 0x7
slot.kind_tag = (((queue_id & ~1) == 2) ? 6 : 7); // decompile: (((v22[4] & 0xFFFFFFFE) == 2) ^ 7)(queue_id & ~1) == 2 只对 queue_id ∈ {2, 3} 成立,即 QUEUE_ID_DIRECTWRITEQUEUE0 和 QUEUE_ID_DIRECTWRITEQUEUE1。sete 产生 1,然后 xor 1, 7 = 6;对所有其他 queue_id,sete 产生 0,然后 xor 0, 7 = 7。
queue_id | Queue class | (queue_id & ~1) == 2 | KIND tag | Lane |
|---|---|---|---|---|
| 2, 3 | DIRECTWRITEQUEUE0/1 | yes | 6(MemcpyH2D) | 63 |
| 0, 1, 4..21 | debug / magic / infeed / outfeed / reserved | no | 7(MemcpyD2H) | 64 |
因此,只有两个 direct-write queue 被分桶为 host→device;所有其他 queue,包括直觉上可能以为是 H2D 的 infeed queue,都会落到 D2H。完整 22-value QueueIdValues enum 和原因见 UHI Host-Interface DMA。
陷阱 — 方向是 trace-design bucketing,不一定是物理方向。 该规则按字节固定(
and ~1; cmp 2),但将INFEEDQUEUE*/OUTFEEDQUEUE*分类为 D2H 是反映硬件真实数据方向,还是有意的 timeline bucketing 选择,无法仅从libtpu.so证明;只有捕获的 XSpace 才能显示最终 lane placement。字面谓词为 CONFIRMED;它编码的 firmware queue→direction 约定为 LOW(解码为该谓词,未对 silicon 验证)。
tag → lane / event-metadata 映射
共享 renderer 的 kind switch 通过 (kind_tag - 2) 索引 @ 0xab589bc 的 jump table(add $0xfffffffe,%eax; cmp $5,%eax; ja skip; movslq (r9,rax,4),rax @ 0xf255041–0xf25504c,因此有效 tag 范围是 2..7),在表索引 4 和 5 上分别给出 tag 6 和 7 的不同分支:
| tag | jt idx | jt arm | TpuComponent line | XEvent metadata | 来源 |
|---|---|---|---|---|---|
| 6 | 4 | 0xf25507e | 63 MemcpyH2D | "MemcpyH2D" | queue_id ∈ {2,3}(direct-write) |
| 7 | 5 | 0xf255340 | 64 MemcpyD2H | "MemcpyD2H" | 所有其他 queue_id |
反编译确认 renderer 在 kind switch 前 intern GetOrCreateEventMetadata("MemcpyH2D")(@ 0xf254e5f,length 9)和 GetOrCreateEventMetadata("MemcpyD2H")(@ 0xf254e82,length 9),随后将 tag 6/7 路由到 H2D/D2H 分支。置信度:CONFIRMED。(这修正了早先 sibling note 中将 tag 6/7 列为“unused on pxc”以及 tag/lane 表转置的问题:tag 6 = H2D = lane 63,tag 7 = D2H = lane 64。)
渲染出的 span
逐 span XStat 是 片上 DMA 描述符 §5 中记录的共享 DmaTransfer 集合,并有两个 host-DMA 特点:
bytes_transferred(78) =size,即原始字节计数;不像片上 band 的length << {2,9},这里没有 granule shift。queue(79) =QueueIdenum name(例如QUEUE_ID_DIRECTWRITEQUEUE0),在 host-DMA span 上非空。details(string)保持为空(producer 写[slot+0x30]/[slot+0x38]= queue,从不写[slot+0x48]= details)。
4. jxc HIB Host-DMA Derivation
jxc 是 proto2-self-describing 的,并且不发射 MemcpyH2D/MemcpyD2H span。它的 host-interface(HIB)DMA timeline 由 DeriveHostDmaTransfers 构建,这是一个 SyncFlagUpdate-deque 配对:它记录 descriptor-staged 的“begin”,并将其与 sync-flag-update “completion”匹配。staging 每个 begin 的 intra-chip descriptor 是 片上 DMA 描述符 中的那个;本节记录构建在其上的 host↔device 配对。
4.1 五个 trace point
DeriveHostDmaTransfers 内联到 jxc ConvertTpuTraceToXPlane lambda @ 0xf252260;其 static-init 块 @ 0xf252f00–0xf25303b 构造五个 function-local TracePoint static(五对 __cxa_guard_acquire/release),随后通过 TpuTraceEntries::GetMerged call @ 0xf252382(callee @ 0xf253080)合并它们:
| Static | Band / id | 角色 |
|---|---|---|
nf_descriptor_hib | nf_descriptor(case 3),id 2(HIB) | host-side staged descriptor — begin |
nf_hib_write_cmd | nf(case 6),HIB_WRITE_COMMAND(id 22) | HIB write command |
nf_hib_write_data_end | nf(case 6),HIB_WRITE_DATA_END(id 23) | HIB write-data end |
hib_hbm_write | hib_hbm_write(case 19),HBM_WRITE(id 87) | HIB→HBM write |
hib_sync_update | hib_sync_update(case 18),SYNC_UPDATE(id 86) | sync-flag-update — completion |
这五个是 pxc UHI host-DMA band 的 jxc 对应物。置信度:CONFIRMED(五个 guard-var 符号 + 内联 init)。
4.2 SyncFlagUpdate deque map
配对结构是 absl::flat_hash_map<uint64 sync_flag_target, std::deque<SyncFlagUpdate>>(policy @ 0x21646f10;policy 类型在反编译中按字节可见)。SyncFlagUpdate 是 0x38 字节(56 字节)的 POD(stride 由 MergeSyncFlagUpdates 的 add r15, 0x38 确认):
| 偏移 | 字段 | 用途 |
|---|---|---|
+0x00 | sync_flag_target | 配对 key(SourceSyncFlagTarget / UpdatedSyncFlagTarget 结果) |
+0x08 | dma_id | flow-stat 值来源(& 0xff_ffff_ffff_ffff → XFlow id) |
+0x10 | kind | DMA Local/Remote/H2D event-metadata 选择器(0..4) |
+0x18..+0x37 | begin_gtc / size / endpoint | 记录的 begin metadata(由 reflection 填充) |
逐 core map 由 MergeSyncFlagUpdates @ 0xf248ee0 合并(遍历每个 map 的 {key, deque} 并合并 deque),然后再渲染。
注意 —
+0x18..+0x37槽位(begin_gtc、dma size、endpoint chip/node)由 populate side 的标准 reflection walk 填充;target/dma_id/kind按字节钉牢,但其余 0x20 字节的逐字段映射未被 single-step。配对语义已解码;精确 begin-metadata 槽位布局为 CONFIRMED-PARTIAL。
4.3 populate side — ConvertDmaDescriptorToXPlane
ConvertDmaDescriptorToXPlane @ 0xf253620 将每个 staged HIB descriptor 渲染为一个 descriptor XEvent,并且入队一个 pending begin:
// xprof::tpu::ConvertDmaDescriptorToXPlane sub_F253620
// interns 4 event names: "DMA Local"(9), "DMA Remote"(10), "DMA H2D"(7), "DMA D2H"(7) + flow StatType 0x38
for (wrapper : descriptors):
dma_id = wrapper.GetDmaId(); // jxc composite @0xf698180
if (wrapper.EntryDataCase() != 3) continue; // gate: nf_descriptor @0xf25388b
key = wrapper.SourceSyncFlagTarget(); // sync_flag_target @0xf6982e0
slot = map.find_or_prepare_insert_large(key); // @0xf24f320
slot.push_back(SyncFlagUpdate{ .target = key, .dma_id = dma_id, .kind = …, … });
bytes = wrapper.GetDmaSize(); // = length(@descr+0x48) << 10 (1 KiB) @0xf6982a0
```text
`SourceSyncFlagTarget` @ `0xf6982e0` 是 descriptor 的 source-sync-flag-update target(对 `descr+0x60` 的 OCI SyncFlag fold);每个 staged HIB descriptor 都会在该 target 下入队一个 pending begin。`GetDmaSize` 已按字节确认:`nf_descriptor`(case 3)→ `length(@descr+0x48) << 10`。置信度:CONFIRMED(四个 event name、`deque<SyncFlagUpdate>` policy 上的 `find_or_prepare_insert_large`、`GetDmaId`/`SourceSyncFlagTarget`/`GetDmaSize` call 都存在于反编译中)。
### 4.4 consume side — `ConvertDmaEndsToXPlane<jxc>`
`ConvertDmaEndsToXPlane<jxc>` @ `0xf25c500` 消费 completion 并发射配对后的 host-DMA span:
```c
// xprof::tpu::ConvertDmaEndsToXPlane<…jxc…> sub_F25C500
// interns 3 event names: "DMA Local"(9), "DMA Remote"(10), "DMA H2D"(7) + flow StatType 0x38
for (wrapper : completions):
if (!wrapper.LastSyncForTracedDma()) continue; // gate: only the LAST sync @0xf6986a0
key = wrapper.UpdatedSyncFlagTarget(); // completion target @0xf698400
begin = map.lookup(key).pop_front(); // SwissTable lookup of pending begin
name = event_meta[begin.kind]; // cmp kind,5; jae skip @0xf25c807
span = GtcSpan{ begin.recorded_gtc, this.gtc };
line.AddEvent(span, name); // @0xf25c843
span.flow = begin.dma_id & 0xff_ffff_ffff_ffff; // flow XStat 0x38 @0xf25c861end gate LastSyncForTracedDma @ 0xf6986a0 已按字节确认:case 0xb(hib_sync_update)→ field(@submsg+0x28).f@0x1c >> 31(last top-bit);case 9(cs_external sync-flag-update)→ (f@0x30 != 0) && (f@0x3c != 0)(last_sync_for_dma && successful_sync 门控)。UpdatedSyncFlagTarget @ 0xf698400 是 completion 的 target(EntryDataCase keyed sync-flag-target pack),用作 deque key。flow 值在成为 XFlow id 前被掩到 56 bit(& 0xFFFFFFFFFFFFFF)。置信度:CONFIRMED(字节精确 gate + flow mask + kind < 5 选择器 + AddEvent)。
ConvertDmaEndsToXPlane<jxc> 被调用两次:一次来自 lambda(@0xf25b1e0),带 TpuComponent 23 Barna Core Fabric Sync(edi = 0x17,call @ 0xf25b8db);另一次(@0xf25d6e0)带 TpuComponent 17 Tensor Core Sync Flag(edi = 0x11,call @ 0xf25ee62)。因此 jxc host-DMA span 会落到 Sync-Flag lanes(17/23),根据匹配 begin 的 kind 命名为 DMA Local/DMA Remote/DMA H2D,并通过 dma_id flow-link 到其 descriptor。这是 pxc UHI begin/end 配对的 jxc analog,但 key 是 sync-flag target,且由 DMA 的最后一次 sync-flag-update 门控,而不是 RESPONSE trace point。
注意 —
kind→ direction label。 host-DMA span 的名称(DMA Local/Remote/H2D)由记录的SyncFlagUpdate.kind(+0x10,以cmp kind, 5; jae skip边界索引 event-metadata array)选择。哪个nf_descriptor字段(descriptor_sourceenum / dma locality)设置各个kind,在 populate side 中已结构性读取,但未制成 descriptor locality enum 对照表;kind索引来源为 CONFIRMED,精确 descriptor-field →kind映射为 LOW。
5. 重新实现说明
- 检测 host DMA。 在
pxc上,一个传输当且仅当源自 UHI band(trace points{0,2,4})时是 host↔device;除 tag 外,DmaTransferrecord 上没有额外标志(6/7 = host,2/3 = 片上 ICI)。在jxc上,host DMA 是 HIBnf_descriptor_hibband staging 且由hib_sync_updatecompletion 关闭的任何 DMA;它渲染在 Sync-Flag lanes 上,不是专用 Memcpy lane。 - 方向。
pxc:(queue_id & ~1) == 2 ? H2D : D2H,只有DIRECTWRITEQUEUE0/1是 H2D。jxc:匹配 begin 的kind字段(DMA Local/Remote/H2D);没有单独的 H2D/D2H tag;“Local”覆盖片上 staged 情形。 - Byte count。
pxc:原始size(无 shift)。jxc:length << 10(1 KiB granule)。不要将片上 band 的<< {2,9}granule 逻辑应用到任一 host 路径。 - 配对 key。
pxc:32-bittransaction_id,每个 host DMA 一个。jxc:sync_flag_target(SourceSyncFlagTarget/UpdatedSyncFlagTargetfold),且每个 DMA 的最后一次 sync-flag-update 关闭 span。 - host endpoint 仅保留摘要。 两条路径都不渲染 host 或 device address。
pxc解码并丢弃dva;jxc在SyncFlagUpdate中记录 endpoint 槽位,但没有 symbolizer 回读它。需要 host↔device address 的重新实现者必须重新读取被丢弃的 proto 字段(pxcSTARTED+0x28处的dva);libtpu.so中没有 consumer 这样做。
交叉引用
- UHI Host-Interface DMA — UHI message wire format,以及 tag-6/7 选择器据以分派的完整 22-value
QueueIdValuesenum - 片上 DMA 描述符 —
OciDescriptorCommonIssuedFromTcslocal-leg descriptor;§5 记录本页 span 使用的共享DmaTransferrecord + 逐 span XStat 集合 - OCI Command DMA-ID —
trace_id_headerDMA-id 配对 key 和逐 band id helper(pxctransaction_idanalog) - Rolled / Strided / General 发射器 — 发射
jxchost-DMA pass 所 staging 描述符的 transfer-body 发射器 - ICR DMA Timeline Band — 由 sibling
pxclambda @0xf26c6e0产生的片上 ICI band(tags 2/3,lanes 54/55),不同于此 host band - DMA Endpoint Rendering —
ConvertDmaTransfersToXPlane如何将配对后的DmaTransfer渲染为 deviceXEvent,以及它保留和丢弃哪些字段 - JXC DMA / HBM-Mux / BrnPerf —
SyncFlagUpdate配对渲染到 Sync-Flag lanes(17/23)的jxcDMA band