Skip to content

RouteCacheDeduplicator — 缓存键与三个代号集合

本页所有地址均适用于 libtpu-0.0.40-cp314-cp314-manylinux_2_31_x86_64 wheel 中的 libtpu.so(构建 libtpu_lts_20260413_b_RC00,build-id 89edbbe81c5b328a958fe628a9f2207d)。该二进制带有完整 C++ 符号(.text VMA == 文件偏移,基址 0xe63c000);下文所有地址都是 VMA。解修饰名称、结构体偏移和字符串字面量均已与 IDA 反编译交叉核对。其他版本会有所不同。

摘要

RouteCacheDeduplicator把切片形状转换为预烘焙 route-cache blob 的查找表,也是让同一形状的每种轴旋转共享一个烘焙 blob 的机制。它是 InitRouteSolution 在预计算(快速)路径上首先触碰的对象:在从磁盘读取任何 blob 之前,会用拓扑的 {dim_sizes, is_twisted, orientation} 三元组对已填充的 FlatHashMap 做哈希查找。命中会返回该 blob 烘焙时使用的规范标识符,以及把该规范 chip-id 空间重映射到当前拓扑的 vector<proto::Orientation> 旋转。这个旋转向量正是 route-cache-decompress.md 中的 CacheRead 用来给内存映射重新键控的输入。

去重器存在的原因是烘焙 blob 的库存很小:kRouteCacheSet 中只有八个 twisted 形状,但一个物理切片可能是沿 XYZ 轴 twisted 的 12x12x24 torus。生产者不会为每个(形状 × 轴)烘焙一个 blob,而是为每个形状烘焙一个规范 blob,并把每个形状的全部四种 orientation(X/Y/Z + 无 orientation 形式)注册为映射键,全部指回同一个规范条目。映射的是从规范 orientation 恢复被查询 orientation 的 orientation 旋转,也就是 CacheRead 中旋转辅助器应用的几何收益。

本页负责说明去重键RouteCacheIdentifier)、Find/Insert/UpdateDeduplicator 查找与填充路径,以及按代号集合的选择:无参 singleton 只由 kRouteCacheSet 喂入;按 codename 加键的 GetCacheDeduplicator(int) singleton 则在基础集合之上叠加 k6acc60406RouteCacheSetkViperfishRouteCacheSet。缓存容器(四个 FlatHashMap 和运行时读侧分派)见 toroidal-route-cache.mdDecompress + proto 到 map 的展开见 route-cache-decompress.md;逐轴旋转数学见 route-cache-codec.md

对重新实现而言,契约是:

  • RouteCacheIdentifier{ vector<int> dim_sizes; bool is_twisted; optional<proto::Orientation> orientation },通过 Abseil combine<vector<int>, bool, optional<Orientation>> 哈希,其中 is_twisted取反形式(^ 1)参与哈希。
  • Find — 一次 FlatHashMap 查找;命中时复制匹配槽位中的规范 RouteCacheIdentifier 以及vector<Orientation> 旋转;未命中时返回 not-found 标志。
  • UpdateDeduplicator — 对集合中的每个拓扑字符串,先 ParseTopologyString,再 Insert 四个变体(X/Y/Z + NONE),从而让全部旋转注册到同一个规范条目。
  • 三个集合kRouteCacheSet(基础集合,八个 twisted 形状)、k6acc60406RouteCacheSetkViperfishRouteCacheSet。无参 singleton 只加载基础集合;6acc60406(TPU7x)和 viperfish singleton 各自加载基础集合外加其代号专属集合。
