iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0
Software Development

在 AI Compiler 工程師的路上系列 第 31

Day30:複習 Tenstorrent、TT-Metal、TT-MLIR、Triton Flow、TileLoom

  • 分享至 

  • xImage
  •  

Tenstorrent 這九天終於走完了。從 Tenstorrent 硬體架構開始複習,接著看 TT-Metal 程式模型和 TT-MLIR compiler stack,再比較 Triton 到不同 NPU 的 lowering flow。最後用 TileLoom paper 和 matmul IR 把 Triton on Tenstorrent 的路線走一次。

本篇大綱

  • 複習這九天的內容與可以帶著走的讀法
  • 最後整理三種硬體分別把哪些最佳化責任交給 AI compiler

Day21:Tenstorrent 架構

https://ithelp.ithome.com.tw/upload/images/20260830/20183319ydK42Eb3cn.png

Day21 從 WormholeB0 README 開始。 Wormhole ASIC 由多種 tile 組成

Tensix tile 負責 compute,DRAM tile 是 GDDR6 的入口,Ethernet tile 連線到其他 ASIC,PCIe tile 接 host,ARC tile 管理晶片與板卡。Wormhole 有兩套方向相反的 NoC,把這些節點接成 2D torus。

這裡的 tile 有兩種意思

  • Hardware tile:NoC grid 上的一個座標與硬體節點,例如 Tensix、DRAM、Ethernet、PCIe、ARC tile。
  • Tensor tile:被搬移與運算的資料區塊,最常見的形狀是 32×32 elements。一顆 Tensix hardware tile 會反覆處理許多 tensor tiles。

Wormhole 的五種 hardware tile 分工也不一樣

Hardware tile 數量與角色 讀程式時要找什麼
Tensix 80 個實體 tile;產品實際開放數量可能不同 本地 L1、data movement core、Unpack/Math/Pack、Matrix/Vector/Scalar Unit
DRAM 18 個 NoC 入口,共同連到 12 GiB GDDR6 DRAM bank、來源座標、DRAM → L1 搬移
Ethernet 16 個 100 GbE 節點 晶片內 NoC 如何連線到多 ASIC fabric
PCIe 1 個 PCIe 4.0 x16 host interface Host command 與 host-to-device traffic 從哪裡進入
ARC 1 個管理節點 初始化、監控與板卡管理;不執行使用者 kernel

Tensix tile 裡還可以再拆。Wormhole 每顆 Tensix 有 1464 KiB 本地 L1、五個 Baby RISC-V core、兩個 unpacker、Matrix Unit、Vector Unit、Scalar Unit 與四個 packer。Baby RISC-V core 負責控制資料搬移及派送工作,主要矩陣與向量吞吐量來自 Tensix coprocessor。

所以看 NoC layout 時,先認節點種類,再沿著來源與目的座標追資料,tensor tile 從哪個 DRAM tile 出發、進到哪顆 Tensix 的 L1、是否送給一列或一欄 cores,最後又從哪裡寫回。這些問題會變成 reader/writer kernel,在 TileLoom 則變成 placement、broadcast 與 reuse 規劃。

Day22:TT-Metal

https://ithelp.ithome.com.tw/upload/images/20260830/20183319ohvb3AEoYa.png
這天先介紹 Tenstorrent software stack

TT-Forge / TT-NN / TT-Lang
  ↓
TT-Metalium / TT-Metal
  ↓
TT-LLK / Tensix instruction level

接著看 TT-Metal / Metalium,重要的三種 kernel: reader kernel、compute kernel、writer kernel

Reader 把資料從 DRAM 搬進 circular buffer。Compute 等 buffer 有資料,做 tile operation。Writer 等 output buffer 有結果,再寫回目標位置。

Circular buffer 同時是 producer-consumer queue 和同步契約。cb_reserve_backcb_push_backcb_wait_frontcb_pop_front 這些 API 會把資料流的正確性建立起來。

看這張圖時,可以跟著一個 tensor tile 走。Reader 先對 input CB 保留空間,發出非同步 NoC read,等 barrier 確認傳輸完成後才 push;compute 等到 input CB 有資料後執行 tile operation,再把結果 pack 到 output CB;writer 最後等 output tile 就緒,經 NoC 寫回 DRAM。

