Skip to content

GetDistances

本页所有地址均适用于 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 == 文件偏移,因此下面每个 0x20b… 地址都是 VMA。其他版本会有所不同。

摘要

GetDistances 是 slice-builder twisted torus 的候选路由生成器:给定源坐标和目标坐标,它返回二者之间所有最小曼哈顿距离路由,形式为有符号逐轴位移向量的 vector<Coordinates>。它是路径生成器(GetStaticPathRandomizedToroidalWildFirstPaths)消费的几何核心:它们拿到一个距离向量,选择一个轴顺序,并把它打包成 hops。本页负责距离端:TwistedTorusTopology::GetDistances @ 0x20b420e0(生成器)、TwistedTorusTopology::GetDistanceFromOrigin @ 0x20b42980(逐轴 toroidal-with-twist 距离),以及让 torus 成为 twisted 而非 plain 的 seam table。

熟悉的参考系是教科书式环面距离:在大小为 S 的环上,两点之间的距离是 min(forward, backward),其中一个方向会跨过 seam(±S)。3-D torus 对每个轴独立执行这一点;选择在哪些轴上绕回就是符号选择,因此一个节点最多有 2^(#wrappable-axes) 条候选路由,并且最短路可能在其中多条之间并列GetDistances 精确枚举这个幂集:它为每个组合构建一个 Polarity 向量(POSITIVE = 向前 wrap,NEGATIVE = 向后 wrap,NONE = 不 wrap),通过 GetDistanceFromOrigin 计算得到的位移,取 ManhattanNorm,并保留所有并列最小的位移。返回集合的大小就是 vertex class — corner / edge / mid — 供 twist tiebreaker(twist/get-tiebreak)分派使用。

与 plain torus 唯一的差异是 twist seam。在一个加倍(长度 2K)轴上,跨越 wrap 边不会回到伙伴轴上的相同位置,而是会偏移 +K,也就是 replica-group 构造同样使用的 (+K,+K) 对角折叠。GetDistanceFromOrigin 用逐 wrap 的 seam carry 串起这一点:当某个轴 wrap 时,它会把逐轴偏移向量(seam[d],来自 this+0x108)加入运行中的累加器,并按每个轴大小取模折叠。这就是完整的 nK-shape 故事:长 nK 轴只是另一个具有 dimsize = nK 和自身 seam 条目的维度;没有特殊 case 分支,这也是 tiebreaker 不需要特殊分支的原因。

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

  • 候选枚举GetDistances):wrap-mask popcount、2^m 上限且 ≥2<2 时设为 1 的 Polarity 循环、最小曼哈顿 keep-all-ties 规则,以及向 vector<Coordinates> 的有序插入。
  • 逐轴 toroidal-with-twist 距离GetDistanceFromOrigin):有符号 delta = c − accum[d]、由 Polarity 门控的 ±dimsize[d] wrap、wrap 触发条件,以及 seam carry accum[j] = (seam[d][j] + accum[j]) mod dimsize[j]
  • seam tablethis+0x108):在 Init 中构建的 vector<vector<int>>,每轴一个内部 vector,编码加倍轴 wrap 在伙伴轴上诱发的 +K 对角偏移。