查找RouteCacheDeduplicator::Find(const RouteCacheIdentifier&) @ 0x20b59000
插入(规范化)RouteCacheDeduplicator::Insert(const RouteCacheIdentifier&) @ 0x20b58340
填充集合(anon)::UpdateDeduplicator(RouteCacheDeduplicator&, SetView<string_view>) @ 0x1fbe3780
键哈希absl::…::combine<vector<int>, bool, optional<proto::Orientation>> @ 0x20b5aa40
解析形状字符串slice_builder::ParseTopologyString(string_view) @ 0x20b480c0
无参 singleton(anon)::GetCacheDeduplicator()::deduplicator(guard @ 0x2258fc28
代号 singleton(anon)::GetCacheDeduplicator(int)::{pf,vf,gf}_deduplicator
基础集合kRouteCacheSet @ 0x22011f88(8 个 {const char*, size_t} 对,.data.rel.ro
代号集合k6acc60406RouteCacheSet, kViperfishRouteCacheSetResilientToroidalTopology:: 成员)
来源platforms/accel_ssw/deepsea/slice_builder/internal/{toroidal_route_cache,topology}.cc

对于键字段遍历、Find 槽位复制偏移、Insert 规范化链、UpdateDeduplicator 四变体扇出,以及三个集合的代号分层,置信度为 Confirmed (byte-anchored),均已与 IDA 反编译交叉核对(combine<…> 模板解修饰、FlatHashMapPolicy<RouteCacheIdentifier, pair<…, vector<Orientation>>>find/find_or_prepare_insert 实例化,以及命名每个集合的 MakeCheckFailString 字面量)。两个 LOW / HIGH 项在正文中就地标出(int → ToroidalRouteCacheType 表,以及 code 来源)。


1. 去重键 — RouteCacheIdentifier

该键是一个三字段结构体,用切片形状而不是芯片对来标识唯一 route-cache 条目。具有相同形状、twist 和轴 orientation 的两个切片共享一个条目;逐 (src,dst) 的数据位于该条目指向的 blob 内部。

c
struct RouteCacheIdentifier {                       // sizeof ~0x28
    std::vector<int>            dim_sizes;           // +0x0 base / +0x8 end / +0x10 cap
    bool                        is_twisted;          // +0x18   (hashed inverted: ^ 1)
    std::optional<proto::Orientation> orientation;   // +0x1c value (int) / +0x20 has_value (bool)
};
```text

字节偏移已由 `0x20b5aa40` 处的 hash-combine 字段遍历确认。其解修饰模板签名为 `combine<std::vector<int>, bool, std::optional<proto::Orientation>>`,也就是按声明顺序的三个字段:

```c
// 0x20b5aa40 — HashStateBase<MixingHashState>::combine<vector<int>, bool, optional<Orientation>>
//   step 1: CRC32 over the dim_sizes int vector (4 bytes / 8 bytes per stride; tail-folded)
v11 = _mm_crc32_u32(v11, *(uint32_t*)v7);                 // each int element

// step 2: is_twisted, hashed INVERTED — (*a3 ^ 1)
v15 = _mm_crc32_u64(HIDWORD(v14), -(int64_t)(uint8_t)*a3);
v16 = _mm_crc32_u64((unsigned)v14, 3LL * (*a3 ^ 1u) - 3); // line 0x20b5aae4
// step 3: the optional<Orientation> { value @ +0, has_value @ +4 }

怪癖 — is_twisted 以取反形式(^ 1)哈希。 该布尔值在进入 CRC 混合前会与 1 做 XOR(3 * (is_twisted ^ 1) - 3)。这不影响正确性,因为哈希在内部是一致的;但如果重新实现者对原始布尔值做哈希,会得到不同的哈希表布局,并且如果某天去重表被序列化,将无法与烘焙的去重表互操作。它只是结构体字节如何被送入 absl::Hash 的产物;只有在需要逐字节哈希兼容时才需要原样复现。

proto::Orientation enum(既用作可选键字段,也用作值向量的元素类型)是一个稠密的 [0,6] protobuf enum:

名称名称
0UNKNOWN4A
1X5B
2Y6C
3Z

UpdateDeduplicator(§3)只会产生 X/Y/Z(1/2/3)和未设置(has_value == false)形式;A/B/C 属于 enum 取值范围,但在此构建中未作为去重 orientation 使用。


2. 去重器映射与 Find @0x20b59000

去重器是单个 Abseil flat hash map,其 policy 已由 Find 内部的 find 实例化从字节层面确认:

text
absl::container_internal::raw_hash_set<
  absl::container_internal::FlatHashMapPolicy<
    RouteCacheIdentifier,                                            // KEY
    std::pair<RouteCacheIdentifier, std::vector<proto::Orientation>> // VALUE
  >>
```text

因此每个槽位存储 `(key, value)`,其中 `value` 本身是 `pair<canonical RouteCacheIdentifier, vector<Orientation>>`。**值中的** `RouteCacheIdentifier` 是烘焙 blob 写入时使用的*规范*(未旋转)形状;`vector<Orientation>` 是把该规范形状映射到被查询形状的旋转。一个形状的四种 orientation 这些多个键都指向同一个规范条目,这就是去重。

`Find` 是一个命中后复制的例程。命中时,它通过复制匹配槽位的值来物化一个小型的 `StatusOr<RouteCacheIdentifier>` 形状结果:

```c
// 0x20b59000 — Find(out <- a1, const RouteCacheIdentifier* key <- a2, hash <- a3)
__int64 Find(out, key, hash) {
    if (map.find<RouteCacheIdentifier>(key, hash)) {       // FlatHashMapPolicy find → slot ptr v5
        // --- copy the slot's CANONICAL RouteCacheIdentifier into out[0x0..0x20] ---
        out[0..0x10] = {};                                 // empty dim_sizes vector header
        n = slot->dim_sizes.size();                        // [slot+0x30]
        if (n) {
            out.dim_sizes = new int[n];                    // operator new(4*n)
            memcpy(out.dim_sizes, slot->dim_sizes, 4*n);   // [slot+0x28] → out+0x0
        }
        out.is_twisted  = *(uint8_t*)(slot+0x48);          // canonical is_twisted
        out.orientation = *(uint64_t*)(slot+0x40);         // canonical optional<Orientation>
        // --- copy the VALUE vector<Orientation> (the rotation) into out[0x28..0x38] ---
        m = slot->orient_vec.size();                       // [slot+0x58]
        if (m) {
            out.orient_vec = new Orientation[m];           // operator new(4*m)
            memcpy(out.orient_vec, slot->orient_vec, 4*m); // [slot+0x50] → out+0x28
        }
        out.ok = 1;                                        // [out+0x40] = found
    } else {
        out.dim_sizes_hdr = 0;
        out.ok = 0;                                        // [out+0x40] = not found
    }
    return out;
}

槽位偏移已从字节确认:规范 dim_sizes 向量位于 slot+0x28/0x30,规范 is_twisted/orientation 位于 slot+0x48/slot+0x40,值中的 vector<Orientation> 旋转位于 slot+0x50/0x58。结果的成功字节是 [out+0x40]。未命中时,结果携带空的 dim_sizes 头和 ok == 0

说明 — 调用者如何使用两半结果。 返回的规范 RouteCacheIdentifier 会送入 GetRouteCacheDataPath 来计算 embed://…/<shape>.binarypb.compressed 路径(文件名使用规范形状);返回的 vector<Orientation> 会送入 CacheReadTopologyRotationHelper(该旋转把已加载的 map 重新键控到被查询拓扑)。重新实现者必须贯通结果的两半,而不只是命中/未命中标志。见 route-cache-decompress.md


3. 填充集合 — UpdateDeduplicator @0x1fbe3780 与 Insert @0x20b58340

UpdateDeduplicator 接受一个 gtl::SetView<string_view>(三个 k*RouteCacheSet 表之一)并注册其中每个形状。对每个拓扑字符串,它先解析形状,然后插入四个 orientation 变体:

c
// 0x1fbe3780 — UpdateDeduplicator(RouteCacheDeduplicator& dedup, SetView<string_view> set)
for (string_view topo : set) {
    auto [dims, is_twisted] = ParseTopologyString(topo);   // 0x20b480c0
    // four Insert variants — orientation value (v30) X(1) / Y(2) / Z(3), then the NONE form
    Insert(dedup, {dims, is_twisted, /*orient=*/X, /*has=*/true});   //  v30=1  @0x1fbe385c-ish
    Insert(dedup, {dims, is_twisted, /*orient=*/Y, /*has=*/true});   //  v30=2
    Insert(dedup, {dims, is_twisted, /*orient=*/Z, /*has=*/true});   //  v30=3
    Insert(dedup, {dims, is_twisted, /*orient=*/NONE, /*has=*/false});//  the un-oriented form
}
```text

反编译确认了该扇出:一串 `Insert` 调用中 orientation 字段(`v30`)被设为 `1`、`2`、`1`、`2`,随后是 `3`,外加无 orientation(NONE/`has_value == false`)路径;也就是每个形状注册四个键,让一个规范 blob 服务每种轴旋转。

`ParseTopologyString` @ `0x20b480c0` 会按 `'x'` 拆分字符串(Abseil `ByChar('x')`),用 `safe_strto32_base` 把每段解析进 `dim_sizes`,并通过 `"_twisted"` 后缀测试设置 `is_twisted`(`setne @0x20b481a1`)。因此 `"12x12x24_twisted"` → `dims=[12,12,24], is_twisted=true`,而 2 轴 `"4x8_twisted"` → `dims=[4,8], is_twisted=true`。

`Insert` @ `0x20b58340` 不会原样存储被查询的标识符;它会先**规范化**

```c
// 0x20b58340 — Insert(RouteCacheDeduplicator& dedup, const RouteCacheIdentifier& id)
auto faulty   = ToFaultyDimensions(id);          // 0x20b57b40 — vector<FaultyDimension> (stride 12)
sort(faulty);                                     // introsort 0x20b59140
auto canonical = ToRouteCacheIdentifier(faulty);  // 0x20b57d80 — the un-rotated canonical shape
auto rotation  = ToRotationMapper(canonical, id); // 0x20b58160 — the Orientation rotation list
dedup.find_or_prepare_insert(canonical) = {canonical, rotation};   // 0x20b5b680

ToRouteCacheIdentifier 会验证最多只有一个维度是 “faulty”(即最多只有一个轴被旋转);两个会触发 abort 字符串 "Only one faulty orientation is allowed but found two:".rodata @ 0xa244c87,带 " v.s." 分隔符 @ 0xa291630)。存储的值对是 {canonical key, rotation vector},也正是 Find 复制出来的内容。

