Payload: jxc Legacy Trace (PerformanceTraceEntry)
本页中的所有地址和偏移均适用于
libtpu-0.0.40-cp314wheel 中的libtpu.so(build-id89edbbe81c5b328a958fe628a9f2207d)。该二进制未 stripped,完整 C++ symbols 存在,且.text/.rodataVMA 等于 file offset。其他版本会有所不同。
摘要
jxc,即 Jellyfish,是最早被 profiling 的 TPU generation,它不使用之后每个家族都会解码的定宽 TraceEntriesCoder packet。它的设备端 trace ring 会由一个不同的 DecodeTraceBuffers 实例解码成自描述 proto2 消息 asic_sw::driver::deepsea::jxc::PerformanceTraceEntry。deepsea gens(pxc/vfc/vlc/glc/gfc)读取固定的 16-byte bit-packed packet:2-bit framing、59-bit TraceHeader、一串 GetBits64 width sequence,以及 per-event consumed-bit CHECK;而 jxc 解析的是普通 proto2 record:timestamp(field 1,GTC cycle stamp)、chip_id(field 2),以及选择 17 个 band sub-messages 之一的 oneof entry_data(fields 3..19)。jxc 上没有 GetBits sequence,也没有 consumed-bit CHECK;wire 就是 proto2 message layout 本身。
把 jxc 与现代路径统一起来的唯一事实是路由 key。deepsea codec 在 decode 时按 8-bit on-wire trace_point_id 分发,在 encode 时按稠密 oneof field 分发。jxc 根本没有 on-wire id byte,因此 TracePoint<jxc>::FromTraceEntry 会通过把 oneof case 放入 high byte、把该 band 的本地 id enum 放入 low byte,合成一个 16-bit key:key = (EntryDataCase << 8) | (id & 0xff)。这就是 tracepoints registry 在 jxc 0x9xx/0xaxx range 中记录的 key。在这个 key 之上,subscriber 层与现代 gens 统一:cross-gen TraceEntryWrapper<jxc> 暴露同样的 CoreId()/MemoryCommand()/GetDmaId()/SyncFlagValue() accessor surface,因此 CoreDispatcher<jxc>::Dispatch 是 deepsea dispatcher 的 byte-for-byte structural twin;只有 wire format 和 key composition 不同。
本页负责 jxc legacy PerformanceTraceEntry wire format(17-band oneof、per-band TracePoint enums 与 payload fields、selector enum value tables、packed-key composition)以及 两个 jxc 独有的 trace subscribers:HbmMuxSubscriber(HBM read/write multiplexer occupancy band,位于自己的 XLine)和 DmaSubscriber(Node-Fabric DMA command/data-end band,通过 synthetic dma_id 配对)。这两个 band 在 newer gens 中被折入其 ICI/intra-DMA payloads,因此在 UHI/OCI/ICI/DMA 或 vfc/vlc/gfc 上没有 analog。与 fixed-16-byte codec 的对比见 TraceEntriesCoder。
对重实现而言,契约是:
- proto2 record,而不是 bit packet —
PerformanceTraceEntry由标准 proto2 runtime 解析;band fields 是 message-layout offsets,而不是GetBits64width sequence。codec 在GetTraceCodec内作为独立的std::variantalternative 被选择。 - synthetic packed routing key
key = (EntryDataCase << 8) | (band.id & 0xff),由FromTraceEntry从 per-bandid-field offset 组合而成;这是现代 dual dispatch 在 jxc 上折叠到一个 16-bit value 的 analog。 - 17 个 bands — 每个 band 的 oneof field number、其
TracePointenum(本地 16-bit id range)、具名 payload fields,以及 selector enum value tables。 - 两个独有 subscribers —
HbmMux(单 key0x728,XLine 56 上的 2-state switch tracker)和Dma(17 个 nf-band keys0x603..0x617,通过以GetDmaId()为 key 的FlatHashMap<dma_id, pending-begin>配对)。
| 解码后的消息 | asic_sw::driver::deepsea::jxc::PerformanceTraceEntry(proto2;自描述,非 bit-packed) |
| Container 布局 | field 1 timestamp(u64,GTC cycle stamp);field 2 chip_id(u32);oneof entry_data fields 3..19(17 个 band sub-messages) |
| Codec 选择 | xprof::tpu::DecodeTrace(DeviceType, JfTrace*) @ 0xf59dba0 → GetTraceCodec @ 0xf5a2900(variant alternative unique_ptr<TraceCodecInterface<…jxc::PerformanceTraceEntry>>) |
| 路由 key | TracePoint<jxc>::FromTraceEntry @ 0xf1bace0 — key = (EntryDataCase << 8) | (id & 0xff) |
| Dispatcher | CoreDispatcher<jxc>::Dispatch @ 0xf1dcee0 — FlatHashMap<u16 packed-key, vector<subscriber>>,SwissTable probe,fan-out call *0x10(vtable) |
| Name lookup | JxcTracePointName(EntryDataCase, u16) @ 0xf69d800(per-band NameOfDenseEnum;default "Unknown" @ 0x85dd1fd) |
| Subscriber setup | jxc ConvertTpuTraceToXPlaneV2<jxc::PerformanceTraceEntry> lambda @ 0xf1da7c0 — 10 个 RegisterSubscriber sites |
| 独有 subscribers | HbmMuxSubscriber<jxc> @ 0xf1def00(vtable 0x21643ce0);DmaSubscriber<jxc> @ 0xf1dfee0(vtable 0x21643dc0) |
jxc 为何分叉 — Proto2 对 16-Byte Packet
这个跨 gen 分裂是基础性的,并在 codec-selection 时决定。xprof::tpu::DecodeTrace(DeviceType, JfTrace*) @ 0xf59dba0 调用 GetTraceCodec @ 0xf5a2900(device generation 从 *(int*)(a2 + 260) 读取),后者返回一个 std::variant,其 alternatives 为:
variant<
monostate,
unique_ptr<TraceCodecInterface<gxc::glc::profiler::TraceEntry>>, // glc
unique_ptr<TraceCodecInterface<gxc::gfc::profiler::TraceEntry>>, // gfc
unique_ptr<TraceCodecInterface<vxc::vlc::profiler::TraceEntry>>, // vlc
unique_ptr<TraceCodecInterface<vxc::vfc::profiler::TraceEntry>>, // vfc
unique_ptr<TraceCodecInterface<pxc::profiler::TraceEntry>>, // pxc
unique_ptr<TraceCodecInterface<jxc::PerformanceTraceEntry>> // jxc — DISTINCT TYPE
>随后 decode 对该 variant 执行 __visit。五个 deepsea alternatives 都是 TraceEntry codecs,即 16-byte fixed-width packet。jxc alternative 则是完全不同的 proto type:PerformanceTraceEntry,由标准 proto2 runtime 解析。DecodeTrace decompile 中已 byte-confirmed:codec 通过一个 __variant_detail::__visitation __fmatrix 分发,最后一个 alternative 命名为 jxc::PerformanceTraceEntry。jxc decode path 中没有任何 GetBits64/SkipBits 调用。
对重实现者的直接后果是:
QUIRK — jxc trace 是自定界 proto2,因此没有固定字段宽度,也没有 per-event total-bit
CHECK。试图用现代 codec 的 framing(2-bitvalid/started、59-bit header、GetBits64width sequence)驱动 jxc 的重实现会误解析每条 record。jxc 没有 framing bits,没有TraceHeadersub-record,也没有TraceIdHeader;GTC timestamp 是 proto field 1,chip_id是 field 2,band 是 active oneof member。proto wire-tag layout 就是格式。
Container 与 band offsets
解码后的 PerformanceTraceEntry 对象暴露两个路由 key 会读取的 offsets。oneof discriminator(EntryDataCase)位于 entry + 0x30,active oneof member pointer 位于 entry + 0x28(proto2 把 case 存为 int,把 variant member 存为 pointer)。两者在 FromTraceEntry 中得到确认(*(int*)(a1 + 48) 读取 case;*(_QWORD*)(a1 + 40) 解引用 member)。Fields 1/2(timestamp、chip_id)是 scalar,不属于 oneof,因此它们从不用来索引 band。
| 字段 | Offset | 类型 | 含义 |
|---|---|---|---|
EntryDataCase | +0x30 | int (oneof case) | 17 个 bands 中哪一个处于 active 状态(3..19);0 = DATA_NOT_SET |
| active oneof member | +0x28 | ptr | band sub-message;其 id field 在 per-band offset 处读取 |
timestamp (field 1) | proto-layout | u64 | GTC cycle stamp(→ GtcSpanConverter,cycle→ps downstream) |
chip_id (field 2) | proto-layout | u32 | chip identifier |
Packed Routing Key
jxc 没有 on-wire trace_point_id byte;band 的身份在 proto oneof case 中,event 的身份在 band sub-message 自己的 id enum 中。TracePoint<jxc>::FromTraceEntry @ 0xf1bace0 把两者折叠为一个 16-bit dispatch key:
// TracePoint<jxc>::FromTraceEntry @0xf1bace0 — packed-key composer
function FromTraceEntry(entry):
case = *(int*)(entry + 0x30); // EntryDataCase (oneof discriminator)
switch (case):
case 0: id = case; // DATA_NOT_SET — degenerate
case 1, 2: __builtin_trap(); // timestamp/chip_id are scalar, never keyed
case 3, 8: id = member->[+0x18]; // nf_descriptor / ici_packet
case 4, 6, 10, 12, 15, 16: id = member->[+0x30]; // nf_control / nf / cs_internal / brn_sync_wait / bcs_internal / hib_request
case 5: id = member->[+0x34]; // nf_ici
case 7: id = member->[+0x20]; // hbm_mux_switch
case 9, 18: id = member->[+0x40]; // cs_external_sync / hib_sync_update
case 11: id = member->[+0x24]; // brn_fabric_sync
case 13, 14, 19: id = member->[+0x38]; // brn_perf1 / brn_perf2 / hib_hbm_write
case 17: id = member->[+0x4c]; // hib_interrupt
return ((u16)case << 8) | (u8)id; // <- the packed key最终组合是 byte-exact:((unsigned __int16)case << 8) | (unsigned __int8)id。per-case id-field offset 是该 band 第一个字段在其 sub-message 内的 proto2 layout offset,通过 +0x28 member pointer 读取。
GOTCHA —
id-field offset 不是跨 band 恒定的;它根据每个 band 的 proto2 message 中有多少 fixed-layout fields 位于id前面,在+0x18到+0x4c之间变化。在单一硬编码 offset 读取 band id 的重实现,会给除恰好共享该 offset 的 bands 外的所有 bands 建错 key。应像FromTraceEntry一样由 oneof case 驱动 offset。(Cases 1 和 2 会 trap;它们是 scalartimestamp/chip_id,从不是 active oneof member。)
这个 packed key 直接解码 tracepoints registry 为 jxc 报告的 namespace。已 byte-confirmed 的 worked examples:
| Packed key | = (case << 8) | id | band | event |
|---|---|---|---|
0x728 | (7<<8)|0x28 | case 7 hbm_mux_switch | id 40 EVENT |
0x603..0x617 | (6<<8)|low | case 6 nf | 17 个 DMA command/data-end ids(见 DMA band) |
0x93c | (9<<8)|0x3c | case 9 cs_external_sync_flag_update | id 60 DMA_DONE |
0xa3d | (10<<8)|0x3d | case 10 cs_internal | id 61 SET_SYNC_FLAG |
0xa40 | (10<<8)|0x40 | case 10 cs_internal | id 64 SET_TRACEMARK |
0xa41 | (10<<8)|0x41 | case 10 cs_internal | id 65 TRACE_INSTRUCTION |
0xa45/0xa46 | (10<<8)|0x45/0x46 | case 10 cs_internal | ids 69/70 SCALAR_FENCE_{START,END} |
Dispatch
CoreDispatcher<jxc>::Dispatch @ 0xf1dcee0 是 deepsea dispatcher 的结构孪生。它调用 FromTraceEntry 获得 u16 key,然后探测 FlatHashMap<u16 packed-key, vector<shared_ptr<TraceEventSubscriber>>>,并把 entry 分发给每个已注册 subscriber:
// CoreDispatcher<jxc>::Dispatch @0xf1dcee0
function Dispatch(self, entry_wrapper):
lock(self);
key = FromTraceEntry(entry_wrapper->[+0x10], entry_wrapper); // u16 packed key
// SwissTable probe of FlatHashMap<u16, vector<subscriber>>:
h = crc32(seed, key); // _mm_crc32_u64
grp = vpshufb(h7); // 16-lane control byte broadcast
for (slot in groups):
if (vpcmpeqb(grp, ctrl) match && *(u16*)slot == key) // cmp word, (slot)
break;
for (sub in bucket.vector): // fan-out
sub->vtable[0x10](sub, entry_wrapper); // call *0x10(vtable) = ProcessTraceEntryhash 是带 vpcmpeqb group scan 和 cmp %ax,(slot) final compare 的 16-bit key 上的 crc32,与现代 CoreDispatcher<TraceEntry> 使用的同一套 absl SwissTable probe 相同。唯一的 jxc-specific 部分是 FromTraceEntry;key 之上的所有内容都是 gen-independent。
17 个 Bands
oneof entry_data 持有 17 个 band sub-messages,即 oneof fields 3..19。每个 band 中某个 event 的 packed routing key 是 (field << 8) | (band.id & 0xff)。JxcTracePointName(EntryDataCase, u16) @ 0xf69d800 通过 per-band NameOfDenseEnum<descriptor, Lo, Hi> table(Lo/Hi = 该 band 的本地 id range)把 key 解析成 name;越界 id 解析为 "Unknown",len 7,@ 0x85dd1fd。与其 dump 每个字段,下表给出每个 band 的 oneof field、本地 id range、key range 和角色;后面的字段列表描述 subscriber 实际读取的 bands。
| Case | Band sub-message | Local ids | Key range | 角色 |
|---|---|---|---|---|
| 3 | nf_descriptor | 0..2 | 0x300..0x302 | Node-Fabric descriptor — OCI-descriptor analog(完整 src/dst + 3 个 sync-flag-update channels) |
| 4 | nf_control_message | 28..29 | 0x31c..0x31d | Node-Fabric control message |
| 5 | nf_ici | 24..26 | 0x518..0x51a | Node-Fabric ICI receive/send framing |
| 6 | nf | 3..27 | 0x603..0x61b | Node-Fabric DMA band — DmaSubscriber source |
| 7 | hbm_mux_switch | 40 | 0x728 | HBM read/write multiplexer switch — HbmMuxSubscriber source |
| 8 | ici_packet | 0..7 | 0x800..0x807 | Node-Fabric router flit band(jxc analog of deepsea ICI link) |
| 9 | cs_external_sync_flag_update | 60 | 0x93c | TC cross-chip sync set-done(DMA_DONE)— SyncSubscriber |
| 10 | cs_internal | 61..70 | 0xa3d..0xa46 | TC sequencer internal sync/trace band — Sync/Step/Hlo/Overlay/ScalarFence |
| 11 | brn_fabric_sync | 112 | 0xb70 | BarnaCore fabric sync |
| 12 | brn_sync_wait | 113 | 0xc71 | BarnaCore sync wait |
| 13 | brn_perf1 | 109..111 | 0xd6d..0xd6f | BarnaCore FSM perf group 1 |
| 14 | brn_perf2 | 100..108, 114..121 | 0xe64..0xe79 | BarnaCore FSM 16-channel controllers |
| 15 | bcs_internal | 122..127 | 0xf7a..0xf7f | BarnaCore sequencer internal |
| 16 | hib_request | 80..83 | 0x1050..0x1053 | Host Interface Block DMA request — UHI/HDE analog |
| 17 | hib_interrupt | 84..85 | 0x1154..0x1155 | HIB interrupt(queue-occupancy snapshot) |
| 18 | hib_sync_update | 86 | 0x1256 | HIB sync-flag update |
| 19 | hib_hbm_write | 87 | 0x1357 | HIB→HBM write |
NOTE —
brn_perf2enum rangeLo..Hi = 100..121与brn_perf1/brn_fabric_sync/brn_sync_waitid values 重叠,但EntryDataCase会消歧:case 14 永远是 16-channel-controller band,与 raw id 无关。BarnaCore bands 中仅 id 是有歧义的;只有 packed key(case + id)唯一。这正是 routing key 把 case 打包进 high byte 的原因。
Subscribers 读取的 bands
cs_internal band(case 10)最繁忙,会按 id fan 到五个不同 subscribers:
case 10 cs_internal (ids 61..70) fields: id, tensor_node, data_field,
sync_flag_number, program_counter,
sfence_end, sfence_start
61 SET_SYNC_FLAG ┐
62 ADD_SYNC_FLAG │
66 UNSUCCESSFUL_SYNC_ATTEMPT├─ SyncSubscriber (in-body mask 0xe3 over id-base 61)
67 SUCCESSFUL_SYNC_ATTEMPT │
68 READ_SYNC_FLAG ┘
64 SET_TRACEMARK ── TensorCoreStep (key 0xa40 → StepTracker)
65 TRACE_INSTRUCTION ── Hlo+Overlay+OnDevTraceMe+LloOp (key 0xa41, 4-way fan-out)
69 SCALAR_FENCE_START ┐
70 SCALAR_FENCE_END ┴─ ScalarFence (keys 0xa45/0xa46)
63 HOST_INTERRUPT · 65 (also) covered abovenf band(case 6)是 DmaSubscriber 消费的 DMA-started/completed band:通过 Node Fabric 的每次 transfer 都会按 memory engine 发出一个 *_COMMAND/RECEIVE begin 和一个 *_DATA_END completion。其字段是 id, tensor_node, trace_id, descriptor_source, node_id, chip_id, first, last。hbm_mux_switch band(case 7)只携带 id, tensor_node, fsm;fsm 是 HbmMuxSubscriber 跟踪的 2-state mux-switch direction。
Selector enum value tables
若干 band 字段是 enum,其 value tables 从 descriptor pool byte-exact 得到:
descriptor_source_value: 0=TENSOR_CORE 1=BARNA_CORE 2=HIB 3=HIB_HBM_QUEUE
nf_ici.vc_value: 0=CONTROL 1=DATA
ici_packet.router_port_id_value: 0..3=EXTERNAL_PORT_0..3 4=NODE_FABRIC_0 5=NODE_FABRIC_1
hib_sync_update.sf_rsrc_value: 0=TENSOR_CORE 1=BARNA_CORE
hib_hbm_write.queue_type_value: 0=TC_INFEED 1=BC_INFEED 2=HBM_WRITE
hib_request.requester_tag_value: 0=TC_INFQ 1=TC_OFQ 2=BC_INFQ 3=BC_OFQ 4=HBM_WRQ
5=BC_FSMQ 6=NF_DESCRQ 7=CHIP_DEBUGQ 8=NF_OFQ
hib_request.requester_id_value: 0=TC_OF 1=BC_OF 2=NF_OF 3=CHIP_DEBUG 4=STATUS_BLOCK_WRITE
5=TC_INF 6=BC_INF 7=HBM_WR 8=BC_FSM 9=QUEUE_FETCH 10=PAGE_TABLE_REQNOTE —
hib_request.virt_addr(u64)与hib_hbm_write.virt_addr(u64)的拆分,以及每个 sub-message 字段的确切 proto2 wire-tag offset,都是标准 proto2 message layout,而不是手写 bit-codec;因此它们从 descriptor 恢复,而不是从GetBitswidth sequence 恢复。(这两个 u64 的确切 in-RAM offset 为 LOW confidence;字段的存在与类型由 descriptor pool 确认,CERTAIN。)
十个 jxc Subscribers
jxc ConvertTpuTraceToXPlaneV2<jxc::PerformanceTraceEntry> setup lambda @ 0xf1da7c0 精确发起 10 次 RegisterSubscriber 调用(由 E8-rel32 caller scan 确认)。其中八个复用 deepsea begin/end-pairing trackers;两个,即 HbmMux 和 Dma,是 jxc 独有的。
| # | Subscriber (vtable) | Packed key(s) | jellyfish event(s) | 备注 |
|---|---|---|---|---|
| 1 | HbmMux (0x21643ce0, threaded) | {0x728} | hbm_mux_switch EVENT(40) | XLine 56 "HBM Mux";2-state fsm tracker |
| 2 | Dma (0x21643dc0, threaded) | {0x603..0x617} (17) | nf DMA cmd/data-end | dma_id pairing(FlatHashMap);XStat 0x38 |
| 3 | Sync (0x21643e88, threaded) | {0x93c,0xa3d,0xa3e,0xa42,0xa43,0xa44} | cs_external DMA_DONE + cs_internal sync set | in-body mask 0xe3 over id-base 61 |
| 4 | ScalarFence (0x21643ed8, threaded) | {0xa45,0xa46} | cs_internal SCALAR_FENCE_{START,END} | XLine 9 (Scalar Unit) |
| 5 | TensorCoreStep (0x21643f28) | {0xa40} | cs_internal SET_TRACEMARK(64) | → StepTracker (TraceMark id) |
| 6 | TensorCoreHlo (ctor 0xf1e27c0) | {0xa41} | cs_internal TRACE_INSTRUCTION(65) | XLA Ops line |
| 7 | TensorCoreOverlay (0x21644178) | {0xa41} | cs_internal TRACE_INSTRUCTION(65) | → OverlayTracker |
| 8 | TensorCoreOnDeviceTraceMe (0x216441c8) | {0xa41} | cs_internal TRACE_INSTRUCTION(65) | XLA TraceMe |
| 9 | LloOpEvent (0x21644218, threaded) | {0xa41} | cs_internal TRACE_INSTRUCTION(65) | Tensor Core line |
| 10 | ScalarFence (0x21643ed8, threaded) | {0xa45,0xa46} | cs_internal SCALAR_FENCE_{START,END} | XLine 62 (Barna Core Fence) |
QUIRK — key
0xa41(TRACE_INSTRUCTION)是一个 4-way fan-out 点:Hlo、Overlay、OnDeviceTraceMe和LloOp都注册到同一个 packed key,并共享 setup lambda 中的一个TracePointsbuffer。这精确镜像 deepsea id-85 4-way fan-out;dispatcher 会把一个 entry 交付给全部四个 subscribers,每个 subscriber 再把它投影到不同 XPlane line。假设每个 key 只有一个 subscriber 的重实现会丢掉四个 TRACE_INSTRUCTION consumers 中的三个。
Step/Overlay/Sync trackers 复用 deepsea begin/end-pairing model:StepTracker 以 TraceMark id 为 key,OverlayTracker 以 overlay operand 为 key,SyncTracker 以 sync_flag_number 为 key。两个 jxc 独有 trackers,即基于 dma_id 的 DmaSubscriber 和基于 fsm direction 的 HbmMux,详见下文。
DMA Subscriber — Node-Fabric DMA Band {#the-dma-subscriber-the-node-fabric-dma-band}
DmaSubscriber<jxc>(vtable 0x21643dc0)是第二个注册的 subscriber。它和 HbmMux 都被包在一个 0x240 字节的 ThreadedSubscriber 中(ThreadLoop @ 0xf1ddd60,+0xa0 处为 ClosureThread worker),因此二者都应视为 threaded。其内部对象在 +0x18 持有一个 XStat StatMetadata(StatType 0x38)。它消费 nf band(case 6),也就是 newer gens 折入 ICI/intra-DMA payloads 的 jxc DMA band。
注册的 keys — 17 个 nf DMA bands
lambda 通过遍历 .rodata table @ 0xab53940 中的 17 个 dword entries 构建 Dma TracePoints buffer:每次读取 low byte(一个 nf TracePoint id)并 OR 0x600(case 6 位于 high byte),得到 17 个 packed keys:
key nf id event key nf id event
0x603 3 HBM_READ_COMMAND 0x60a 10 VMEM_ICI_WRITE_COMMAND
0x604 4 HBM_WRITE_COMMAND 0x60b 11 VMEM_ICI_WRITE_DATA_END
0x605 5 HBM_WRITE_DATA_END 0x60c 12 SMEM_READ_COMMAND
0x606 6 VMEM_HBM_READ_COMMAND 0x60d 13 SMEM_WRITE_COMMAND
0x607 7 VMEM_HBM_WRITE_COMMAND 0x60e 14 SMEM_WRITE_DATA_END
0x608 8 VMEM_HBM_WRITE_DATA_END 0x60f 15 IMEM_WRITE_COMMAND
0x609 9 VMEM_ICI_READ_COMMAND 0x610 16 IMEM_WRITE_DATA_END
0x614 20 HIB_WRITE_RECEIVE 0x616 22 HIB_WRITE_COMMAND
0x617 23 HIB_WRITE_DATA_ENDNOTE —
nfids 17/18/19(BMEM)和 27(ICI_SEND_END)存在于nfband 中,但未被Dmasubscriber 注册;只有六类 memory-engine command/data-end families(HBM、VMEM-HBM、VMEM-ICI、SMEM、IMEM、HIB)会被配对。注册整个 band 6 的重实现会拾取 subscriber 从不配对的 BMEM 和 ICI-send events。
Match key — dma_id pairing
DmaSubscriber<jxc>::ProcessTraceEntry @ 0xf1dfee0 是一个以 synthetic dma_id 为 key 的 begin/end pairer:
// DmaSubscriber<jxc>::ProcessTraceEntry @0xf1dfee0
function ProcessTraceEntry(self, entry):
if (!CoreId_matches(self, entry)) return; // chip/core filter (+0x08/+0x0c)
if (!(MemoryCommand(entry) || MemoryDataEnd(entry))) return; // gate: begin or end only
if (entry.EntryDataCase != 6) return; // confirm nf band (member+0x30 == 6)
switch (nf.id - 3): // 0..0x14 → per-engine XStat selector
// picks a TypeInfo label (typeinfo @0x21643e20/e30),
// a kind (4=command, 5=data-end), a StatType (0x12/0x13/0x14/0x34/0x39)
dma_id = GetDmaId(entry); // @0xf698180 — composite pairing key
bucket = pending.find_or_prepare_insert_large(dma_id); // FlatHashMap<dma_id, vector<begin>>
if (MemoryCommand(entry) && First(entry)): // @0xf698620
bucket.vector = { entry }; // open a pending begin
else if (MemoryDataEnd(entry)):
emit_duration_span(bucket.vector[0], entry); // pair, emit, clear the slotgate 和 EntryDataCase == 6 confirm 均为 byte-exact(MemoryCommand() || MemoryDataEnd(),然后 *(int*)(member + 0x30) == 6)。pairing store 是一个 FlatHashMap<unsigned long, vector<shared_ptr<TraceEntryWrapper>>>,通过 find_or_prepare_insert_large<unsigned long> @ 0xf1e05e0 到达。带 First() 的 *_COMMAND/RECEIVE 会在 dma_id 下打开一个 begin;匹配的 *_DATA_END 发出 duration span 并清除 slot。读/写显示名由 0xf1e0152 处的 "Writ" magic compare 选择。
GetDmaId — composite key
GetDmaId @ 0xf698180 是 synthetic-key composer。它基于 nf oneof case switch,并把 nf sub-message 的 per-direction fields 折叠到一个 unsigned long 中,使 command 和其 data-end 生成相同 key(并让不同 concurrent DMAs 有差异)。HBM/VMEM-HBM/ICI-packet arms 已 byte-confirmed:
// GetDmaId @0xf698180 — composite-key composition (HBM/VMEM-HBM arm)
key = (trace_id & 0x1f00) // bits 8..12 of trace_id
| ((resource & 3) << 13) // 2-bit src/dst resource
| ((node_id & 1) << 15) // node bit
| ((chip_id << 16) & 0x7ff0000) // 11-bit chip
| (id & 0xff); // low byte = the nf id
// simple arms (VMEM-ICI / SMEM / IMEM / BMEM / HIB): key = 0 (degenerate — no composite, low byte never set)GOTCHA — simple-engine arms(switch 中的
case 7,9,0xA..0x11)会落到LABEL_12并返回0;这些 case 从不赋值 composite fields(v3保持0,low byte 也保持0),因此没有 rich command/data-end identity 的 engine families 会折叠到单一 degenerate key。只有 composite arms(case 3nf_descriptor、case 4/6nf_control/nf、case 5nf_ici、case 8ici_packet,以及两个 HIB armscase 0x12/0x13)会构建 full key。该值是确定性的,且能按 engine 正确配对,但每个 arm 的确切 LSB bit layout 是 CONFIRMED-PARTIAL:每个方向的字段选择是从 arm table @0xab88674byte-read 得到,composite family 的 OR/shift composition 已读取,但未完整列出 per-arm bit map。重实现者必须复现逐 arm 的字段选择,而不是使用单一全局公式。
per-engine XStat assignment(哪个 engine/direction 落到 StatType 0x12/0x13/0x14/0x34/0x39)以及 read-vs-write XEvent display-name table("Writ" branch)尚未完整制表(整数→XStat-name 映射为 LOW confidence;机制为 CERTAIN)。
HBM-Mux Subscriber — HBM Multiplexer Band
HbmMuxSubscriber<jxc>(vtable 0x21643ce0)是第一个注册的 subscriber;它被 ThreadedSubscriber 包装(0x240 bytes)。它是 jxc 独有的:HBM read/write multiplexer occupancy band 在 deepsea gens 上没有 analog(它们把这类信息折入 intra-DMA/HBM bands)。构造时它预先创建两个 XEventMetadata,用于两个 switch directions:
+0x18 = "BFIFO to Node Fabric" (rodata @0x8732bba, len 20)
+0x20 = "Node Fabric to BFIFO" (rodata @0x929bc3b, len 20)注册 key 与 2-state tracker
它注册单个 packed key 0x728(由 movw $0x728,(buf) @ 0xf1db361 构建):0x728 = (7<<8)|0x28 = case 7 (hbm_mux_switch) id 40 = EVENT。HbmMuxSubscriber<jxc>::ProcessTraceEntry @ 0xf1def00 是一个四符号 open/close FSM:{1,2} 打开一个方向,{0,3} 关闭它:
// HbmMuxSubscriber<jxc>::ProcessTraceEntry @0xf1def00 (byte-confirmed)
function ProcessTraceEntry(self, entry):
if (!CoreId_matches(self, entry)) return; // +0x08
state = HbmMuxSwitchState(entry); // @0xf6986e0
// HbmMuxSwitchState: if EntryDataCase==7 -> return (fsm | 0x100000000); else 0
if ((state >> 32) == 0) return; // not an hbm_mux_switch entry
fsm = state & 0xffffffff;
if ((fsm - 1) < 2): // fsm in {1,2} — OPEN, no emit
self[+0x28] = entry; self[+0x30] = entry.rc; // stash prev entry + refcount
self[+0x38] = fsm; // open_dir (1 or 2)
return
if (fsm == 3): // CLOSE what fsm==1 opened
if (self[+0x38] != 1) { clear(); return; }
start = self[+0x28].gtc - (DurationCycles(prev) << 4);
AddEvent(GetOrCreateLine(56), start, entry.gtc - start, self[+0x20]); // "Node Fabric to BFIFO"
clear(); // zero +0x28/+0x30/+0x38
else if (fsm == 0): // CLOSE what fsm==2 opened
if (self[+0x38] != 2) { clear(); return; }
start = self[+0x28].gtc - (DurationCycles(prev) << 4);
AddEvent(GetOrCreateLine(56), start, entry.gtc - start, self[+0x18]); // "BFIFO to Node Fabric"
clear();HbmMuxSwitchState @ 0xf6986e0 已 byte-confirmed:它检查 EntryDataCase == 7,在 member + 0x1c 读取 fsm field,并返回 fsm | 0x100000000(bit-32 = present marker,低 32 bits = state);否则返回 0。
HBM-mux event payload 是 {fsm switch-symbol, tensor_node};四个 fsm 符号形成两组 open/close pair(1→3 和 2→0),因此一个 span 就是 mux 指向某方向所持续的区间。Spans 落在 XLine TpuComponent 56 = "HBM Mux"(name @ 0x84c06ed)上。
NOTE — FSM 是四符号 open/close,不是 two-state toggle:
fsm 1 = open(BFIFO→NF)与fsm 3 = close配对(发出"Node Fabric to BFIFO",meta+0x20);fsm 2 = open(NF→BFIFO)与fsm 0 = close配对(发出"BFIFO to Node Fabric",meta+0x18)。State 3 是fsm==1方向的 close marker,而不是第三种 mux mode。decompiled0xf1def00body 中已 byte-confirmed(if ((fsm-1) >= 2)是 close branch;open branch stasha2并设置*(this+56)=fsm)。完整 open/close pairing 由 jxc DMA / HbmMux / brn_perf 负责。
相关 Struct 与 Table Offsets
| Symbol | Address / offset | 角色 |
|---|---|---|
PerformanceTraceEntry (proto2) | +0x30 EntryDataCase; +0x28 active oneof member ptr; field 1 timestamp (GTC); field 2 chip_id | 解码后的 jxc message |
TracePoint<jxc>::FromTraceEntry | 0xf1bace0 | key = (case<<8)|(member->[per-case off] & 0xff) |
CoreDispatcher<jxc>::Dispatch | 0xf1dcee0 | FlatHashMap<u16, vector<subscriber>>, crc32/vpcmpeqb probe, call *0x10 |
JxcTracePointName | 0xf69d800 | key → name(per-band NameOfDenseEnum;default "Unknown" @ 0x85dd1fd) |
DecodeTrace(DeviceType, JfTrace*) | 0xf59dba0 | 通过 GetTraceCodec @ 0xf5a2900 选择 codec;proto path,无 GetBits |
| setup lambda | 0xf1da7c0 | 10 个 RegisterSubscriber sites;RegisterSubscriber @ 0xf1dca40 |
HbmMuxSubscriber<jxc> | vtable 0x21643ce0; ProcessTraceEntry 0xf1def00 | +0x18/+0x20 direction XEvents;+0x28 start gtc;+0x38 current dir |
HbmMuxSwitchState | 0xf6986e0 | fsm @ member+0x1c;返回 fsm | 0x100000000 |
DmaSubscriber<jxc> | vtable 0x21643dc0; ProcessTraceEntry 0xf1dfee0 | +0x18 XStat(StatType 0x38);+0x20 FlatHashMap<dma_id, vector<begin>> |
GetDmaId | 0xf698180(arm jt 0xab88674) | composite pairing key;HBM/VMEM-HBM arms 完整,simple arms id & 0xff |
nf key table | 0xab53940 | 17 dwords(low byte = nf id,OR 0x600) |
ThreadedSubscriber<jxc> | 0x240 B;+0x20 inner vtable;+0x38 inner ptr;+0xa0 worker | 包装 HbmMux 和 Dma |
相关组件
| 组件 | 关系 |
|---|---|
| TraceEntriesCoder | jxc 不使用的现代 fixed-16-byte codec;jxc 是同一 GetTraceCodec selector 中独立的 PerformanceTraceEntry proto2 variant |
| TracePoints Master Registry | 记录本页解码为 (case<<8)|id 的 jxc 0x9xx/0xaxx packed keys |
| Payload: UHI/OCI/ICI/DMA | 现代 bands;jxc nf DMA band 和 hib_request band 是 newer gens 折入 ICI/intra-DMA 的 legacy analogs |
| Payload: vfc/vlc/gfc | newer-family payload deltas;没有任何一个携带 jxc 独有的 HBM-mux band |
| Profiling and Telemetry Overview | capture→decode→xplane 流水线;本 legacy decode 是其中 jxc-specific 阶段 |
交叉引用
- TraceEntriesCoder — 现代 fixed-width codec;jxc 改用 legacy proto2
PerformanceTraceEntrypath,在GetTraceCodec中作为单独std::variantalternative 被选择 - TracePoints Master Registry — wire-id namespace;jxc ids 是本页解码的 packed
(EntryDataCase<<8)|idkeys - Payload: UHI/OCI/ICI/DMA — 现代 interconnect/DMA bands;可与 jxc 独有的
nfDMA band 和 HBM-mux band 对照 - Payload: vfc/vlc/gfc — newer-family payload maps;jxc HBM-mux band 在其中没有后继
- Profiling and Telemetry Overview — 该 legacy-gen decode 所在的 device-trace pipeline