生成器TwistedTorusTopology::GetDistances @ 0x20b420e0(vtable +0xc0
逐轴距离TwistedTorusTopology::GetDistanceFromOrigin @ 0x20b42980
单距离消费者TwistedTorusTopology::GetDistance @ 0x20b408e0(vtable +0xb8
范数 / 比较Coordinates::ManhattanNorm @ 0x20c0ba00 · operator< @ 0x20c0ba40
Seam / 大小 / 顺序this+0x108 seam · this+0x10 dim-sizes · this+0x40 dim-order · this+0xf0 wrap-mask
Polarity 枚举NONE=0, POSITIVE=1, NEGATIVE=2 (accel_ssw::deepsea::proto::Polarity)
Coordinatesint32 ndims @+0, ≤6 int32 coords @+4..+0x18, sizeof = 0x1c
源文件platforms/accel_ssw/deepsea/slice_builder/friends/twisted_torus_topology.cc

注意 — 两个 vtable slot 只差一个字母,且不可互换。vtable+0xc0GetDistances(复数)——本页的候选集合生成器。vtable+0xb8GetDistance(单数)——GetStaticPath 调用的 cache-aware 单个距离。若相邻页面称“GetStaticPath 调用 GetDistancesvtable+0xb8)”,那是用复数 sibling 的名字命名单数 slot;逐字节精确的区别见 §GetDistance


GetDistances — 候选路由生成器

用途

GetDistances(src, dst) 返回一个 StatusOr<vector<Coordinates>>:在 twisted torus 上,从 srcdst 达到最小曼哈顿距离的所有有符号逐轴位移向量集合。plain mesh 中每对节点只有一条最短路径;torus 中每种逐轴 wrap 选择都有一条,twist 又会让其中几种 wrap 选择在最小值上并列。该集合是下游 tiebreaker 和 path packer 的输入:生成器回答“多远,以及有多少种同样好的方式”;消费者回答“选哪一种,以及通过哪个 hop 顺序”。

入口点

text
TwistedTorusTopology::GetDistances (0x20b420e0)          ── vtable+0xc0, candidate-set generator
  ├─ Topology::CheckBoundary(src) (0x20bf5800)           ── line 390, both src and dst must be in-bounds
  ├─ Topology::CheckBoundary(dst) (0x20bf5800)           ── line 391
  ├─ Coordinates::Subtract(src, dst) (0x20c0bfc0)        ── line 394, raw mesh delta (boundary-validated)
  ├─ vtable[+0x98](src, raw_delta)                       ── line 395, normalize coord into dim range
  ├─ popcount(wrap_mask[this+0xf0])                      ── #wrappable axes  → combo count
  ├─ for each Polarity combination:
  │     └─ GetDistanceFromOrigin(dst, polarity, wrap)    ── line 444 (0x20b42980)
  │           └─ ManhattanNorm (0x20c0ba00)              ── keep all equal-minimum vectors
  └─ vector<Coordinates>::emplace (operator< 0x20c0ba40) ── sorted insert of each tying vector

算法

c
function GetDistances(this, src, dst):                   // 0x20b420e0
    if !CheckBoundary(src):  return Error(line 390)       // 0x20b42106
    if !CheckBoundary(dst):  return Error(line 391)       // 0x20b4211b
    raw   = Coordinates::Subtract(src, dst)               // 0x20b42137, line 394 — plain mesh delta
    base  = this->vtable[0x98](src, raw)                  // 0x20b42174, line 395 — fold into dim range
                                                          //   (base is the "from-origin" coord passed below)
    wrap  = this->wrap_applies                            // this+0xf0, vector<bool>: which axes may wrap
    m     = popcount(wrap.bits)                            // 0x20b42210 (bt; adc) — #wrappable axes
    n_combos = (1 << m) < 2 ? 1 : (1 << m)                // 0x20b42404 (shl; cmp $2; cmovl $1)

    best  = 0x7FFFFFFF                                     // 0x20b4242e — min Manhattan norm so far
    routes = []                                           // vector<Coordinates>
    for combo in 0 .. n_combos-1:                          // outer bound is 1<<ndims, see GOTCHA
        // Build the per-axis Polarity span for this combination.
        pol = new Polarity[ndims]                          // 0x20b42470
        for axis a in 0 .. ndims-1:
            pol[a] = _bittest(combo, a) ? NEGATIVE : POSITIVE   // (bit ? 2 : 1) — set for every axis
        // Build the wrap-applies bitset that gates the seam carry, masking out non-wrappable axes.
        wmask = bitset(ndims)                              // 0x20b424d0-ish
        for axis a in 0 .. ndims-1:
            wmask[a] = wrap[a] && pol_combo_selects(a)     // only axes in this combo wrap

        dc = GetDistanceFromOrigin(base, pol, wmask)       // 0x20b42671, line 444
        norm = ManhattanNorm(dc)                           // 0x20b426aa — Sigma |coord|
        if norm < best:                                    // 0x20b426af
            best   = norm
            routes = [dc]                                  // reset to the new minimum
        else if norm == best:
            routes.emplace_sorted(dc)                      // 0x20b4278e, operator< (0x20c0ba40)
        free(pol)
    return routes                                          // |routes| == vertex class size

陷阱 — 组合计数有两个不同边界,它们不是同一个值。内部 accept/reject 循环以 n_combos = max(1<<popcount, 1) 为上限(当 1<<m < 2,即没有轴 wrap 时设为 10x20b42404)。但外部循环继续条件会重新加载 ndims,并比较 combo >= (1 << ndims)0x20b4244c/0x20b42460 区域),不是 1 << m。如果重新实现让两个边界都由 popcount 驱动,在 wrappable < ndims 的拓扑上会迭代过少的组合;如果都由 ndims 驱动,则会在不可 wrap 的轴上构建冗余 Polarity span(无害——这些轴会得到 pol = POSITIVE/NEGATIVE,但 wmask[a] = 0,因此不会触发 wrap)。安全解读是:构建 2^ndims 个 Polarity span,但只有 wrap_applies bit 置位的轴才实际 wrap;重复位移向量会在 keep-all-ties 集合中折叠,因为 operator< 对它们给出相同排序。