陷阱 — 你查询的键不是被存储的键。 Insert规范标识符注册为 map 键,但会针对每个 orientation 变体调用一次。四个变体都会规范化到(近似)同一个形状,但携带不同旋转,因此 map 最终会为每个不同规范形状保留一个条目,其值记录如何到达被查询的 orientation。若重新实现者直接存储被查询的 RouteCacheIdentifier(跳过 ToFaultyDimensions → ToRouteCacheIdentifier),就会破坏旋转收益:CacheRead 随后会收到 identity rotation,并错误地给旋转切片的 map 键控。


4. 三个代号集合与逐 singleton 选择

这里有三个拓扑字符串集合,以及消费它们的两类不同 singleton。这是本页的结构核心,而三个集合之间的区别很容易混淆。

4.1 基础集合 — kRouteCacheSet @0x22011f88

TwistedTorusTopology::kRouteCacheSet @ 0x22011f88.data.rel.ro 中的八个 {const char*, size_t} 对,RELA 解析到八个 twisted 形状字符串。(ResilientToroidalTopology::kRouteCacheSet @ 0x21f57380 是一个不同的数据符号,库存更大且不同,包含十二个 {const char*, size_t} 对,覆盖普通和 twisted 形状:4x4x4, 4x4x8, 4x4x8_twisted, 4x4x12, 4x4x16, 4x8x8, 4x8x8_twisted, 8x8x8, 8x8x16_twisted, 8x16x16_twisted, 12x12x12, 12x12x24_twisted(通过重定位 0x21f57380 处的 RELA 指针按字节验证)。§4.3 代号 singleton 叠加的 resilient base set 是这个 12 形状的 ResilientToroidalTopology::kRouteCacheSet不是下表列出的 8 形状 twisted set。)

