
CANN pto-isa 中的 TSORT32基于 VBS32 的 32 元素塊值-索引排序指令詳解【免費(fèi)下載鏈接】pto-isaParallel Tile Operation (PTO) is a virtual instruction set architecture designed by Ascend CANN, focusing on tile-level operations. This repository offers high-performance, cross-platform tile operations across Ascend platforms.項(xiàng)目地址: https://gitcode.com/cann/pto-isaPTOParallel Tile Operation虛擬指令集中的TSORT32指令用于對(duì) Tile 中每個(gè) 32 元素塊連同其索引一起做降序排序并將排序后的值-索引對(duì)寫(xiě)入目標(biāo) Tile底層由 SFU 硬件指令VBS32vbitsort支撐。本文以倉(cāng)庫(kù)中 TSORT32_zh.md 指令文檔為主體結(jié)合 A2/A3 實(shí)現(xiàn)、A5 實(shí)現(xiàn)、CPU 仿真實(shí)現(xiàn) 與 ST 測(cè)試用例完整講清該指令的數(shù)學(xué)語(yǔ)義、Tile 尺寸規(guī)則、尾部非對(duì)齊處理策略以及跨平臺(tái)實(shí)現(xiàn)差異讀完后可直接在 PTO kernel 中正確調(diào)用TSORT32并完成tmp緩沖規(guī)劃與流水線同步。指令語(yǔ)義每 32 元素塊的值-索引對(duì)排序TSORT32對(duì)src的每個(gè) 32 元素塊與idx中對(duì)應(yīng)的索引一起排序并將排序后的值-索引對(duì)寫(xiě)入dst。對(duì)每一行rsrc按獨(dú)立的 32 元素塊處理設(shè)塊b覆蓋列32b … 32b31n_b min(32, C - 32b)為其有效元素?cái)?shù)則構(gòu)成值-索引對(duì)$$ (v_k, i_k) (\mathrm{src}{r,32bk},; \mathrm{idx}{r,32bk}), \quad 0 \le k n_b $$按值降序排序輸出重排后的序列$$ [(v_{\pi(0)}, i_{\pi(0)}),; (v_{\pi(1)}, i_{\pi(1)}),; \ldots] $$其中π為該塊的排序置換值相同時(shí)索引小者優(yōu)先tie-break。兩個(gè)容易誤解的要點(diǎn)idx是輸入Tile索引隨值一起被重排不是輸出dst存儲(chǔ)的是排序后的值-索引對(duì)而非僅排序后的值。這一語(yǔ)義在 CPU 仿真實(shí)現(xiàn) 中可得到直接印證其ScoreIndexPair比較器先按分?jǐn)?shù)降序、分?jǐn)?shù)相同再按原始索引升序并使用std::stable_sort保證穩(wěn)定性與硬件的 tie-break 規(guī)則一致。硬件基礎(chǔ)VBS32vbitsortVBS32 運(yùn)行在SFU非向量流水線上。一次調(diào)用可排序repeat個(gè)連續(xù)的 32 元素塊每個(gè)塊由 32 個(gè)值 32 個(gè)索引組成void vbitsort(__ubuf__ T *dst, // 排序后的值-索引對(duì)輸出 __ubuf__ T *src0, // 每塊 32 個(gè)值 × repeat __ubuf__ uint32_t *src1, // 每塊 32 個(gè)索引 × repeat uint8_t repeat); // 32 元素塊的數(shù)量1..255repeat上限REPEAT_MAX 255打包到指令字config[63:56]塊在內(nèi)存中連續(xù)分布、步長(zhǎng)為 32 個(gè)元素塊b讀取src0[b*32 : b*3232]和src1[b*32 : b*3232]寫(xiě)入dst[b*32*coef : ...]其中coef 2float或 4half——即值-索引對(duì)的擴(kuò)展因子排序順序按值降序相同值時(shí)索引小者優(yōu)先。從源碼結(jié)構(gòu)看REPEAT_MAX與BLOCK_SIZE等常量定義在 common/constants.hpp被各平臺(tái)實(shí)現(xiàn)統(tǒng)一 includeMAX_UB_TMP 32 * 255 8160在 a2a3/TSort32.hpp 中定義它同時(shí)是單次vbitsort調(diào)用可處理元素?cái)?shù)的上限255 塊 × 32 元素。當(dāng)repeat超過(guò) 255 塊時(shí)A2/A3 實(shí)現(xiàn) 會(huì)將一行拆分為多次vbitsort調(diào)用前若干組各處理 255 塊最后一組處理余下塊。C 內(nèi)建接口接口聲明于 include/pto/common/pto_instr.hpp公共包含頭為pto/pto-inst.hpp// TSORT32 does not take wait events. Wait on events before calling it if needed. template typename DstTileData, typename SrcTileData, typename IdxTileData PTO_INST RecordEvent TSORT32(DstTileData dst, SrcTileData src, IdxTileData idx); // 角色映射 OIO1 個(gè)輸出 2 個(gè)輸入 template typename DstTileData, typename SrcTileData, typename IdxTileData, typename TmpTileData PTO_INST RecordEvent TSORT32(DstTileData dst, SrcTileData src, IdxTileData idx, TmpTileData tmp); // 角色映射 OIOI1 個(gè)輸出 3 個(gè)輸入要點(diǎn)3 參數(shù)版本要求src列數(shù) 32 對(duì)齊validCol % 32 0直接排序4 參數(shù)版本支持非 32 對(duì)齊尾部validCol % 32 ! 0通過(guò)tmp做尾部填充該指令不接受WaitEvents...參數(shù)、也不做內(nèi)部事件同步——如需同步調(diào)用者須在調(diào)用前顯式等待相關(guān) event。這在頭文件注釋中被明確寫(xiě)出也體現(xiàn)在約束表中。各平臺(tái)的底層實(shí)現(xiàn)通過(guò)MAP_INSTR_IMPL_ROLES宏分發(fā)到TSORT32_IMPLpto_instr_impl.hpp 中按目標(biāo)平臺(tái)分別 include 了pto/npu/a2a3/TSort32.hpp、pto/npu/a5/TSort32.hpp與pto/cpu/TSort32.hpp。Tile 尺寸與數(shù)據(jù)類型對(duì)于src形狀為 $R \times C$有效區(qū)域、塊大小 32Tiledtype尺寸元素?cái)?shù)說(shuō)明srchalf或float$T$$R \times C$待排序的值idxuint32_t$R \times C$或 $1 \times C$ 廣播隨值重排的索引dst$T$$R \times (2C)$ float$R \times (4C)$ half排序后的值-索引對(duì)tmp僅4參數(shù)$T$見(jiàn)下方 tmp 尺寸公式尾部填充 scratchdst擴(kuò)展因子typeCoef每個(gè)輸入元素生成一個(gè) 8 Byte 的 tuple[value (4Byte), index (4Byte)]——float的 value 占滿 4 Bytehalf的 2 Byte value 零擴(kuò)展至 4 Byte。因此dst恒為 $C \times 8$ 字節(jié)dtype每個(gè)src列對(duì)應(yīng)的dst列數(shù)dtype 單位tuple 布局字節(jié)/tuplefloat×22 個(gè) float 槽位[value_f32, index_u32]8half×44 個(gè) half 槽位[value_f16, 0x0000, index_u32]8源碼印證a2a3 實(shí)現(xiàn) 定義了FLOAT_DST_STRIDE_COEF 2與HALF_DST_STRIDE_COEF 4寫(xiě)dst時(shí)按typeCoef推進(jìn)偏移CPU 仿真 中t totalByte / sizeof(T)totalByte 8推進(jìn)輸出指針half 時(shí)還顯式寫(xiě)入一個(gè) 0 槽位與上表 tuple 布局完全一致。關(guān)于idx廣播實(shí)現(xiàn)中idxStride idx.GetValidRow() 1 ? 0 : RowStride見(jiàn) a2a3/TSort32.hpp即當(dāng)idx只有一行時(shí)行步長(zhǎng)取 0實(shí)現(xiàn) $1 \times C$ 的列廣播。約束匯總約束原因dst/srcdtype half或float須一致idxuint32_tVBS32 類型分派所有 Tile 為T(mén)ileType::Vec、BLayout::RowMajorSFU 尋址validCol % 32 03參數(shù)每塊恰為 32 個(gè)元素validCol任意4參數(shù)尾塊通過(guò)tmp填充至 32填充值為 $-\infty$repeat validCol/323參數(shù)或ceil(validCol/32)4參數(shù)VBS32 repeat 計(jì)數(shù)每次調(diào)用 ≤ 255更大的validCol拆分為多次vbitsort調(diào)用tmp4參數(shù)≥tmpSize元素見(jiàn)下方公式保存填充后的行/尾塊副本無(wú)WaitEvents.../ 無(wú)內(nèi)部 event synchronization如需同步須顯式調(diào)用這些約束在編譯期由CheckStatic以static_assert強(qiáng)制檢查見(jiàn) a2a3/TSort32.hppdst/src 必須同為half或float、idx 必須為uint32_t、三個(gè) Tile 均須TileType::Vec且行主序。違反任一條件將直接觸發(fā)編譯錯(cuò)誤。tmp尺寸公式4參數(shù)設(shè) $C$ validCol$b$ sizeof(T)字節(jié)數(shù)$G$ 32塊大小。實(shí)現(xiàn)根據(jù)整行大小是否滿足MAX_UB_TMP 8160進(jìn)行分支且閾值單位因目標(biāo)平臺(tái)而異$$ \mathrm{tmpSize} \begin{cases} \mathrm{ceil}_{G}(C) \text{A2/A3} C \le 8160 \text{元素?cái)?shù)} ;; \text{A5/950PR/950DT} C \cdot b \le 8160 \text{字節(jié)} \ G 32 \text{A2/A3} C 8160 \text{元素?cái)?shù)} ;; \text{A5} C \cdot b 8160 \text{字節(jié)} \end{cases} $$ceil_G(C) $C$ 向上取整到 32 的倍數(shù)Atlas A2/A3 訓(xùn)練/推理系列產(chǎn)品閾值單位為元素?cái)?shù)。源碼 的判斷是srcShapeBytesPerRow / sizeof(T) MAX_UB_TMP即 $C \le 8160$與 dtype 無(wú)關(guān)float、half 均為 $C \le 8160$A5Ascend 950PR/950DT閾值單位為字節(jié)。源碼 的判斷是validCol * sizeof(T) MAX_UB_TMP即 $C \cdot b \le 8160$float → $C \le 2040$half → $C \le 4080$。該閾值為pto_copy_ubuf_to_ubufMOV_UB_TO_UB的 repeat 上限 255 塊 × 32 Byte尾塊 $t C \bmod G$ 個(gè)元素末尾不完整塊擴(kuò)展至 $G$ 并以 $-\infty$ 填充Path A小行從行首整行復(fù)制到tmp然后原地填充最后 32 個(gè)元素Path B大行僅復(fù)制尾塊到tmp完整塊直接從src排序VBS32 硬件上限每次調(diào)用repeat ≤ 255塊≤ 8160 元素超過(guò) 255 塊的行拆分為多次vbitsort調(diào)用UB 布局tmp應(yīng)緊接dst之后放置32 Byte 對(duì)齊大小為ceil(C·b, 32)字節(jié)因 $b \in {2,4}$ 整除 32等價(jià)于ceil(ceil(C, 32)·b, 32)——不應(yīng)使用固定的 8KB 偏移因?yàn)?Path AA2/A3在接近閾值時(shí)對(duì) float 需要最多約 32KB$C \le 8160$ 元素 32KB。4 參數(shù)尾部處理路徑當(dāng)validCol % 32 ! 0時(shí)末尾不完整塊$t C \bmod 32$ 個(gè)元素須填充為完整的 32 元素塊后才能送入vbitsortA2/A3$C \le 8160$元素?cái)?shù) / A5$C \cdot b \le 8160$字節(jié)小行整行復(fù)制到tmp然后原地覆蓋最后 32 個(gè)元素為 $-\infty$ 填充從tmp排序整行。A2/A3 路徑用vector_dup完成填充見(jiàn) 源碼A5 路徑則通過(guò)vlds/vdup/vsts向量指令配合掩碼完成見(jiàn) 源碼A2/A3$C 8160$元素?cái)?shù) / A5$C \cdot b 8160$字節(jié)大行僅復(fù)制尾塊到tmp并填充完整塊直接從src排序僅尾塊從tmp排序。該邏輯封裝在LargeTmpBufferImpl中a2a3 版本先對(duì)前面各滿組做vbitsort(..., REPEAT_MAX)最后一組用srcTailRepeatNum - 1處理剩余滿塊再將尾塊拷入tmp、用set_vector_maskvector_dup填充 $-\infty$、最后單獨(dú)vbitsort(..., 1)。填充值$-\infty$ -(0.0/0.0)即負(fù) NaN等價(jià)于std::numeric_limitsT::lowest()落在降序排序的底部不影響有效元素的相對(duì)順序。若validCol 32 × 255行按REPEAT_MAX大小的組拆分每組通過(guò)獨(dú)立的vbitsort調(diào)用排序。平臺(tái)實(shí)現(xiàn)差異從源碼看三條執(zhí)行路徑PTO 為同一TSORT32內(nèi)建指令提供了三套實(shí)現(xiàn)理解差異有助于排查跨平臺(tái)行為A2/A3Atlas A2/A3 系列——include/pto/npu/a2a3/TSort32.hpp每個(gè)vbitsort調(diào)用后都插入pipe_barrier(PIPE_V)保證 SFU 結(jié)果在下一調(diào)用前就緒行步長(zhǎng)直接取Tile::RowStridedstStride/srcStride為編譯期常量小行閾值按元素?cái)?shù)判斷srcShapeBytesPerRow / sizeof(T) MAX_UB_TMP。A5——include/pto/npu/a5/TSort32.hpp不插入pipe_barrier(PIPE_V)流水線語(yǔ)義由編譯器/硬件保證行步長(zhǎng)按 32 Byte 對(duì)齊計(jì)算PTO_CEIL(Cols * byteSize, 32) / byteSize尾部填充改走_(dá)_VEC_SCOPE__內(nèi)的vlds/vdup/vsts向量指令且閾值按字節(jié)數(shù)判斷dst與src的行步長(zhǎng)按各自的列寬獨(dú)立向上取整到 32 字節(jié)這解釋了為何dst尺寸公式中 half 的擴(kuò)展因子是 4一個(gè) tuple 占 8 字節(jié) 4 個(gè) half。CPU 仿真——include/pto/cpu/TSort32.hpp用std::stable_sort 自定義比較器分?jǐn)?shù)降序、同分按索引升序逐塊模擬硬件行為保證 CPU 結(jié)果可作 golden reference靜態(tài)斷言比 NPU 路徑更寬松額外允許int32_t/int16_t/bfloat16_t且 4 參數(shù)版本直接復(fù)用 3 參數(shù)邏輯validCol任意值天然被std::min(sortNum, validCol - j)截?cái)酂o(wú)需顯式填充。測(cè)試用例如何在倉(cāng)庫(kù)中驗(yàn)證倉(cāng)庫(kù)為多個(gè)平臺(tái)提供了完整的 STSystem Test用例可直接編譯運(yùn)行驗(yàn)證語(yǔ)義。以 A2/A3 為例tests/npu/a2a3/src/st/testcase/tsort32/main.cpp 定義了 4 個(gè)用例恰好覆蓋了文檔的全部關(guān)鍵路徑TEST_F(TSort32Test, case1) { tsort32_test1, float(2, 32, 32); } // 32 對(duì)齊單塊 TEST_F(TSort32Test, case2) { tsort32_test2, uint16_t(4, 64, 64); } // halfuint16_t 即 f16 存儲(chǔ)雙塊 TEST_F(TSort32Test, case3) { tsort32_test3, float(1, 32 * 256, 32 * 256); } // 256 塊 REPEAT_MAX(255)驗(yàn)證分組拆分 TEST_F(TSort32Test, case4) { tsort32_test4, float(2, 13, 16); } // 非 32 對(duì)齊尾部13 列4 參數(shù) tmp對(duì)應(yīng) kernel tsort32_kernel.cpp 展示了完整的 UB 規(guī)劃與 Manual 模式同步寫(xiě)法// Tile 規(guī)劃ALIGN_C 為 32 對(duì)齊后的列寬TYPE_COEF sizeof(float)/sizeof(T) using SrcTileData TileTileType::Vec, T, ROWS_, ALIGN_C, BLayout::RowMajor, -1, -1; using IdxTileData TileTileType::Vec, uint32_t, ROWS_, ALIGN_C, BLayout::RowMajor, -1, -1; using DstTileData TileTileType::Vec, T, ROWS_, TYPE_COEF * 2 * ALIGN_C, BLayout::RowMajor, -1, -1; using TmpTileData TileTileType::Vec, T, 1, ALIGN_C, BLayout::RowMajor; TASSIGN(srcTile, 0x0); // src 0x0 TASSIGN(idxTile, 0x8000); // idx 0x800032 字節(jié)對(duì)齊偏移 TASSIGN(dstTile, 0x16000); // dst 0x16000 TASSIGN(tmpTile, 0x20000); // tmp 0x20000 TLOAD(srcTile, srcGlobal); TLOAD(idxTile, idxGlobal); TLOAD(tmpTile, tmpGlobal); #ifndef __PTO_AUTO__ set_flag(PIPE_MTE2, PIPE_V, EVENT_ID0); // Manual 模式顯式等待 MTE2 加載完成 wait_flag(PIPE_MTE2, PIPE_V, EVENT_ID0); #endif TSORT32(dstTile, srcTile, idxTile, tmpTile); // 無(wú) wait event 參數(shù) #ifndef __PTO_AUTO__ set_flag(PIPE_V, PIPE_MTE3, EVENT_ID0); // Manual 模式SFU 完成后通知 MTE3 寫(xiě)回 wait_flag(PIPE_V, PIPE_MTE3, EVENT_ID0); #endif TSTORE(dstGlobal, dstTile);注意dst的有效列數(shù)為VALID_C * TYPE_COEF * 2、分配總列數(shù)為T(mén)YPE_COEF * 2 * ALIGN_C與文檔的擴(kuò)展因子規(guī)則一致tmp分配為ceil32(C)元素測(cè)試中tmpByteSize colsAlign * typeSize也印證了 tmp 尺寸公式。A5、kirin9030、kirinDev0000、kirinX90 及 CPU 仿真均有同構(gòu)用例A5、CPU、kirin9030每個(gè)目錄都附帶gen_data.py生成數(shù)據(jù)與 golden 校驗(yàn)。匯編語(yǔ)法與示例AS Level 1SSA%dst pto.tsort32 %src, %idx : (!pto.tile..., !pto.tile...) - !pto.tile...AS Level 2DPSpto.tsort32 ins(%src, %idx : !pto.tile_buf..., !pto.tile_buf...) outs(%dst : !pto.tile_buf...)C 調(diào)用示例32 對(duì)齊與非對(duì)齊尾部#include pto/pto-inst.hpp using namespace pto; // 32 對(duì)齊每行單個(gè)塊 using SrcT TileTileType::Vec, float, 1, 32; using IdxT TileTileType::Vec, uint32_t, 1, 32; using DstT TileTileType::Vec, float, 1, 64; // 2× src 列數(shù)float SrcT src; IdxT idx; DstT dst; TSORT32(dst, src, idx); // 非 32 對(duì)齊尾部4 參數(shù) tmp using SrcT2 TileTileType::Vec, half, 1, 100; using IdxT2 TileTileType::Vec, uint32_t, 1, 100; using DstT2 TileTileType::Vec, half, 1, 400; // 4× src 列數(shù)half using TmpT TileTileType::Vec, half, 1, 128; // ≥ ceil32(100)128 TmpT tmp; TSORT32(dst2, src2, idx2, tmp);Manual 模式 ASM 形式Manual 模式下需先用pto.tassign綁定 tile 地址偏移需 32 字節(jié)對(duì)齊再發(fā)射排序指令與上文 kernel 中的TASSIGN序列一一對(duì)應(yīng)# pto.tassign %arg0, tile(0x1000) # pto.tassign %arg1, tile(0x2000) # pto.tassign %arg2, tile(0x3000) %dst pto.tsort32 %src, %idx : (!pto.tile..., !pto.tile...) - !pto.tile...小結(jié)與實(shí)踐要點(diǎn)選接口validCol % 32 0用 3 參數(shù)版本否則用 4 參數(shù)版本并預(yù)留tmp規(guī)劃 UBdst按 8 字節(jié)/元素對(duì)擴(kuò)展float ×2 列、half ×4 列tmp按tmpSize公式放置于dst之后、32 字節(jié)對(duì)齊勿用固定 8KB 偏移注意閾值單位差異A2/A3 按元素?cái)?shù)$C \le 8160$、A5 按字節(jié)數(shù)float $C \le 2040$、half $C \le 4080$走小行/大行兩條路徑顯式同步TSORT32不接收 wait eventManual 模式下須按set_flag/wait_flag在 MTE2→V、V→MTE3 邊界顯式同步Auto 模式下編譯器自動(dòng)處理驗(yàn)證手段跨平臺(tái)行為可用 cpu 仿真用例 生成 golden再用各 NPU ST 用例比對(duì)。參考路徑指令文檔docs/isa/TSORT32_zh.md、docs/isa/TSORT32.md公共聲明include/pto/common/pto_instr.hpp平臺(tái)實(shí)現(xiàn)include/pto/npu/a2a3/TSort32.hpp、include/pto/npu/a5/TSort32.hpp、include/pto/cpu/TSort32.hpp測(cè)試用例tests/npu/a2a3/src/st/testcase/tsort32/、tests/npu/a5/src/st/testcase/tsort32/、tests/cpu/st/testcase/tsort32/【免費(fèi)下載鏈接】pto-isaParallel Tile Operation (PTO) is a virtual instruction set architecture designed by Ascend CANN, focusing on tile-level operations. This repository offers high-performance, cross-platform tile operations across Ascend platforms.項(xiàng)目地址: https://gitcode.com/cann/pto-isa創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考