怪癖 — 生成器在 Polarity 循环之前会计算一个 Coordinates::Subtract0x20b42137,第 394 行)——也就是 plain mesh delta——然后通过 vtable+0x98(第 395 行)将其归一化为 base 坐标,作为传给 GetDistanceFromOrigin 的实际参数。因此,逐轴距离是从归一化 mesh delta 开始计算的,而不是直接从 dst 重新计算;Polarity 循环随后在其上重新引入 wrap。这与直觉上的“每个组合重新计算一次”相反,并且对精确匹配 wrap 算术很重要——GetDistanceFromOrigin 看到的是已经逐轴缩减到 [0, dimsize) 的坐标,它的 delta = c − accum 会相对零初始化的累加器运行。

keep-all-ties 集合

结果是一个等最小距离路由集合,而不是单个距离。bestINT32_MAX0x20b4242e)开始;严格更小的 norm 会把 routes 重置为单元素 vector,相等的 norm 会通过 Coordinates::operator<(字典序,0x20c0ba40)有序插入。因此最终 vector<Coordinates> 是按位移排序并去重的。

|routes|Vertex class形状消费者
6symmetric midk*k*2kget-tiebreak corner/edge/mid 分派
4cornerk*2k*2k(同上)
3midk*2k*2k(同上)
2edgek*2k*2k(同上)