Host 與 device 兩側也要分開。Host 建立 buffer、circular buffer、kernel 與 program,設定 runtime arguments,再將 program 排進 command queue。Reader、compute、writer 是 device kernels,使用 L1 裡的 circular buffer 狀態協調進度。

檢查可以核對 producer 與 consumer:每個 reserve 後面有沒有 push,每個 wait 後面有沒有 pop,非同步 NoC operation 是否在公布資料前完成。少掉其中一步,程式可能卡住,也可能讓 consumer 讀到尚未完成的資料。

Day23:TT-MLIR

https://ithelp.ithome.com.tw/upload/images/20260830/20183319XWM7vV4wJN.png

TT-MLIR 建在 MLIR 之上,定義 Tenstorrent 專用的 dialect 和 transformation pass。目前文件展示 TTIR 可分流到 TTNN runtime pipeline,也有 D2M、TTKernel 與 TTMetal 這條更低階路徑。這個版本的 project-structure 文件仍將 TTMetal runtime namespace 標示為 not implemented,FlatBuffers 文件也將 .ttb 標示為 unsupported。

這層把前一天看到的 TT-Metal 程式模型,接到更上層的 model 和 compiler frontend

front-end dialect / model
-> TT-MLIR TTIR
   ├─> TTNN dialect
   │   -> TTNN FlatBuffer / runtime
   └─> D2M
       -> TTKernel + TTMetal dialect

每個 dialect 保存的資訊不同。ttir 還像 tensor compute graph;ttnn 加入 physical tile、memory space、layout 與 tensor lifetime,d2m 展開 grid、iterator、circular buffer 與 data movement;ttkernel 出現 reader/compute/writer 的同步和 tile instruction,ttmetal 則描述 host buffer、kernel configuration 與 program dispatch。

因此讀 lowering 不只看 operation 名稱有沒有改。更值得問的是 tensor shape 是否維持、logical layout 何時變成 physical layout、buffer lifetime 在哪一層出現,以及 device kernel 與 host program 是從哪個 pass 開始分開。這些資訊能幫忙判斷錯誤應該停在高階 tensor 語意、memory layout,還是 runtime 邊界。

這裡也保留版本限制。TTNN FlatBuffer/runtime 路徑與較低階的 D2M 路徑需要分別核對公開 artifact 與支援狀態,本文核對的 TT-MLIR 文件仍將 .ttb 與部分 TTMetal runtime support 標示為未完成。

Day24:Triton NPU Flow

https://ithelp.ithome.com.tw/upload/images/20260830/20183319B0F599mvR9.png

把六條 flow 放在一起看

Triton-Tenstorrent TTMLIR
TileLoom
Triton-Ascend
Triton-XDNA
Hexagon-MLIR
Triton-MTIA

有些 flow 保留 TTIR / TTGIR 後接硬體 dialect,有些 flow 經由 triton-shared 轉成 affine / linalg / scf / memref,再進 backend-specific compiler。

TileLoom 屬於後者

Triton
-> TTIR
-> triton-shared
-> affine / linalg / scf / memref
-> TileLoom dataflow-aware MLIR
-> TT-Metalium C API

這條線很適合研究,因為每個階段都有 IR 可以看

比較六條 flow 時,可以先找 bridge 插入的位置。triton-shared 會把可辨識的 Triton block 與 pointer pattern 轉成 affinelinalgscfmemref 等通用 MLIR,後端再補上各自的 core array、local memory、DMA/NoC、vector 或 matrix unit 資訊。

讀一條新的 NPU flow 時,我會依序找四種 artifact,Triton dialect 在哪裡結束、通用 MLIR 保留哪些存取關係、硬體 dialect 何時加入 placement 與 memory space,以及最後由哪個 runtime 載入與啟動。若 pointer analysis 只能處理 strided/affine pattern,原本合法的 Triton kernel 也未必能走完這條 lowering。

Day25:Tile language 到 spatial accelerator 的 compiler 缺口

https://ithelp.ithome.com.tw/upload/images/20260830/20183319O4pOSlTscl.png

TileLoom paper 的問題設定是 spatial dataflow accelerator 的 programmability。Tile language 已能描述單一 tile 的運算,整張 logical grid 如何放到有限的 physical cores,仍需要規劃 placement、execution waves、reuse 與 communication。