索引str VMA长度字符串维度
00x87022ba1612x12x24_twisted[12,12,24]
10x87022a91612x24x24_twisted[12,24,24]
20x87022cb1616x16x32_twisted[16,16,32]
30x870227c134x4x8_twisted[4,4,8]
40x870227e114x8_twisted[4,8]
50x870226e134x8x8_twisted[4,8,8]
60x8702299158x16x16_twisted[8,16,16]
70x870228a148x8x16_twisted[8,8,16]

这八个形状 × 四个 {X,Y,Z,NONE} orientation 变体会注册 32 个去重键(规范化后收敛为每个不同规范形状一个条目)。索引 4 是唯一的 2 轴形状(4x8_twisted)。

4.2 无参 singleton(slice-builder twisted torus)

TwistedTorusTopology::InitRouteSolution @ 0x20b3f7c0 使用无参 GetCacheDeduplicator()(匿名命名空间 singleton,guard @ 0x2258fc28)。其惰性 Create() lambda 遍历 kRouteCacheSet0x20b3f990 处的循环把 &kRouteCacheSet[v15] / [v15+1] 当作 {ptr,len} 对索引),并调用一次 UpdateDeduplicator。这条路径上的未命中是致命错误:"Cannot find route cache: ".rodata,见该函数的错误构造器)。这是唯一的默认去重器;它永远不会看到代号集合。

4.3 按代号加键的 singleton(resilient 路径)

ResilientToroidalTopology::InitRouteSolution @ 0x1fbdf8a0 使用 int 重载 GetCacheDeduplicator(int code)。反编译后的 switch (code) 会选择三个匿名命名空间 singleton 之一,并且每个都会惰性填充自己:在基础 kRouteCacheSet 之上叠加其代号集合。集合名称由 CHECK/MakeCheckFailString 字面量按字节确认:

codesingletonUpdateDeduplicator 调用(按顺序)ToroidalRouteCacheType
1pf_deduplicator (pufferfish)kRouteCacheSetCACHE_ICI_RESILIENCY_PUFFERFISH (2)
2vf_deduplicator (viperfish)kRouteCacheSet,然后 kViperfishRouteCacheSetCACHE_ICI_RESILIENCY_VIPERFISH (3)
4gf_deduplicator (6acc60406 / TPU7x)kRouteCacheSet,然后 k6acc60406RouteCacheSetCACHE_ICI_RESILIENCY_6acc60406 (4)