注意 — 上面的 |routes| → vertex-class 映射,是 twist tiebreaker 用来选择单条规范路由的计数;逐字节精确的 class 边界属于该页面。本页负责说明为什么集合具有该基数2^(#wrap-axes) 并列结构),而不是负责选择。具体计数的置信度:HIGH(锚定于 tiebreaker 页面)。

函数映射

函数地址作用
TwistedTorusTopology::GetDistances0x20b420e0候选集合生成器(vtable +0xc0
TwistedTorusTopology::GetDistanceFromOrigin0x20b42980逐轴 toroidal-with-twist 距离
Coordinates::ManhattanNorm0x20c0ba00Σ|coord|(vpabsd + horizontal add)
Coordinates::operator<0x20c0ba40有序集合的字典序
Coordinates::Subtract0x20c0bfc0归一化之前的 plain mesh delta
Topology::CheckBoundary0x20bf5800src 和 dst 的边界内守卫

GetDistanceFromOrigin — 逐轴 toroidal-with-twist 距离

用途

给定一个(归一化)坐标、一个逐轴 Polarity span 和一个 wrap-applies bitset,GetDistanceFromOrigin 会产生一个有符号位移向量:每个轴上先是直接 delta,在所选 polarity 跨越该轴 seam 时可选地用 ±dimsize wrap,并通过 twist seam carry 把加倍轴 wrap 串到伙伴轴上。这个函数区分了 twisted torus 和 plain torus;在 plain torus 上,seam table 为空,carry 是 no-op。

入口点

text
TwistedTorusTopology::GetDistanceFromOrigin (0x20b42980)
  ├─ Topology::CheckBoundary(coord) (0x20bf5800)         ── line 702
  ├─ alloc accum[ndims], res[ndims]  (memset 0)          ── two int32 arrays
  ├─ for i in dim_order[this+0x40]:
  │     ├─ Coordinates::GetCoordinate(coord, dim)        ── line 713 (0x20c0b800)
  │     ├─ delta = c - accum[dim]                         ── signed
  │     ├─ Polarity[dim] gate → ±dimsize[dim]             ── wrap fwd/back
  │     └─ seam carry: accum[j] = (seam[dim][j]+accum[j]) % dimsize[j]
  └─ Coordinates(res, ndims)                             ── line 713/error line 702

算法

c
function GetDistanceFromOrigin(this, coord, pol, wmask):  // 0x20b42980
    if !CheckBoundary(coord):  return Error(line 702)     // 0x20b429a9
    ndims = this->ndims                                   // this+0x8
    accum = new int[ndims];  memset(accum, 0)             // 0x20b429dd — running carry per axis
    res   = new int[ndims];  memset(res,   0)             // 0x20b429f1 — output displacement per axis

    for i in 0 .. ndims-1:                                // walk axes in DIMENSION ORDER
        dim = this->dim_order[i]                          // this+0x40 base, this+0x48 count (0x20b42a28)
        c   = coord.GetCoordinate(dim)                     // 0x20b42a4c, line 713
        a   = accum[dim]                                   // current carry for this axis
        delta = c - a                                      // 0x20b42a74 — signed direct distance
        res[dim] = delta

        wrapped = false
        switch pol[dim]:                                   // [pol + dim*4] (0x20b42a81)
          POSITIVE(1): if c < a:                            // 0x20b42a95
                          res[dim] = delta + dimsize[dim]   // wrap forward; this+0x10 (0x20b42a9e)
                          wrapped = true
          NEGATIVE(2): if c > a:                            // 0x20b42ada
                          res[dim] = delta - dimsize[dim]   // wrap backward (0x20b42ae2)
                          wrapped = true
          // NONE(0): res[dim] stays the direct delta
        // A third wrap trigger: an axis flagged wrappable whose endpoints coincide.
        if !wrapped && wmask[dim] && c == a:               // 0x20b42aXX (bittest wmask; cmp c,a)
            wrapped = true                                 // seam carry still fires (degenerate wrap)

        if wrapped and seam[dim] is non-empty:             // seam = this+0x108[dim], stride 0x18
            for j in 0 .. ndims-1:                          // thread the twist onto every axis
                accum[j] = (seam[dim].data[j] + accum[j]) % dimsize[j]   // 0x20b42b3f / 0x20b42b98
        accum[dim] = c                                      // 0x20b42b.. — this axis's carry := c
    return Coordinates(res, ndims)                          // 0x20b42c34

陷阱 — seam-carry 的模数按 dimsize[j] 折叠,也就是目标j 的大小,不是按 wrapping 轴 dimdimsize[dim] 折叠。反编译非常明确:模数操作数位于 j 循环内,是 dimsize_base[this+0x10] + 4*j0x20b42b3f/0x20b42b98),由内层计数器索引。如果重新实现按 wrapping 轴的大小折叠整个 carry,会静默破坏每个大小不同于 dim 的伙伴轴;在 k*2k*nk 形状上,这几乎就是全部伙伴轴。逐字节精确读法是 mod dimsize[j]

怪癖 — 坐标从参数coord / GetDistances 传入的归一化 base)读取,并且累加器会按维度顺序向前串起 carry:accum[dim] 只有在 seam carry 已经改变伙伴轴的 accum[j] 之后,才会被设置为 c0x20b42b..)。因此,早序轴上的 wrap 会移动后序轴测量 delta 的参考点。这种顺序耦合就是 twist:各轴并不独立;如果不按 dim_order 访问,就会得到不同(错误)的位移。