這類硬體有 local memory、NoC 與 core grid,可以減少 DRAM 往返。效能會受到幾個互相牽動的決策影響

  • logical tile 要放在哪個 core?
  • 哪些資料可以 broadcast 或 temporal reuse?
  • local memory 是否放得下要保留的 tiles?
  • 哪個 mapping 會造成 NoC congestion 或 core idle?

TileLoom 接收 tile kernel 與 architecture representation,產生多個 dataflow candidates。這天的複習重點是 compiler 缺口:單一 tile 的 compute lowering,還不足以解決整張 spatial core grid 的資料流。

用 matmul 想最容易。C[m,n] 的 logical grid 可能大於實體 8×8 core mesh,所以同一批 cores 要分成多個 temporal waves。每個 candidate 都要回答 (m,n,k) 哪些軸放到 core grid、waves 用什麼順序執行、A/B tiles 是否能跨 core 共用,以及 L1 是否裝得下需要保留的資料。

TileLoom 的輸入因此有兩部分:tile program 提供運算與 affine memory access,architecture representation 提供 core、memory、interconnect、capacity、bandwidth 與 compute resource。輸出的 dataflow plan 包含 kernel body、placement、execution order、buffer 與 communication 決策。

如果只驗證單顆 core 上的 matmul 能算對,仍沒有回答整張 logical grid 是否會讓部分 cores 閒置、讓多筆 traffic 擠在同一條 NoC link,或重複從 DRAM 載入原本可共用的 tile。

Day26:mapping、reuse、performance model 與實驗證據

https://ithelp.ithome.com.tw/upload/images/20260830/201833198hqUYsX5CB.png

Day26 把 TileLoom 的 planning pipeline 拆開

Spatiotemporal mapping
  → Reuse analysis
  → Data movement planning
  → Performance model
  → Top-k candidates
  → optional hardware profiling

Spatial mapping 決定 logical axis 如何對應 core grid;temporal mapping 安排同一組 cores 先後處理哪些 waves。Reuse analysis 從 affine access dependency 判斷 spatial/temporal reuse,再將機會落成 broadcast、load hoisting 與 buffer lifetime。Performance model 把 compute、memory 與 NoC cost 放在一起估計,用來排序 candidates。

Paper 的實驗也提醒我讀數字要連同條件一起看。FlashAttention 有明顯 reuse,Flash Decode 的 query length = 1 讓可用 parallelism 變少;GEMM 接近 vendor library;Mamba Chunk Scan 的 baseline 是 unfused implementation。模型的用途是 candidate ranking,論文也保留 optional profiling 處理錯排,不能把估計值當成 cycle-accurate simulation。

Reuse analysis 的判斷可以直接從 index dependency 讀。某個 access 不依賴 spatial index,表示沿該軸的 cores 會使用相同 tile,可能轉成 NoC broadcast;不依賴 temporal loop variable,表示不同 waves 可重用同一份資料,load 可以 hoist,但 buffer lifetime 也會變長。

Performance model 會估計 compute、DRAM、local memory 與 NoC cost,也要考慮 load/compute/store 能否重疊。它的工作是縮小候選集合,之後可對 top-k 做硬體 profiling。這和「模型精確預測每一個 cycle」是不同的驗證目標。

Day27:舊 pipeline 00~02,讓 memory access 顯式化

https://ithelp.ithome.com.tw/upload/images/20260830/20183319uSlVsRRNOB.png

Day27 開始閱讀舊 loom-dataflow standalone pipeline 的 committed artifact

00 frontend
  affine.parallel + scf.for + linalg.matmul

01 tensor canonicalized
  統一 destination 與 Loom bufferization bridge

02 explicit memory access
  加入 L1 allocation、DRAM/L1 copy 與 semaphore

這三步先保留 matmul 的 M/N/K 與計算語意,再讓 buffer、copy 與同步操作成為 IR 的一部分。比較前後 IR 時要核對 shape、offset 與 load/store 方向,避免 memory rewrite 改壞原始計算。

00_from_helion_frontend.mlir 先找 affine.parallel、K loop 與 linalg.matmul01_tensor_canonicalized.mlir 檢查 destination handoff 與 proxy copy;02_explicit_memory_access.mlir 再找 loom.allocloom.semaphore_take/give、DRAM ↔ L1 的 loom.copy

