片内 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→文件增量。其他版本会不同。
摘要
TensorCore sequencer 发出的每个片上 DMA(VMEM↔HBM 暂存、标量 memset、collective 的本地段、host infeed/outfeed)都由一条记录描述:OciDescriptorCommonIssuedFromTcs(“OCI descriptor common, issued from the TensorCore Sequencer”)。它是一个 17 字段、按位打包的结构;两个内存端点各自由一个 (mem_id, core_id, opcode) 三元组命名,传输类别是一个 dma_type 标签,大小则是一对 (length, length_granule)。同一描述符家族会按硅片代际实例化:pxc(Pufferfish/BarnaCore)、vfc/glc/gfc(SparseCore)以及 vlc(无 SparseCore);各代类之间的差异仅在于附加到内存空间枚举值上的复合名称,字段布局、opcode 枚举以及 dma_type/length_granule 枚举在所有代际中都相同。
这个描述符是跨芯片 ICI 线缆描述符的片内对应物:ICI 构建器(JellyfishDmaDescriptorState / PufferfishDmaDescriptorState)会在 SMEM 中暂存一个 8 或 24 word 的数组,并把远端 chip id 和 remote-sync-flag 地址写入其中;而片内描述符不会离开芯片,两个端点都解析为本地层级(HBM、VMEM、SMEM、CMEM、IMEM、BMEM、SPMEM)。已经理解 DMA 引擎“source descriptor / destination descriptor / length / completion-flag”四元组的读者会立即认出其形状;本页记录的两个意外点是:(1) 内存端点是多态的,同一个 2-bit mem_id 值会根据配套的 3-bit core_id 解析到不同物理层级;(2) 二进制中存在两个互不相关的 DmaType 枚举,一个由 LLO/runtime 层携带,另一个在 profiler 描述符中,二者的值数量和顺序不同。
本页负责三件事:SrcMem/DstMem 内存空间枚举(MemMemId + MemCoreId),以及 (mem_id, core_id) 对如何渲染为物理层级;Src/Dst Opcode 枚举,以及 LLO DMA op 实际携带的字符串值 opcode 属性;还有 LLO DMA-start op 填写的描述符字段布局(偏移 +0x18..+0x5c)。Simple-vs-Strided DmaParameters 选择器见 DmaParameters 选择器;rolled/strided/general 传输体发射器见 Rolled / Strided / General 发射器;生成地址操作数的 tile-index→flat-offset 代数见 Tile-Index 展开。
对于重新实现,契约是:
- 两个内存空间枚举:4 值
MemMemId和 8 值MemCoreId,以及把(mem_id, core_id)对转换为具名物理层级的分段选择规则。 - 两个 opcode 枚举:
SrcOpcode {READ, …}和DstOpcode {WRITE, …},以及 LLODmaSimpleStartOp/DmaGeneralStartOp携带的字符串值dst_opcode属性(write_4b/read_and_add/atomic_add),再加上限制每个 opcode 的内存空间门控。 - 端点渲染:
MemorySpaceToDriverResource(MemorySpace)(用于写入描述符地址 word 的 LLOMemorySpace→ driver-resource id),以及(mem_id, core_id, opcode, addr)如何组合成源/目标端点。 - 字段布局:
+0x18..+0x5c的 17 个字段、(length, length_granule)大小对,以及哪些字段由 LLO DMA-start op 写入、哪些字段由 profiler 描述符解析。
| 描述符(profiler/wire) | asic_sw::driver::deepsea::<gen>::profiler::OciDescriptorCommonIssuedFromTcs |
| pxc ctor | …pxc::profiler::OciDescriptorCommonIssuedFromTcs::OciDescriptorCommonIssuedFromTcs @ 0x1cf1b620 |
| 逐代解码 | …<gen>::profiler::DecodeOciDescriptorCommonIssuedFromTcs (pxc @ 0xf5bace0, vlc @ 0xf5e29a0, vfc @ 0xf607b20, glc @ 0xf63a140, gfc @ 0xf66fba0) |
| 逐代编码 | …<gen>::profiler::EncodeOciDescriptorCommonIssuedFromTcs (pxc @ 0xf5cc700) |
| 端点渲染 | xla::jellyfish::MemorySpaceToDriverResource(MemorySpace) @ 0x1d6223e0 |
| LLO dst-opcode 读取器 | xla::tpu::sparse_core::GetDstOpcode<DmaSimpleStartOp> @ 0x135aaa60, <DmaGeneralStartOp> @ 0x135b2be0 |
Runtime DmaType 枚举 | xla::jellyfish::DmaType — 3 个值(<< operator @ 0x1d5ae080) |
| 字段范围 | +0x18 (trace_id_header) … +0x5c (length_granule);大小 word 位于 +0x58/+0x5c |
| 证据等级 | 可重新实现级 / 已按字节对 IDA 反编译 + FDP 描述符池确认 |
1. 两个内存空间枚举(SrcMem / DstMem) {#1-the-two-memory-space-enums-srcmem--dstmem}
目的
DMA 端点并不是由单个内存空间整数命名的。描述符把每个端点的空间拆成两个字段:2-bit mem_id(src_mem_mem_id @ +0x24,dst_mem_mem_id @ +0x30)和 3-bit core_id(src_mem_core_id @ +0x28,dst_mem_core_id @ +0x34)。这对字段是多态的:同一个 mem_id 值会根据配套 core_id 选择的 core 类别解析到不同物理层级。四个 2-bit 代码正是用这种方式覆盖完整的 HBM / VMEM / SMEM / IMEM / CMEM / BMEM / SPMEM 层级空间,而无需更宽字段。
编码
这两个枚举已从 FDP 描述符池(切出的 OciDescriptorCommonIssuedFromTcs DescriptorProto 的 enum_type 块)按字节验证,在 source(SRC_*)和 destination(DST_*)之间完全相同:
MemMemId (2-bit) | pxc 复合名称 (SRC_MEM_MEM_ID_*) |
|---|---|
| 0 | HBM_TCVMEM_BCBMEM |
| 1 | RSVD_TCSMEM_BCSMEM |
| 2 | CMEM_TCIMEM_BCBIMEM |
| 3 | RSVD_RSVD_BCVIMEM |
MemCoreId (3-bit) | 名称 (SRC_MEM_CORE_ID_*) | 选择分段 |
|---|---|---|
| 0 | RESERVED | — |
| 1 | NONCORE | 第 1 段(HBM / CMEM / …) |
| 2 | TC0 | 第 2 段(TCVMEM / TCSMEM / TCIMEM) |
| 3 | TC1 | 第 2 段 |
| 4 | BC0 | 第 3 段(BCBMEM / BCSMEM / BCBIMEM) |
| 5 | BC1 | 第 3 段 |
| 6 | BC2 | 第 3 段 |
| 7 | BC3 | 第 3 段 |
复合名称是用 _ 连接的三元组 <noncore>_<tensorcore>_<thirdcore>。要把 (mem_id, core_id) 对解析为物理层级,先选取 mem_id 行,再选择由 core_id 类别命名的分段:
mem_id = 0, core_id = NONCORE -> HBM (HBM_TCVMEM_BCBMEM, 1st segment)
mem_id = 0, core_id = TC0/TC1 -> TCVMEM (2nd segment)
mem_id = 0, core_id = BC0..3 -> BCBMEM (3rd segment)
mem_id = 2, core_id = NONCORE -> CMEM
mem_id = 2, core_id = TC0 -> TC IMEM
mem_id = 1, core_id = TC0 -> TC SMEM注意 — 分段选择规则(NONCORE→第 1 段,TC*→第 2 段,BC*/SC*→第 3 段)是根据复合名称结构推断出来的,并不是从渲染器按字节证明的:
libtpu.so中没有链接MemMemId × MemCoreId → tier符号化器。解码函数(DecodeOciDescriptorCommonIssuedFromTcs)会把mem_id/core_id解析到 proto 中,但唯一消费该描述符的片内 DMA timeline pass(ConvertDmaTransfersToXPlane@0xf254bc0)丢弃两个端点,见 §5。mem_id/core_id值→名称绑定已确认;它们暗示的层级解析为推断。
跨代重命名
MemMemId 的值集合固定为四个;只有复合名称会按代际变化,以跟踪每一代的第三 core 类别:
| 代际 / 家族 | mem_id=0 | mem_id=1 | mem_id=2 | mem_id=3 |
|---|---|---|---|---|
pxc (BarnaCore) | HBM_TCVMEM_BCBMEM | RSVD_TCSMEM_BCSMEM | CMEM_TCIMEM_BCBIMEM | RSVD_RSVD_BCVIMEM |
vfc/glc/gfc (SparseCore) | HBM_TCVMEM_SCSPMEM | HOST_TCSMEM_SCSMEM | VMEMALL_TCIMEM_SCSIMEM | NONCORERESERVEDMEM0_TCRESERVEDMEM_SCTIMEM |
vlc(2 段名,无 SparseCore) | HBM_TCVMEM | HOST_TCSMEM | NONCORERESERVEDMEM0_TCIMEM | NONCORERESERVEDMEM0_TCRESERVEDMEM |
vlc 名称是 2 段式的(无第三 core),因此它的 core_id 只有在选择 NONCORE 与 TC* 时才有实际意义。五个 gen 都以相同字段布局和相同 4 值 mem_id 枚举声明 OciDescriptorCommonIssuedFromTcs 类;这一点由五个逐代 Decode… / class-data 符号确认(…vfc…OciDescriptorCommonIssuedFromTcs::GetClassData @ 0x1cf23e40,…vlc… @ 0x1cf2cf80,等等)。
LLO 侧的 MemorySpace
描述符的 (mem_id, core_id) 对是端点的 wire/profiler 视图。在编译器内部,LLO DMA 操作数携带一个 xla::jellyfish::MemorySpace,这是 MemorySpace 枚举中记录的 17 值 runtime 枚举。描述符构建器通过 MemorySpaceToDriverResource(§3)把该 MemorySpace 转换为硬件端点;profiler 描述符中的 mem_id/core_id 是同一端点经过硬件编码后的读回值。重新实现时应端到端携带 MemorySpace,只在描述符边界映射到 (mem_id, core_id);不要把 17 值 LLO 枚举和 4 值 mem_id 混淆。
2. Opcode 枚举(SrcOpcode / DstOpcode) {#2-the-opcode-enums-srcopcode--dstopcode}
目的
每个端点携带一个 2-bit opcode(src_opcode @ +0x2c,dst_opcode @ +0x38),用于选择 DMA 引擎在该端点上除普通移动之外要执行的动作。source opcode 在普通读取和两种 memset 模式之间选择;destination opcode 在普通写入和两种 special-write / atomic 模式之间选择。
编码
两个枚举都是 2-bit,已从 FDP enum_type 块按字节验证:
SrcOpcode (+0x2c) | 名称 | 含义 |
|---|---|---|
| 0 | READ | 普通源读取 |
| 1 | RESERVED | — |
| 2 | INSTRUCTIONMEMSET | 填充 IMEM(无源读取) |
| 3 | DATAMEMSET | 填充数据内存(无源读取) |
DstOpcode (+0x38) | 名称 | 含义 |
|---|---|---|
| 0 | WRITE | 普通目标写入 |
| 1 | RESERVED | — |
| 2 | WRITESPECIAL0 | 特殊写入模式 0 |
| 3 | WRITESPECIAL1 | 特殊写入模式 1 |
LLO 侧字符串 opcode
LLO SparseCore DMA-start op 把 destination opcode 作为字符串值 MLIR 属性携带,而不是 2-bit 代码;lowering 会把字符串映射到枚举。GetDstOpcode<DmaSimpleStartOp> @ 0x135aaa60(以及字节相同的 DmaGeneralStartOp 对应体 @ 0x135b2be0)会把属性字节同固定的小端常量比较:
// xla::tpu::sparse_core::GetDstOpcode<DmaSimpleStartOp> sub_135AAA60
function GetDstOpcode(op, ms):
s = op.getDstOpcode() // string attr @ this+0x48 (sub_145B9700)
if len(s)==8 && s == "write_4b": // 0x62345F6574697277 LE -> "write_4b"
code = 1
elif len(s)==16 && s == <16-char write attr>: // vptest vs xmmword_A2D00C0
code = 2
elif len(s)==12 && s == "read_and_add": // 0x646E615F64616572 | 0x6464615F
code = 3
elif len(s)==10 && s == "atomic_add": // 0x615F63696D6F7461 | 0x6464
code = atomic-add path
else:
code = 0 // default: plain "write"
// memory-space gates (emitError on violation):
if code != default && ms != Smem:
error("dst_opcode is only supported for Smem.")
if atomic_add && ms != Spmem:
error("Atomic add dst_opcode is only supported for Spmem.")
return codeLLO op 发出的字符串→代码表:
LLO dst_opcode 字符串 | 长度 | 映射到 DstOpcode | MS 门控 |
|---|---|---|---|
| (缺省) | 0 | WRITE (0) | — |
write_4b | 8 | WRITESPECIAL0/1 | 仅 Smem |
| (16 字符 write 属性) | 16 | special write | 仅 Smem |
read_and_add | 12 | special / atomic | 仅 Smem |
atomic_add | 10 | atomic-add(元素类型化) | 仅 Spmem |
易错点 — opcode 在 LLO/MLIR 层是字符串,在 wire 上是 2-bit 枚举。直接从 2-bit 枚举驱动描述符的重新实现会漏掉门控:非默认 opcode 会被拒绝,除非 destination memory space 是
Smem(或atomic_add的Spmem)。getDstOpcode访问器通过属性 word 上的 bit-test((*(this+44) >> 19) & 0x10)读取this+0x48处的属性,因此该属性是可选的;缺省表示普通WRITEopcode。16 字符变体的确切拼写位于xmmword_A2D00C0,未完成字符串解码(HIGH,非 CONFIRMED)。
atomic_add 分支还会检查 destination memref 的元素类型(isF32 → code 1,isBF16 → 2,Float8E4M3FN → 3,否则报错 "Unsupported element type for atomic add."),因此 atomic-add opcode 在 Spmem 路径内部还会按元素宽度进一步专门化。
3. 端点渲染 {#3-endpoint-rendering}
目的
“渲染”端点,是指把 LLO (MemorySpace, byte-offset) 操作数转换为描述符的地址 word。内存空间会变成放在地址 word 高位字段中的 driver resource id;偏移会缩放到地址粒度后 OR 进低位。source 和 destination 共用同一渲染路径;描述符的 mem_id/core_id 字段是硬件对该编码的读回值。
算法
space→resource 映射是 MemorySpaceToDriverResource,它是对 LLO MemorySpace 枚举(17 值 runtime 枚举,不是 proto)的密集 switch。对于哪些层级可被 DMA 寻址以及各自取得什么 resource id,它是唯一按字节锚定的事实来源:
// xla::jellyfish::MemorySpaceToDriverResource(MemorySpace ms) sub_1D6223E0
function MemorySpaceToDriverResource(ms):
switch ms: // ms = the 17-value LLO MemorySpace enum
case 0 (<no memory space>): return 10
case 1 (hbm): return 2
case 2 (hib): return 3
case 3 (vmem): return 4
case 4 (cmem): FATAL("Unsupported memory space") // memory_space.cc:31
case 5 (smem): return 6
case 6 (sflag): return 0
case 7 (imem): return 5
case 8 (barna_core_bmem): return 7
case 9 (barna_core_smem): return 9
case 10 (barna_core_sflag): return 1
case 11 (barna_core_imem): return 8
case 12..16: FATAL("Unsupported memory space") // memory_space.cc:49返回的 resource id 会被写入描述符地址 word 的 bit 40(ICI 构建器 ctor 中的 SetSourceAddress(resource << 0x28);片内端点也用同一个 << 0x28 shift 渲染),而 tier 内偏移会在粒度缩放后 OR 进低位(EncodeDmaAddressForGranule @ 0x1d5402c0,对于 HBM/external-resource 操作数还会额外 OR bit 31 = 0x80000000 作为外部地址标记)。
注意 — 该函数返回的 driver-resource id 不是 LLO
MemorySpace枚举值;这个映射是一个置换。hbm(枚举 1)渲染为 resource id 2,vmem(枚举 3)为 4,smem(枚举 5)为 6,sflag(枚举 6)为 0,而cmem(枚举 4)是硬FATAL,绝不能通过该路径 DMA 寻址。应从 switch arm 读取具体空间的 resource id,而不是从枚举 ordinal 推导;唯一碰巧相同的值是smem→6。
resource-id 表
LLO MemorySpace | 枚举# | Driver resource id |
|---|---|---|
<no memory space> | 0 | 10 |
hbm | 1 | 2 |
hib | 2 | 3 |
vmem | 3 | 4 |
cmem | 4 | — (FATAL) |
smem | 5 | 6 |
sflag | 6 | 0 |
imem | 7 | 5 |
barna_core_bmem | 8 | 7 |
barna_core_smem | 9 | 9 |
barna_core_sflag | 10 | 1 |
barna_core_imem | 11 | 8 |
sparse_core_* (12..16) | 12..16 | — (FATAL) |
怪异点 — resource-id 分配不是
MemorySpace枚举的恒等映射,也不是单调的:sflag→0,barna_core_sflag→1,hbm→2,hib→3,vmem→4,imem→5,smem→6,barna_core_bmem→7,barna_core_imem→8,barna_core_smem→9,NONE→10。重新实现必须使用显式表;从 space 整数推导 resource id 对每一行都是错的。cmem和sparse_core_*case 会在LogMessageFatal陷入;这些空间可由 LLO load/store 寻址,但在这一代的 resource model 中不能作为 DMA 端点,因此指向它们的 DMA 是编译期 fatal,而不是静默漏掉。
4. 描述符字段布局
目的
OciDescriptorCommonIssuedFromTcs 是一条 17 字段、按位打包的记录。LLO DMA-start op 填充的字段,以及逐代 Decode… 函数读回的偏移,在所有代际中都是固定的。
布局
字段偏移已从切出的 DescriptorProto(FDP message body)和 pxc producer store 按字节验证。该结构是按位打包的;这些是解析到 proto 后的成员偏移,不是原始 bit 位置:
| # | 字段 | 偏移 | 宽度 / 枚举 | 填充方 |
|---|---|---|---|---|
| 1 | trace_id_header | +0x18 | u64 | DMA-id producer(配对 key) |
| 2 | dma_type | +0x20 | DmaTypeValues (4) | DMA lowering |
| 3 | src_mem_mem_id | +0x24 | MemMemId (2-bit) | source endpoint render |
| 4 | src_mem_core_id | +0x28 | MemCoreId (3-bit) | source endpoint render |
| 5 | src_opcode | +0x2c | SrcOpcode (2-bit) | source opcode |
| 6 | dst_mem_mem_id | +0x30 | MemMemId (2-bit) | dest endpoint render |
| 7 | dst_mem_core_id | +0x34 | MemCoreId (3-bit) | dest endpoint render |
| 8 | dst_opcode | +0x38 | DstOpcode (2-bit) | GetDstOpcode<> |
| 9 | src_sync_flag_id | +0x3c | u32 | sync-flag binding |
| 10 | src_sync_flag_core_id | +0x40 | SyncFlagCoreId (8) | sync-flag binding |
| 11 | dst_sync_flag_0_id | +0x44 | u32 | completion flag 0 |
| 12 | dst_sync_flag_0_core_id | +0x48 | SyncFlagCoreId (8) | completion flag 0 |
| 13 | dst_sync_flag_1_id | +0x4c | u32 | completion flag 1 |
| 14 | dst_sync_flag_1_core_id | +0x50 | SyncFlagCoreId (8) | completion flag 1 |
| 15 | program_counter | +0x54 | u32 | trace/PC |
| 16 | length | +0x58 | u32 | size operand |
| 17 | length_granule | +0x5c | LengthGranule (1-bit) | size operand |
三个 SyncFlagCoreId 枚举(+0x40、+0x48、+0x50)共享与 MemCoreId 相同的 8 值集合(RESERVED/NONCORE/TC0/TC1/BC0..BC3),sync-flag 目标 core 会镜像 memory-target core。双 dst_sync_flag_{0,1} 对是 V2 ICI 描述符也暴露的双通道 completion(通过 set_dst_sync_flag_mem_offset(idx 0..1));在片内描述符中,布局里同时存在二者。
大小对(length × length_granule)
传输字节数为 length << granule_shift,其中 shift 由 1-bit length_granule 选择:
LengthGranule (+0x5c) | 名称 | shift | 每单位字节数 |
|---|---|---|---|
| 0 | 512B | << 9 | 512 |
| 1 | 4B | << 2 | 4 |
pxc DMA-timeline producer(ConvertTpuTraceToXPlane<pxc> lambda,store block @ 0xf26c865)是 size decode 以及哪些字段保留到渲染 span 中的按字节精确证明:
// producer id-91 store @0xf26c865
span.begin_gtc = begin_gtc; // [r15+0x8]
span.begin_present = 1; // [r15+0x10]
shift = (descr.length_granule == 0) ? 9 : 2; // cmp [r14+0x5c],0 ; mov ecx,2 ; mov eax,9 ; cmove
bytes = descr.length << shift; // eax = [r14+0x58] ; shl rax, cl
span.byte_count = bytes; // [r15+0x28]
span.kind_tag = 3; // [r15+0x40]
// NO read of descr[+0x24 .. +0x50] -> src/dst endpoints + sync flags are NOT copiedLLO op 如何填充它
描述符字段由 LLO Dma*StartOp op 的操作数和属性填充(Tile-Index 展开生成地址操作数;DmaParameters 选择器选择 Simple 与 Strided op 形状):
src_mem_*/dst_mem_*← source / destination 操作数的MemorySpace,通过MemorySpaceToDriverResource渲染(§3)。dst_opcode← op 的字符串dst_opcode属性,经由GetDstOpcode<>(§2);src_opcode默认为READ,除非 memset op 选择INSTRUCTIONMEMSET/DATAMEMSET。length/length_granule← size operand,粒度选择方式要让字节数适配 size 字段(ICI 构建器的WriteSize会强制granule_bytes <= 1024,也就是说 512-B 粒度把单个描述符的 size word 限制在等价 10-bit 字段内)。dst_sync_flag_*← 最后一个字节落地时 DMA bump 的 completion sync flag(片上版本对应 ICI 接收侧 auto-increment)。enable_trace← op 的getEnableTrace属性(DmaSimpleStartOp::getEnableTrace@0x145b9620),它切换描述符是否发出 profiler trace entry。
5. 渲染器保留与丢弃的内容 {#5-what-the-renderer-keeps-vs-drops}
唯一的片内 DMA-timeline pass xprof::tpu::ConvertDmaTransfersToXPlane @ 0xf254bc0 会把一个已配对 DMA 渲染为一个 device XEvent。它是唯一为了显示而读取描述符的 consumer,并且它会把端点解码进 proto,但从不把它们复制到渲染后的 span 中。span 的 begin/duration 是 XEvent 自身的 offset/duration 字段,由 TpuXLineBuilder::AddEvent(event, begin, end−begin) 直接从预解码的 DmaTransfer timespan 写入;它们不是 XStat,也不携带 StatType id。除此之外,该 pass 每个 span 会附加六个 XStat,全部通过 GetStatTypeStr(N)(数值)或字面 stat-metadata 名称(字符串):
| Span 字段 / XStat | StatType | 来源 |
|---|---|---|
| event offset (begin) | — (XEvent field) | AddEvent(begin) — DmaTransfer begin timespan |
| event duration | — (XEvent field) | AddEvent(end−begin) — DmaTransfer end−begin |
bytes_transferred | 78 | DmaTransfer.byte_count(producer 解码的 length << granule_shift) |
queue | 79 | 来自 DmaTransfer 的字符串,pxc 上为空 |
details | (string "details") | 来自 DmaTransfer 的字符串,pxc 上为空 |
_a | 42 | 常量 1(per-DMA aggregate marker) |
flow | 56 | XFlow::next_flow_id_,通过 4·(id & 0xff_ffff_ffff_ffff)+3(begin↔end arrow) |
bandwidth | (string "bandwidth") | FormatPack(unit, bytes/(dur/1e12)),5 档 B/KB/MB/GB/TB 阶梯 |
易错点 —
src_mem_*/dst_mem_*/*_opcode/*_sync_flag_*字段(描述符+0x24..+0x50)会由DecodeOciDescriptorCommonIssuedFromTcs解析,但 producer 交给该 pass 的DmaTransfer中,唯一保留下来的描述符字段是length(+0x58)、length_granule(+0x5c,解码为字节数)以及trace_id_header(+0x18,用于 begin/end 配对)。queue和details字符串 stat 会附加到每个 span,但它们在 pxc producer 上的后备字符串为空,因此捕获到的 pxc trace 会显示为空(当DmaTransfer字符串长度为零时,该 pass 会跳过SetStatValue调用)。nm -C扫描没有在libtpu.so中找到任何MemMemId/MemCoreId → tier或 endpoint→stat 符号化器。因此 §1 / §2 的端点枚举完全可解码,但在该单元中没有显示渲染器;下游 xprof/TensorBoard 符号化器如果存在,就必须重新读取该 pass 丢弃的 proto 字段。
6. DmaType 枚举:两个互不相关的枚举
传输类别在两个地方以 DmaType 之名出现,而且它们的值集合不同;混淆二者是一个陷阱。
runtime / LLO 枚举 xla::jellyfish::DmaType 是从它的 absl 日志 operator(operator<<<DmaType> @ 0x1d5ae080)恢复出来的,是一个密集的 3 值 switch:
xla::jellyfish::DmaType | Value |
|---|---|
DMA_TYPE_CHIP_TO_HOST | 0 |
DMA_TYPE_LOCAL_OR_HOST | 1 |
DMA_TYPE_REMOTE_WRITE_UNICAST | 2 |
profiler 描述符枚举 DmaTypeValues(dma_type @ +0x20)是一个 4 值集合,且顺序不同:
DmaTypeValues (pxc) | Value |
|---|---|
DMA_TYPE_LOCAL | 0 |
DMA_TYPE_CHIP2HOST | 1 |
DMA_TYPE_REMOTEUNICAST | 2 |
DMA_TYPE_REMOTEMULTICAST | 3 |
在 SparseCore gen(vfc/vlc/glc/gfc)上,描述符 DmaTypeValues 收缩为两个值 {LOCALORHOST=0, REMOTEUNICAST=1}。runtime 层还命名了更宽的一组 .rodata 字符串(DMA_TYPE_LOCAL、DMA_TYPE_LOCAL_OR_HOST、DMA_TYPE_CHIP_TO_HOST、DMA_TYPE_REMOTE_UNICAST、DMA_TYPE_REMOTE_WRITE_UNICAST、DMA_TYPE_REMOTE_MULTICAST),由 BuildDmaOverrides(srcMS, dstMS, isRemote, DmaType, …) 选择。
怪异点 —
DMA_TYPE_LOCAL是 profiler 枚举的值0(片内情形),但不是 3 值 runtimexla::jellyfish::DmaTypeoperator 的值(后者从DMA_TYPE_CHIP_TO_HOST=0开始)。两个枚举共享部分拼写片段,但在数量、顺序和值0的含义上都不同。重新实现者必须把它们放在独立命名空间中:LLO/runtimeDmaType驱动BuildDmaOverridesregistry,以选择 control-word override;描述符DmaTypeValues是硬件发出的 wire/profiler 标签。对于本页负责的片内描述符,相关dma_type是 profiler 的DMA_TYPE_LOCAL=0。
交叉引用
- DmaParameters 选择器 — Simple-vs-SingleStrided op-shape 选择器,以及决定哪个 LLO DMA-start op 填充此描述符的 dim-coalescing
- Rolled / Strided / General 发射器 — 在字段填好后发出描述符的传输体发射器
- Tile-Index 展开 —
ExpandTiledMemRefs/expandTiledIndices,生成被渲染进 source/destination 端点的地址操作数 - MemorySpace 枚举 — 17 值 LLO
MemorySpace枚举,其值由MemorySpaceToDriverResource映射到 driver resource id - Memory-Load Slot / Memory-Store Slot — 对 DMA 端点解析的操作数编码
MemorySpace标签的 VLIW slot - Host↔Device DMA —
DeriveHostDmaTransfers/ tag-6/7 host 路径(DMA_TYPE_CHIP_TO_HOST/DMA_TYPE_LOCAL_OR_HOST) - OCI Command DMA-ID — 对描述符的 begin/end trace point 进行配对的
trace_id_header(+0x18)DMA-id - net_router 发射器流水线 — 本地段会发出片内描述符的 collective router;其 counterpart 是跨芯片 remote-endpoint 编码
- Address-Space ID — SparseCore
mlir::sparse_core::MemorySpaceAS-ID 枚举,SC 边界处不相关的 sibling 编号