为什么 nK 不需要特殊 case

对于 k*2k*nk 形状,长 nK 轴只是 dim_order 中的另一个条目,具有 dimsize = nK 和自己的 seam 向量 seam[nK_axis]。逐轴循环会像用 ±2K wrap 2K 轴一样,用 ±nK wrap 它,并通过 seam[nK_axis][j] 将 seam carry 串到伙伴轴上。这个函数里没有 nK 专用分支,相应地,tiebreaker 中也没有 [+0xe8]==3 分支:全部 nK 依赖都在这里,位于 dimsize[nK_axis] 和 seam 偏移中。唯一把 nK 轴特殊处理的位置在上面的 GetDistance 中,它可以在约化 3-D twist 上计算之前丢弃 nK 轴。

函数映射

函数地址作用
TwistedTorusTopology::GetDistanceFromOrigin0x20b42980逐轴距离 + seam carry
Coordinates::GetCoordinate0x20c0b800从坐标读取轴 dim
Coordinates::Coordinates(int*, n)0x20c0b1e0res[] 构造结果 Coordinates

seam table — this+0x108

用途

seam table 让 torus 成为 twisted。它是位于 this+0x108(计数 this+0x110)的 vector<vector<int>>,每个轴一个内部 vector,每个内部 vector 长度为 ndimsseam[d] 是跨越轴 d 的 wrap 边时加入运行累加器的偏移向量:在 plain torus 上它全为零(wrap 会回到相同的伙伴轴位置),但在加倍(2K)轴上,它记录 +K 对角线,也就是 replica-group 构造使用的相同 (+K,+K) 折叠(twist/get-replica-pair-3d)。

构造(在 Init 中)

c
function Init(this, dim_sizes, twisted):                 // 0x20b3e5e0
    ...
    this->wrap_applies.assign(ndims, ...)                 // this+0xf0 (line 149, 0x20b3e604)
    this->seam.assign(ndims, vector<int>{})               // this+0x108 (lines 167-168, 0x20b3e681)
    // classify axes: an axis of even size >=2 is "doubled" (size == 2K) via K = size/2 (idiv 0x20b3ea37)
    for each doubled axis d:                               // fill loop 0x20b3ea90
        for each partner doubled axis j:                   // 0x20b3eaa4
            this->seam[d][j] = +K                           // the +K diagonal twist (0x20b3eafc)
    // wrap bits for doubled axes are also set here (this+0xf0[d] |= 1)   (0x20b3e870-ish)

注意 — 填充的结构(通过 size==2K 测试检测加倍轴、向 seam[d][j] 写入伙伴轴,以及设置 this+0xf0 上的 wrap bit)已在 Init 中逐字节确认。精确的逐 (d,j) seam 值矩阵——对于每种 k*k*2k / k*2k*2k / k*2k*nk 朝向,哪个轴把 +K+2K0 carry 到哪个轴——只读到了它的 +K 对角算术,没有按朝向穷尽制表。carry 消费者(上面的 GetDistanceFromOrigin)已完整解码;供给它的表在形状上是 HIGH 置信度,在完整逐朝向值矩阵上是 LOW。请把 seam[d][j] 视为“轴 d wrap 在轴 j 上诱发的 twist 偏移”,这是从 Init+K 填充推断出的,而不是完整制表的常量矩阵。

字段偏移类型含义
ndims+0x8int32轴数;约束每个逐轴循环
dim-sizes+0x10 / +0x18vector<int> base / count每轴大小 = wrap 模数 dimsize[a]
dim-order+0x40 / +0x48vector<int> base / countGetDistanceFromOrigin 中的轴访问顺序
wrap-applies+0xf0 / +0xf8vector<bool> base / bitcount哪些轴可 wrap;popcount → combo count
seam+0x108 / +0x110vector<vector<int>> base / count每轴 +K twist 偏移列表