SSA 編號變動本身沒有獨立意義。這裡要關注 operation 的 operand 來源、tensor/memref shape、subview offset、memory space、copy 方向與 buffer lifetime。尤其 semaphore_take/give 在這層描述資源生命週期,還不能直接解讀成最終硬體 semaphore 指令。

Day28:舊 pipeline 03~05,從 mapping 找到 broadcast

https://ithelp.ithome.com.tw/upload/images/20260830/20183319Vchx4ojIEl.png

03 hardware mapping
  logical loops → 8×8 mesh,展開 16 個 mapping candidates

04 reuse analysis
  檢查 subview access 不依賴哪些 spatial/temporal indices

05 enumerate broadcast
  loom.copy 開始帶有 area 與 region

A[m,k] 不依賴 nB[k,n] 不依賴 m,所以兩者可能沿不同 mesh 方向共用。Step 6 再從 05 產生 staged ETG constraint JSON。

03_hardware_mapping.mlir 會把 logical loops 放到 8×8 mesh;這組 dump 展開 16 個 mapping candidates。數量增加代表列舉不同 spatial/temporal 對應,尚未代表 solver 已選出最佳方案。

到了 04_reuse_analysis.mlir,重點是 subview 的 affine offset 依賴哪些 induction variables。05_enumerate_broadcast.mlir 再把分析結果寫回 loom.copyarea : [8, 1] 描述接收區域大小,ULLR 則給出該區域在 mesh 上的座標範圍。這讓A 沿一軸共用、B 沿另一軸共用成為可檢查的 IR attribute。

Step 6 產生 staged ETG,供 constraint model 使用,裡面保存 task、dependency、symbol 與限制條件。Program MLIR 不會因為產生 JSON 就自動取得具體 block sizes;要看到 resolved ETG 或 solver assignment,才能往下聲稱候選已被求解。

Day27~Day29 使用的 2026-07-31 舊 run_pipeline.sh 到 Step 6 只輸出 staged ETG,沒有接著執行 MLAR resolution 或 CP-SAT。這組舊 artifact 不能用來證明 solver 已選出 block sizes。

Day29:舊 pipeline 06~08,pass 形狀與 artifact 健全性

https://ithelp.ithome.com.tw/upload/images/20260830/20183319VCTQJeYhGC.png

06 materialize + canonicalize + BridgeToOSB
  symbol → fixed shape
  loom.subview → memref.reinterpret_cast

07 One-Shot Bufferization
  tensor SSA dataflow → memref in-place dataflow

08 TT opt
  zero-filled linalg.matmul pattern → loom.matmul

舊 Step 7 沒有讀取 resolved ETG 或 solver assignment,而是觸發 {64,64,512} placeholder。當中的 tile_k=512 超過原始範例 K=256,constraint JSON 的 problem size 也和 00 對不上。這組 artifact 適合學習 pass 形狀,不能視為已由 CP-SAT 求解並驗證可安全執行的設定。

final.mlir 是獨立硬體模型,與 08_tt-opt.mlir 沒有 lowering 關係。08 也尚未展示 TTKernel/TT-Metal code、host launch 或裝置數值驗證,因此應稱為 backend-oriented Loom IR。

Materialize 的工作是把 tile symbol 代入具體整數,接著 canonicalizer 折疊常數、SymbolDCE 清掉不再使用的 symbol,BridgeToOSB 則把多維 subview offset 線性化成 memref.reinterpret_cast 可以表達的形式。這一步一旦代入錯誤尺寸,後面的 bufferization 仍可能產生形式上完整的 IR,所以 tile bound 必須在這裡另外檢查。

One-Shot Bufferization 將 tensor SSA dataflow 轉成 memref in-place dataflow。閱讀 06 → 07 時應追 alias、讀寫對象與 buffer lifetime,不能用檔案行數變少推論 candidate selection。08 的 TT opt 再辨認 zero-filled linalg.matmul pattern,改寫成 loom.matmul,先前的 copy 與 semaphore operations 仍留在周圍。

如果要稱為端到端執行證據,後面至少還要看到實際 TT-Metal kernel source、circular buffer configuration、NoC command、kernel binary、host launch,以及裝置上的數值與效能結果。這組舊 dump 沒有提供這些 artifact。

截至本文核對的新版 oom@f65d199b,monorepo 的完整 run_pipeline() 才會串接 exploration、MLAR resolution、CP-SAT 與 materialization。

