CHAPTER 41 / Tenstorrent · 显式数据流

Tensix 与 tiles:先安排数据,再安排计算

一张小矩阵怎样变成可分配的 tile 工作?

阅读与推演约 55 分钟练习时间另计

这一章要弄清楚

  • 区分数学矩阵与物理布局
  • 说明Tensix控制和计算单元的分工
  • 计算padding与tile数量

先备知识:CPU cache、缓存一致性与 SIMD / 并行分解、分块与负载均衡 / Tensor shape、stride 与 GEMM 分块

C++20 本机逻辑模型;不是设备仿真或性能测量。厂商语法片段未在设备或 SDK 执行,实际 API 以匹配版本的公开文档为准。

Tile 是数据分块,不是新的数学运算

矩阵加法仍是对应元素相加。Tile把矩阵切成适合处理的小块,改变的是存储与工作安排,不改变数学定义。为了能手算,例一用二乘二的教学tile;Tenstorrent常见计算布局以三十二乘三十二tile为基础,具体支持形状、数据格式和API限制需查目标版本。二乘二模型没有模拟实际tile内部编码。

Tensix可以先理解成芯片上具有本地存储、控制和专用计算能力的节点。公开架构资料区分RISC-V控制处理器、矩阵/向量计算引擎、数据打包拆包和NoC通信。不要把控制代码中一个普通for循环想成矩阵单元所有计算;控制处理器可以向专用引擎发出工作,数据还需按相应格式准备。

从行主序到tile顺序

考虑四乘四矩阵,按行写入零到十五。若按二乘二tile打包,左上tile为0、1、4、5,右上tile为2、3、6、7,随后是下面两块。这里最重要的不是背下排列,而是先确定tile坐标,再确定tile内部坐标,最后回到原矩阵的行列索引。例一同时做打包和还原,验证每个位置都回到原处。

相同的一串字节,如果用不同shape或layout解释,可能产生完全不同的矩阵。输出总和相等也无法发现转置或错位,所以测试应检查每个元素,使用像0到15这样能辨认位置的输入。全部填一虽然方便,却很容易掩盖索引错误。

边缘数据需要padding合同

若逻辑矩阵是三十三乘三十三,使用三十二边长的tile网格需要二乘二共四块,物理覆盖六十四乘六十四。逻辑元素只有一千零八十九,覆盖区有四千零九十六个位置。二者差异影响存储开销,也提醒你最后一块存在无效元素。例二只计算这两个数量,没有声称某个产品必须按这个方式分配所有内存。

Padding值取决于操作。加法或求和常可使用零;max、softmax、归一化等操作需要更认真处理无效位置。最终回读也必须恢复逻辑shape,不能把物理padding当用户结果。逻辑维度、物理维度、dtype和layout应一起成为接口合同。

本地存储不是无限缓存

把输入搬到本地SRAM可以增加复用,但空间要同时容纳输入块、输出块、中间结果、通信缓冲以及程序所需资源。给每个buffer多放几块tile,也许便于流水,却可能减少同时驻留的其他工作。这里需要预算,不是简单认为buffer越大越快。

面试讨论“GPU思路如何迁移”时,可以迁移分块、复用、数值验证和测量方法,但不能把CUDA线程块直接等同Tensix core。两种模型暴露的执行和数据移动控制不同。先说共同的数学问题,再说各自如何组织资源,能避免把名词机械替换。

一个有效的阅读顺序

先用C++完成二维索引与打包回环,再读Tensix架构和公开编程模型,最后看真实tile数据类型及kernel API。暂时没有设备时,本章可验收索引、shape和内存预算的推理;专用引擎数值、NoC传输与设备性能则仍未验证。架构代际的核数、本地存储容量和支持格式不应从单一旧图推广到所有产品。

动手改变 · 观察因果

保持矩阵坐标,改变 tile 存储顺序