GetDistance — cache-aware 单距离 {#getdistance--the-cache-aware-single-distance}

用途

GetDistance @ 0x20b408e0(vtable +0xb8)是 GetStaticPath 和 route emitter 调用的该几何逻辑的消费者。它返回一个距离,而不是候选集合:它首先查询嵌入的预计算 route cache,只有在逐 pair cache miss 时才回退到现场 metric(上面的 GetDistances / GetDistanceFromOrigin 机制)。这里仅在边界处记录它——cache 机制位于 toroidal-route-cache,路径打包位于 get-static-path

算法

c
function GetDistance(this, src, dst):                    // 0x20b408e0, vtable+0xb8
    if this->cache_enabled:                               // BYTE[this+0xe0]==1 (0x20b40900)
        r = GetDistanceFromCache(src, dst)                // 0x20b40fa0 — embedded ToroidalRouteCache
        if r is ok:  return r                             // cache HIT → cached distance, done
        // per-pair cache MISS: fall through to the live metric (0x20b40922)
    if this->alt_cache_ptr && this->nK_valid:             // [this+0x120]!=0 && BYTE[this+0x134] (0x20b40968)
        // k*2k*nk shape: drop the nK axis, compute on the reduced 3-D twist
        src' = DropDimnesion(src, this->nK_dim)           // [this+0x130] (0x20b40988)
        dst' = DropDimnesion(dst, this->nK_dim)
        ...compute on the reduced coordinates...
    return  the single twisted-torus distance (the GetDistances min-norm route)

注意 — 逐 pair cache-miss 回落到现场 metric 的结构已逐字节确认:GetDistanceFromCache0x20b40fa0)返回后,GetDistance 会根据 StatusOr ok-bit 分支(0x20b40922),并在查找 ok 时继续到 LABEL_8——现场计算。这不同于 InitRouteSolution 中的整体 cache miss,后者会以 "Cannot find route cache: " 硬错误退出,且没有现场 fallback(见 toroidal-route-cache)。单个缺失的 (src,dst) pair 会降级到现场 metric;slice shape 缺失的 baked cache 文件会中止 bring-up。置信度:HIGH(fall-through 分支逐字节确认;内联 live-recompute 函数体已追踪到该分支,但没有逐行解码每种 cache 类型)。

陷阱 — DropDimnesion 拼写(一个字母转置)是二进制中的真实符号(accel_ssw::deepsea::slice_builder::(anonymous namespace)::DropDimnesion @ 0x20b3f4e0,调用于 0x20b40999)。请按原样 grep;不要“修正”它。


与消费者的关系

组件从这里取得什么页面
GetStaticPathGetDistance(vtable +0xb8)、单条 min-norm 距离,然后打包 hopsget-static-path
RandomizedToroidalWildFirstPathstorus-reduced 距离,然后执行避障多路径搜索randomized-toroidal-wildfirst
twist tiebreaker|GetDistances result| 作为 corner/edge/mid vertex classtwist/get-tiebreak
route cache每个 (src,dst) chip-id pair 存储的 distance-vector 值toroidal-route-cache

GetDistances 产生集合;消费者各自按不同策略把它约化为一条路由:确定性 DOR(GetStaticPath)、避障搜索(WildFirst),或预计算查找(cache)。seam-and-wrap 数学由三者共享;只有选择策略不同。

交叉引用

  • 路由概览 — 此距离 metric 播种的 route-generation → cache → emission 流水线(阶段 1)
  • Get Static Path — 确定性单路径消费者;调用 GetDistance(vtable +0xb8)并打包 DirectionHops
  • Randomized Toroidal WildFirst — 同一 torus 距离的避障多路径消费者
  • Toroidal Route CacheGetDistance 在回退到此现场 metric 前读取的预计算 cache
  • Create Routing Schedule — 正交的 net_router 每步骤 DMA 调度(不同于这里的 auto-route 距离)
  • Twisted Torus — twist 几何;seam table 编码的 (+K,+K) 折叠,以及消费 |GetDistances| 的 tiebreaker