精确的反编译 CHECK 字符串如下,逐字保留:

text
"UpdateDeduplicator( **pf_deduplicator, ResilientToroidalTopology::kRouteCacheSet) is OK"
"UpdateDeduplicator( **vf_deduplicator, ResilientToroidalTopology::kRouteCacheSet) is OK"
"UpdateDeduplicator( **vf_deduplicator, ResilientToroidalTopology::kViperfishRouteCacheSet) is OK"
"UpdateDeduplicator( **gf_deduplicator, ResilientToroidalTopology::kRouteCacheSet) is OK"
"UpdateDeduplicator( **gf_deduplicator, ResilientToroidalTopology::k6acc60406RouteCacheSet) is OK"
```text

> **说明 — 代号集合是*加法式*的,不是替换。** Pufferfish 只加载基础 `kRouteCacheSet`。Viperfish 和 `6acc60406` 各自先加载基础集合,**然后**加载其代号专属集合;viperfish 通过 `RouteCacheDeduplicator::CreateResilientViperfish()` 的 `Create` lambda(其 `__policy_func` 在第二次 `UpdateDeduplicator` 前接线),`6acc60406` 通过 `k6acc60406RouteCacheSet`。因此 viperfish 切片既可以命中基础 twisted 形状,*也可以*命中 viperfish 专属形状;它们并不互斥,`6acc60406` 也没有折叠进基础集合。不同符号名、每个 singleton 两次调用的结构,以及逐字 `CHECK` 字面量共同确认了三个集合,其中基础集合为所有集合共享。置信度:HIGH。

`code` 值来自 fault topology(追踪到 `TopologyFaults::GetSymmetryProperty` @ `0x20bfbd60` / `GetMinFaultLocation` @ `0x20bfbc00`)。在 `Find` 之后,同一函数中的*第二个* `switch`(post-Find 分支处的 case `1 → 4 → 2`)会重新推导传给 `GetRouteCacheData` 的 `ToroidalRouteCacheType`(逐代号烘焙 blob)。结构绑定(`pf → PUFFERFISH`、`vf → VIPERFISH`、`gf → 6acc60406`)通过去重 singleton 按字节确认;第二个 switch 的精确 `code → enum` 整数算术是结构性读取,并未穷尽制表。置信度:LOW。

> **说明 — `6acc60406` 是已脱敏的硅代号,不是十六进制地址。** 它在 enum 名称(`CACHE_ICI_RESILIENCY_6acc60406`)、集合符号(`k6acc60406RouteCacheSet`)和资源路径前缀中都作为字符串 token 原样出现。它表示 TPU7x 硅代;应把它当作不透明标识符。

---

## 5. 端到端位置(一张图)

```text
[slice-builder, non-resilient] TwistedTorusTopology::InitRouteSolution     # 0x20b3f7c0
  dedup = GetCacheDeduplicator()              # no-arg singleton; UpdateDeduplicator(kRouteCacheSet)
  res   = dedup.Find({this.dims, twisted, orient})                          # 0x20b59000
  if !res.ok: FATAL "Cannot find route cache: "
  blob  = ToroidalRouteCache::Create(res.canonical, CACHE_TWISTED_TORUS, res.orient_vec)
                                              # → route-cache-decompress.md

[slice-builder, resilient]     ResilientToroidalTopology::InitRouteSolution # 0x1fbdf8a0
  code  = f(TopologyFaults.GetSymmetryProperty / GetMinFaultLocation)
  dedup = GetCacheDeduplicator(code)          # switch: 1→pf / 2→vf / 4→gf singleton
          # pf: UpdateDeduplicator(kRouteCacheSet)
          # vf: UpdateDeduplicator(kRouteCacheSet); UpdateDeduplicator(kViperfishRouteCacheSet)
          # gf: UpdateDeduplicator(kRouteCacheSet); UpdateDeduplicator(k6acc60406RouteCacheSet)
  res   = dedup.Find(...)                      # 0x20b59000
  type  = {pf→PUFFERFISH, vf→VIPERFISH, gf→6acc60406}                       # CACHE_ICI_RESILIENCY_*
  blob  = ToroidalRouteCache::Create(res.canonical, type, res.orient_vec)

Find 的两个输出,即规范 RouteCacheIdentifier(命名 blob 文件)和 vector<Orientation>(旋转已加载的 map),就是本页暴露给其余加载路径的完整接口。