Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Codename Cheat-Sheet

All addresses on this page apply to libtpu.so from the libtpu-0.0.40-cp314 wheel (build-id 89edbbe81c5b328a958fe628a9f2207d — the unambiguous anchor; the runtime-reported 0.103 is not statically verifiable in the binary). The binary is not stripped — every symbol is a demangled C++ name; .text, .rodata, and .lrodata map VMA == file offset. Other builds will differ.

Abstract

A single TPU generation wears at least seven different names inside libtpu.so, and they live on three independent integer axes that do not share a numbering. A reader chasing one fact — "which chip is gfc?", "what does DeviceType 12 mean?", "is TpuVersion 4 Trillium or v7x?" — keeps hitting a different axis than the one they hold, and the off-by-ones between those axes are exactly where prior analysis went wrong. This page is the one card to come back to: it pins every name of every generation to the binary site that defines it, side by side, so the rest of the wiki can point here instead of re-deriving the mapping.

The three axes are the internal tpu::TpuVersion enum (a dense 0..5, the compiler's notion of "which silicon", defined by TpuVersionToString @ 0x20b3a480); the profiler's xprof::DeviceType enum (a sparse 1..13, the trace pipeline's notion of "which device", defined by DeviceTypeFromDeviceIdentifiers @ 0xf6993a0 and DeviceTypeString @ 0xf69c7c0); and the protobuf TpuVersionProto (a 1..6 wire enum, internal = proto − 1, TpuVersionFromProto @ 0x20b3a8c0). Orthogonal to all three are the codec/ISA codenames (jxc, pxc/plc, vfc/vlc, glc, gfc), the fish marketing codenames (Jellyfish … Trillium), the PCI device-ids, and the public Cloud-API strings (v2tpu7x). Every binary-anchored cell below carries its evidence address; where a name is not in the binary (Trillium, Ironwood, "Ghostfish"), the page says so rather than inventing it.

For navigation, the contract is:

  • The master table binds every axis for every generation in one row, each cell carrying its own confidence — the canonical lookup the rest of the wiki links to.
  • The two-axes warning explains why TpuVersion and DeviceType disagree numerically, so a reimplementer never indexes one table with the other's ordinal.
  • The gotchas collect the traps: the two off-by-one SparseCore sequencer enums, the nested codec namespaces (pxc::plc, vxc::vlc, gxc::gfc), and the v7x 6acc60406/gfc shipping SparseCore SCS+TEC but not TAC.
Internal enumtpu::TpuVersion 0..5TpuVersionToString @ 0x20b3a480, table off_22011BF0 (6 ptrs)
Profiler enumxprof::DeviceType 1..13 (sparse) — DeviceTypeFromDeviceIdentifiers @ 0xf6993a0, names off_21772F00
Proto enumTpuVersionProto 1..6TpuVersionFromProto @ 0x20b3a8c0 (internal = proto − 1)
Codec factorytpu::TpuCodec::Create(TpuVersion) @ 0x1e835fa0 (6-case switch, order = TpuVersion)
Trace codecxprof::tpu::GetTraceCodec @ 0xf5a2900 (keyed on PCI identity, not on either ordinal)
PCI vendor0x1ae0 (Google) for every TPU device

The Master Cheat-Sheet

One row per generation, in TpuVersion order. Read left-to-right to translate any one name into all the others. The Confidence column applies to the whole row's binary-anchored cells; the marketing column is called out separately because it is the one column not sourced from the binary.

Codec codenameFish codenameTpuVersion (internal)DeviceType (profiler)Marketing displayPCI chip DIDHAL family
jxc (jellyfish)Jellyfish03TPU v20x004eTpuHalJxc
jxc (dragonfish)Dragonfish15TPU v30x004fTpuHalJxc
pxc / pfcPufferfish27TPU v4 (v4 lite)0x0050/51/52TpuHalPxc
pxc / plcPuffylite(no own TpuVersion)8(v4-class lite)(chip-parts variant)TpuHalPxc
vxc / vfcViperfish310TPU v5 (v5 lite)0x00ac/0x00adTpuHalVxc
vxc / vlcViperlite(folds into v3)11(v5-class lite)0x00ae/0x00afTpuHalVxc
gxc / glcGhostlite413TPU v6 lite0x00d1TpuHalVxc
gxc / gfc(none — 6acc60406)512TPU7x0x00f2TpuHalVxc

NOTE — the TpuVersion→codename binding is the single most-anchored fact in the binary. TpuVersionToString (0x20b3a480) indexes the 6-pointer .data.rel.ro table at off_22011BF0, whose R_X86_64_RELATIVE relocations target the literals jellyfish (0x863f064), dragonfish (0x863f392), pufferfish (0x863f1c4), viperfish (0x863f172), ghostlite (0x86864e0), 6acc60406 (0x863f0cf). This compiled array is the root every other axis hangs off.

The marketing / Cloud-API column (separate confidence)

The fish and codec codenames are internal names baked into symbols and .rodata. The customer-facing Cloud-TPU names are a parallel string set reached through TpuVersionToExternalName (0x20b3a500) and the AcceleratorType… parser (0x204cf620 / 0x20b3a740). The public product codenames are layered on externally and are not all in the binary:

TpuVersionFishTpuVersionToExternalName stringCloud-API string(s)Public marketingMarketing confidence
0JellyfishTPU v2v2TPU v2HIGH (string in binary)
1DragonfishTPU v3v3TPU v3HIGH (string in binary)
2PufferfishTPU v4 / TPU v4 litev4, v4liteTPU v4HIGH (string in binary)
3ViperfishTPU v5 / TPU v5 litev5, v5e, v5pTPU v5p / v5eHIGH (string in binary)
4GhostliteTPU v6 litev6eTrilliumLOW — "Trillium" is NOT in the binary
56acc60406TPU7xtpu7x, tpu7IronwoodLOW — "Ironwood" is NOT in the binary (external name)

GOTCHA — the string Trillium has zero occurrences in libtpu.so; so does Ironwood; so does Ghostfish. Trillium = Cloud v6e = Ghostlite/glc/TpuVersion 4 and Ironwood = Cloud tpu7x = 6acc60406/gfc/TpuVersion 5 are both external facts (Cloud-TPU documentation), correct but un-sourceable from the binary. The newest generation's only internal name is the obfuscated tag 6acc60406; its gxc::gfc directory abbreviation plausibly stands for a "Ghostfish"-style fish name, but that name is not present — do not assert it. Cite 6acc60406 (or TPU7x for the display string) as the canonical internal name for TpuVersion 5, and treat Ironwood as the external-only marketing label.


Two Axes, Two Numberings — Why TpuVersionDeviceType

The most common error is to index one table with the other's ordinal. TpuVersion 4 is Ghostlite; DeviceType 4 is not any generation in this table at all. They are different enums maintained by different subsystems, and they were never meant to align.

TpuVersion — the dense compiler axis (0..5)

tpu::TpuVersion is the compiler / codec / HAL axis. It is a contiguous 0..5, one value per silicon family that the compiler emits code for. TpuVersionToString bounds it at < 6; TpuCodec::Create (0x1e835fa0) is a clean 6-case switch (case 0→Jellyfish … case 5→ the anonymous gfc codec via sub_1E838380); TpuVersionFromProto maps proto 1..6 onto it as internal = proto − 1. Lite variants (Puffylite, Viperlite) do not get their own TpuVersion — they multiplex inside the parent family's HAL through the embedded TpuChipParts proto, so this axis has exactly six values.

DeviceType — the sparse profiler axis (1..13)

xprof::DeviceType is the profiler / trace axis. DeviceTypeFromDeviceIdentifiers (0xf6993a0) reads a captured device's 12-byte PCI DeviceIdentifiers tuple and assigns a DeviceType ordinal directly — and that ordinal set is sparse: the eight real TPU silicon generations land on ordinals {3, 5, 7, 8, 10, 11, 12, 13}, skipping 1, 2, 4, 6, 9. The skipped values are not gaps: in the 13-entry name table off_21772F00, ordinal 1 is "GPU" and ordinals 2, 4, 6, 9 all read the generic "Cloud TPU" placeholder string, so the TPU silicon slots are interleaved with a GPU slot and several unassigned/fallback slots. DeviceTypeString (0xf69c7c0) computes index = ordinal − 1 and indexes that table, bounding at ordinal − 1 > 0xC (i.e. ordinal 1..13); out-of-range returns "Cloud TPU". The ordinal store is a literal mov in each branch of DeviceTypeFromDeviceIdentifiers:

// xprof::tpu::DeviceTypeFromDeviceIdentifiers(DeviceIdentifiers)  // 0xf6993a0
// each branch matches the PCI tuple against a kXxxChipIdentifiers constant,
// then stores the DeviceType ordinal at result+8 (decompiler: result[2]):
if matches kJellyfishIdentifiers:            DeviceType = 3
else if matches kDragonfishIdentifiers:      DeviceType = 5
else if matches kPuffyliteChipIdentifiers:   DeviceType = 8     // pxc::plc — its own ordinal
else if matches kPufferfishChipB0{Mfg,Water,Air}Identifiers:
                                             DeviceType = 7     // pxc::pfc
else if matches kViperliteChip{A0,A1}{PF,VF}Identifiers:
                                             DeviceType = 11    // vxc::vlc
else if matches kViperfishChip{PF,VF}Identifiers:
                                             DeviceType = 10    // vxc::vfc
else if IsGlc(ids):                          DeviceType = 13    // gxc::glc, Ghostlite / v6e
else if IsGfc(ids):                          DeviceType = 12    // gxc::gfc, 6acc60406 / v7x
else: error("Unsupported device identifiers")                  // device_identifiers_utils.cc:152

QUIRK — on the DeviceType axis the two newest generations are numerically inverted relative to chronology: Ghostlite (older, v6e) is 13, while 6acc60406 (newer, v7x) is 12. The name table itself confirms it directly — off_21772F00 slot 11 (ordinal 12) is "TPU v7x" and slot 12 (ordinal 13) is "TPU v6 Lite". This is the single fact that trips every analyst — DeviceType 12 < 13 does not imply v7x is older than v6e. The profiler's perf-counter layer gates on DeviceType == 12 precisely because v7x is the only generation in this build that exposes named on-device counters (see v7x Perf-Counters); a reimplementer who gates on == 13 expecting "the latest chip" silences the entire v7x counter pipeline.

GOTCHA — Puffylite (pxc::plc) and Viperlite (vxc::vlc) exist as first-class DeviceType ordinals (8 and 11) but have no TpuVersion of their own — they fold into Pufferfish (TpuVersion 2) and Viperfish (TpuVersion 3) respectively. So DeviceType → TpuVersion is many-to-one. Translating a captured DeviceType to a compiler TpuVersion must collapse 8→2 and 11→3; the reverse direction loses the lite/non-lite distinction (which is recovered from the TpuChipParts variant, not from TpuVersion).

The proto axis (1..6) and the public TpuType

A third enum, TpuVersionProto, is the protobuf wire form: TPU_V2=1TPU_V6_LITE=5, TPU_V7X=6. TpuVersionFromProto (0x20b3a8c0) is the literal internal = proto − 1 translation; this is why the embedded 6acc60406_chip_parts.binarypb blob carries version = 6 (proto) for the chip whose internal TpuVersion is 5. A fourth, coarser public enum — superpod::routing::TpuType (GetTpuType @ 0x1ff94340) — spreads the lite/standard split back out (type=2type=10). Four enums, fully reconcilable through the master table above; see Dual-Enum: Proto vs Internal.


Gotchas and Namespace Nesting

Codec namespace nesting — family vs sub-core

The codec/ISA namespaces are two levels deep: a family tag, then a sub-core — for the split families (pxc, vxc, gxc) that sub-core is a fetch/load pair; jxc is fused and instead nests engine blocks. A symbol search for the family tag alone (pxc, vxc, gxc) lands in the wrong sub-namespace half the time. The nesting, under asic_sw::driver::deepsea:::

FamilySub-cores (nested namespaces)Serves
jxcjxc::jfc (Jellyfish core), jxc::dfc (dataflow), jxc::registers, jxc::snapJellyfish, Dragonfish (fused, no fetch/load split)
pxcpxc::pfc (fetch), pxc::plc (load)Pufferfish, Puffylite
vxcvxc::vfc (fetch), vxc::vlc (load)Viperfish, Viperlite
gxcgxc::glc (load), gxc::gfc (fetch)Ghostlite (glc), 6acc60406 (gfc)

GOTCHA — jxc::jellyfish, jxc::dragonfish, jxc::bcs, and jxc::brn are not namespaces. The only real nested namespaces under jxc are the engine blocks (jfc, dfc, registers, snap); the bcs/brn tokens are prefixes inside *_trace_entry type names (bcs_internal_trace_entry, brn_perf1_trace_entry), and jellyfish/dragonfish appear only as *_performance_counters identifiers. JXC's compiler-side ISA lives in platforms_deepsea::jellyfish::isa, not in any jxc::isa. See Sub-Core Taxonomy.

QUIRK — the gxc family registers its HAL into the shared TpuHalVxcHardwareFactory (vtable 0x21cabf70), the same factory class Viperfish uses — there is no TpuHalGxc factory. Three internal codenames (Viperfish, Ghostlite, 6acc60406) share one factory class and one vtable, differing only by the stored TpuVersion at +8. The per-generation HAL registration is what google_init_module_tpu_hal_{vxc,glc,gfc}_hardware_impl injects; the family tag in the codec namespace (gxc) and the HAL factory class (Vxc) are deliberately different — don't expect them to match.

NOTE — only TpuVersion 4 (glc) ships a named codec class, tpu::TpuCodecGhostlite (_ZTV @ 0x21d35c00). TpuVersion 5 (gfc) ships an anonymous codec (vtable 0x21d35898, built by sub_1E838380, reached as case 5 of TpuCodec::Create); there is no TpuCodec6acc60406 symbol. The codec's Encode guard re-proves the proto axis independently: the glc codec checks proto_tag == 5 at +0x58, the gfc codec checks proto_tag == 6.

The two off-by-one SparseCore sequencer enums

TpuSequencerType (the sub-core a bundle targets) has two numberings one apart, and mixing them silently encodes for the wrong engine. The codec template instantiates SCS/TAC/TEC at internal values {3, 4, 5}; the proto/runtime form is one higher, {4, 5, 6}:

SequencerCodec-template (internal)Proto / runtime
TensorCore (TC)01
BarnaCore (BCS)12
(reserved)23
SparseCore Scalar (SCS)34
SparseCore Tile-Access (TAC)45
SparseCore Tile-Execute (TEC)56

TpuSequencerTypeFromProto (0x20b36300) is the literal internal = proto − 1 switch that joins them; the SCS codec is instantiated at (TpuSequencerType)3, the TAC codec at (TpuSequencerType)4. Full op rosters per generation are on Sequencer Ops Per Gen.

GOTCHA — 6acc60406 (v7x) ships SCS + TEC only, no TAC. gxc::gfc::isa::SparseCoreScs{Bundle,CodecBase,Program} and gfc::isa::SparseCoreTec{Bundle,Program} are present in the symbol table; gfc::isa::SparseCoreTac{Bundle,CodecBase,Program} is absent. Viperfish (vfc) and Ghostlite (glc) carry all three SparseCore sequencers; 6acc60406/gfc (v7x) drops the tile-access engine. A reimplementation that assumes the SparseCore triad is uniform across the SparseCore-bearing generations (Viperfish onward) will emit a TAC codec for v7x that the hardware has no sequencer for.

Trace-codec selection is keyed on PCI identity, not on either ordinal

GetTraceCodec (0xf5a2900) does not take a TpuVersion or a DeviceType. It re-classifies the raw DeviceIdentifiers tuple with the Is{Jfc,Dfc,Pfc,Plc,Vfc,Vlc,Glc,Gfc} predicates and selects one of six std::variant codec alternatives. The variant index is a fourth, independent small enum (jxc=6, glc=1, gfc=2, vlc=3, vfc=4, pxc=5 in the decompiled __assign<N> calls) that matches none of the other three axes. When wiring the profiler, drive codec selection from the PCI tuple through these predicates — not from a DeviceType or TpuVersion you computed elsewhere. See Riegeli Trace Container for how the selected codec is then framed.


Cross-References