CPU、GPU、Tenstorrent 三種最佳化路線

回顧這三十天,CPU、GPU、Tenstorrent 都在執行 tensor operator。差別不只在核心數量,也在硬體把哪些資源與決策暴露給 compiler。

問題 RISC-V CPU NVIDIA GPU Tenstorrent ASIC
工作如何分割 loop iteration、thread、RVV vector grid、CTA、warp、lane logical tile、Tensix core coordinate、temporal wave
鄰近計算的儲存 register、L1/L2 cache register、shared memory、L1/L2 每顆 Tensix core 的 L1
矩陣運算 scalar/RVV kernel Tensor Core MMA Tensix Matrix Unit
資料搬移 load/store、cache hierarchy global ↔ shared、coalescing、async copy/TMA DRAM ↔ L1、L1 ↔ L1、NoC broadcast
常見效能限制 vector utilization、cache miss、memory bandwidth occupancy、register/shared-memory pressure、layout conversion、HBM traffic L1 capacity、core utilization、NoC traffic、placement
本系列 compiler 路徑 PyTorch → Inductor → C++/RVV Triton → TTIR/TTGIR → LLVM/PTX/SASS Triton/Helion → TileLoom MLIR → mapping/reuse/broadcast

CPU:從 loop 找出向量工作

CPU 版本最常從巢狀 loop 開始

M/N/K blocking
  → strip-mining
  → vsetvl
  → RVV load / multiply-accumulate / store

TorchInductor RVV 的工作,是讓一般 F.linear 經過 graph lowering、shape gate 與 codegen,走到合適的 RVV microkernel。Compiler 主要處理 loop、vector width、register use、packed weight 與 cache-friendly layout。

GPU:從 tensor tile 決定 CTA、warp 與 lane

Triton matmul 先描述某個 program instance 負責的 output tile,NVIDIA backend 再決定

program id
  → CTA tile
  → warp/lane layout
  → global memory pointer
  → shared-memory staging
  → MMA instruction

Day14~Day19 實際看到這條線的證據

Python specialization
  → TTIR:tile-level 計算與 pointer/mask
  → TTGIR:CTA/warp/lane layout、shared memory、MMA
  → LLVM IR/NVVM:address space、intrinsic
  → PTX:virtual ISA
  → cubin/SASS:實際機器碼
  → CUDA Driver API:launch

GPU compiler 不只做大量 thread 平行化,它還要選 shared-memory layout、安排 async copy 或 TMA、插入 barrier,並在 register、shared memory 與 occupancy 之間取捨。

Tenstorrent:把 tile 放上 2D core grid

Tenstorrent 接續 tile-based program,新增 spatial dataflow 的問題

logical M/N/K tile
  → Tensix (x, y) placement
  → DRAM/L1 buffer
  → NoC0/NoC1、傳輸端點與 broadcast region
  → per-core compute
  → writeback

A tile 若被同一列 output core 共用,可以沿一個方向 broadcast,B tile 則可能沿另一個方向傳送。TileLoom 會列舉 mapping、分析 subview offset dependency,再把 reuse 改寫成 loom.copyarearegion

GPU 與 Tenstorrent 的共同點和分界

兩者都大量使用 tile,也都努力讓資料停留在靠近運算單元的記憶體。GPU 的 kernel 會控制 CTA 內 shared memory、warp layout 與 pipeline,CTA 到 SM 的派發則由 GPU scheduler 處理。Tenstorrent 讓程式更直接地面對 Tensix core 的 (x, y) 座標、各 core 的 L1,以及跨 core NoC 傳輸。

用 compiler IR 來看,它們要求 compiler 規劃的座標系與資料搬移介面不同。

NVIDIA TTGIR:
  tensor element 屬於哪個 CTA / warp / lane?
  shared-memory encoding 和 MMA encoding 是什麼?

TileLoom IR:
  logical loop 映射到哪個 physical dimension?
  copy 的接收 area / region 是什麼?
  subview 有沒有 spatial / temporal reuse?

謝謝大家看到這裡,下一篇會是最後的結尾。

參考資料


上一篇
Day29:Loom-dataflow:Materialize、One-Shot Bufferization 和 TT opt
下一篇
終結與開始的序言——在 AI compiler 工程師的路上
系列文
在 AI Compiler 工程師的路上32
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言