所选坐标进入哪个 tile?打包后在线性存储的哪里?

4×4 逻辑矩阵,教学 tile 边长可选 1、2、4。这不是 Tensix 指令模拟,也不声明产品支持这些硬件 tile。 对应 例题 37-a;图中的代码行是步骤提示,完整可编译源码见例题。

改输入后从第一步重新推演。Tab 选择控件,Enter/空格操作按钮;图内方向键平移,手机可横向滑动。

正在准备默认算例。下方例题包含完整源码与逐步解释。

第 1 步

先预测,再前进一步

所选坐标进入哪个 tile?打包后在线性存储的哪里?

输入、边界、状态变化

完整文字推演与当前数据
    静态推演与完整文字(便于对照、打印)
    观察 · 推演

    tile 数值的文字摘要(矩阵坐标见上方实验)

    row00 1 2 3row14 5 6 7row28 9 10 11row312 13 14 1501 / 03 · TILESrow00 1 2 3row14 5 6 7row28 9 10 11row312 13 14 1501 / 03 · TILES
    逻辑矩阵

    输入按行存储。

    1 / 3
    阅读完整推演文字
    1. 逻辑矩阵

      row0:0 1 2 3;row1:4 5 6 7;row2:8 9 10 11;row3:12 13 14 15

      输入按行存储。

    2. 上半两块

      tile0:0 1 4 5;tile1:2 3 6 7

      每块取两行两列。

    3. 下半两块

      tile2:8 9 12 13;tile3:10 11 14 15

      逆变换应还原每个坐标。

    跟着例子,走完一遍

    例题 01C++20 · 本机可运行

    四乘四矩阵的tile打包回环

    行主序0–15,教学tile边长2。

    1. 按tile行列遍历
    2. 每块内部按行复制
    3. 逆变换并逐元素比较
    37-a.cpp
    下载
    // Original CPU teaching model; not a device simulator or benchmark.
    #include <iostream>
    #include <vector>
    #include <stdexcept>
    
    void require(bool ok) { if (!ok) throw std::runtime_error("model check failed"); }
    
    int main() {
     std::vector<int> source(16),packed,restored(16);
     for(int i=0;i<16;++i) source[static_cast<std::size_t>(i)]=i;
     for(int tr=0;tr<2;++tr) for(int tc=0;tc<2;++tc)
      for(int r=0;r<2;++r) for(int c=0;c<2;++c)
       packed.push_back(source[static_cast<std::size_t>((tr*2+r)*4+tc*2+c)]);
     std::size_t k=0;
     for(int tr=0;tr<2;++tr) for(int tc=0;tc<2;++tc)
      for(int r=0;r<2;++r) for(int c=0;c<2;++c)
       restored[static_cast<std::size_t>((tr*2+r)*4+tc*2+c)]=packed[k++];
     require(source==restored);
     std::cout<<"first_tile="<<packed[0]<<' '<<packed[1]<<' '<<packed[2]<<' '<<packed[3]<<" roundtrip=ok\n";
    }
    

    如何编译和运行下载的 .cpp 文件 →

    结果与解释

    第一tile=0 1 4 5;回环成功。

    空间分块改变存储顺序,未改变坐标含义。

    在本机运行这个例子

    下载后,在文件所在目录执行。需要支持 C++20 的编译器;POSIX 示例还需要章节说明中的系统条件。

    clang++ -std=c++20 -Wall -Wextra -Wpedantic -Werror -pthread 37-a.cpp -o example && ./example

    预期标准输出:

    first_tile=0 1 4 5 roundtrip=ok
    
    例题 02C++20 · 本机可运行

    边缘tile的逻辑与覆盖数量

    逻辑33×33,教学覆盖tile32×32。

    1. 每维向上取整为2块
    2. 覆盖64×64
    3. 比较逻辑与覆盖数量
    37-b.cpp
    下载
    // Original CPU teaching model; not a device simulator or benchmark.
    #include <iostream>
    #include <stdexcept>
    
    void require(bool ok) { if (!ok) throw std::runtime_error("model check failed"); }
    
    int main() {
     constexpr int rows=33,cols=33,tile=32;
     const int tr=(rows+tile-1)/tile, tc=(cols+tile-1)/tile;
     const int logical=rows*cols, covered=tr*tc*tile*tile;
     require(tr*tc==4 && logical==1089 && covered==4096);
     std::cout<<"tiles="<<tr*tc<<" logical="<<logical<<" covered="<<covered<<'\n';
    }
    
    结果与解释

    4 tiles,1089 logical,4096 covered。

    只计算布局开销,不断言具体产品分配策略。

    在本机运行这个例子

    下载后,在文件所在目录执行。需要支持 C++20 的编译器;POSIX 示例还需要章节说明中的系统条件。

    clang++ -std=c++20 -Wall -Wextra -Wpedantic -Werror -pthread 37-b.cpp -o example && ./example

    预期标准输出:

    tiles=4 logical=1089 covered=4096
    
    常见错误

    把物理shape当逻辑shape

    把padding位置一起输出或用于非中性运算。

    修正思路:分别保存逻辑维度与布局维度,选择正确padding并裁剪。

    轮到你动手

    先写预测或代码,再按需打开提示。完整答案用于对照自己的推理。

    练习 1

    三乘三矩阵0–8按2×2教学tile补零,写左下tile。

    给我一点提示
    1. 左下从第2行第0列开始
    2. 超出逻辑行填零
    查看答案与推理

    左下块为6、7、0、0;右下为8、0、0、0。回读需裁回3×3,不能把padding拼进逻辑结果。

    练习 2

    三个buffer分别2、2、1个tile,每tile2048字节,最低数据空间多少?

    给我一点提示
    1. 先加tile数
    2. 程序与额外资源另计
    查看答案与推理

    数据buffer合计5×2048=10240字节。这只是给定buffer的预算,不是整个kernel的SRAM需求;还需计入其他中间存储和实现资源。

    把理解说出来

    先用中文讲清因果,再用英文回答。问题依据技能主题编写,并非公司内部题库。

    解释

    tile化会改变矩阵加法定义吗?

    参考回答 / English answer

    不改变有效坐标的数学结果,但改变存储、padding和工作分配。

    Tiling changes layout and scheduling, not the logical elementwise operation. Padding still needs an explicit contract.
    调试

    为什么全部填一不是好的layout测试?

    参考回答 / English answer

    错序仍全部为一,可能假通过;应使用坐标可辨识值并逐元素检查。

    Uniform data can hide permutations. I use coordinate-dependent values and compare every element.
    预测

    33×33使用32×32覆盖tile,为什么是四块?

    参考回答 / English answer

    每一维都需两块,二维乘积为四,不是总元素数简单除1024。

    Each dimension requires two tiles. The two-dimensional grid therefore contains four tiles.
    解释

    RISC-V控制处理器就是矩阵计算引擎吗?

    参考回答 / English answer

    不是。控制与专用计算分工不同,需理解指令派发和数据准备。

    Control processors and specialized compute engines have different roles. Control code orchestrates work rather than replacing the matrix engine.
    追问

    buffer容量加倍总会更快吗?

    参考回答 / English answer

    不一定。占用SRAM增加,可能挤压其他驻留资源;需算预算并测量。

    Larger buffers can consume scarce local memory. I evaluate the whole resource budget and measure the effect.
    解释

    本章2×2模型能证明真实tile编码正确吗?

    参考回答 / English answer

    不能,只验证原创索引变换;真实格式需对应API和设备验证。

    The two-by-two model checks our indexing logic. It does not validate the hardware tile encoding.

    继续查证

    公开资料用于查证;本章图解和例题是独立教学内容。CPU 逻辑模型不能证明设备性能。