RM新时代|官方理财平台

算豐技術(shù)揭秘|深入學(xué)習和掌握TPU硬件架構有困難?TDB助力你快速上手!

TDB介紹

TDB(TPU DeBugger)是針對TPU-MLIR編譯出來(lái)的BModel設計的一系列調試工具集合, 可以支持對BModel反匯編、結構可視化、單步執行仿真等功能,使用方法靈活。能夠快速定位BModel與原始模型推理結果不一致的問(wèn)題,進(jìn)而修復TPU-MLIR的編譯或模型出錯點(diǎn)。

下圖是TDB工具集的框架。

TDB主要是基于Python開(kāi)發(fā)的,其核心功能模塊包括TPU架構相關(guān)的指令解析、指令運行、數據IO功能,以及通用的BModel反匯編框架及MLIR的索引機制。在此基礎上,形成了TDB調試、BModel_checker,?BModel_dis, MLIR2graph等工具。TDB目前支持的處理器包括BM1684、BM1684X。

下表是TDB工具的具體功能

本文重點(diǎn)介紹tdb.py的使用方法和實(shí)現細節。

tdb.py的使用

tdb.py提供了一個(gè)和pdb、gdb界面類(lèi)似的調試窗口,用于分析BModel運行,支持添加斷點(diǎn),單步執行,查看內存數據(修改內存數據),數據比對。相關(guān)差異可參考下圖:

進(jìn)入調試

在context_dir直接運行tdb.py即可調試當前目錄下的compilation.bmodel文件;可通過(guò)--ref_data來(lái)傳入參考數據,示例如下:

調試命令

在進(jìn)入TDB后,可以使用多個(gè)快捷命令來(lái)控制運行狀態(tài)。按下兩次tab或者鍵入 ? 獲取命令提示。

基本命令

命令 說(shuō)明
r/run 從頭執行到結束,run指令包含重新初始化
s/start 加載 bmodel 并初始化cmodel,cmodel 為單例模式,不會(huì )重復加載,只會(huì )清空內存;bmodel 每次初始化均會(huì )重新加載。
n/next 執行下一條指令,可以使用n 3來(lái)執行接下來(lái)的三條指令
c/continue 繼續執行指令
q/quit 退出
py 直接在環(huán)境中執行python命令,集成了pdb的代碼補全功能,連按兩下 tab 鍵獲取提示

插件系統

為了減少代碼的冗余程度,設計上TDB本體只負責對指令執行過(guò)程的基本控制,而額外通過(guò)插件系統對TDB的功能進(jìn)行擴展。插件提供的功能包括:

  • 在TDB執行指令的不同生命周期接收回調信息

  • 對TDB本身的指令進(jìn)行擴展

目前內置的“插件” 有 breakpoints、display、info、data-check 等,可以根據需求實(shí)現自己的TDB插件。

breakpoint

breakpoint插件用于實(shí)現斷點(diǎn)功能,在設計之初就考慮了可以通過(guò)多種形式添加斷點(diǎn),包括指令名、指令地址、指令id、mlir的Operation名、value-id、location...等,同時(shí)可以根據需求靈活建立斷點(diǎn)。

命令 介紹 示例
b/break 添加斷點(diǎn),具體查看下方的 b %1
enable num 允許在index為num 的斷點(diǎn)停下 enable 1 ?
enable 1,2,3
disable num 停止使用index為num的斷點(diǎn) disable 1
disable 1,2,3
delete 刪除斷點(diǎn) delete 1
info b 查看斷點(diǎn)信息 info b

目前支持的斷點(diǎn)類(lèi)型包括:

斷點(diǎn)類(lèi)型名稱(chēng) 斷點(diǎn)命令使用示例 斷點(diǎn)來(lái)源說(shuō)明
asm-name b dma.tensor
b arith.cast
解析出的asm的指令名稱(chēng),如:
%R8, %B2420 = "arith.cast"(%R0, %D288) {round_mode = 1} : (memref<16x64x1x512xf16, strides: [512, 512, 512, 1]>, none) -> (memref<16x64x1x512xf32, strides: [512, 512, 512, 1]>, none)
address b R0
b G33386496
解析出的asm的 memref,如:
%G33386496, %D293 = "dma.matrix"(%R8, %B2422) {decompress = False} ...
目前對Local Memory僅支持offset,不支持通過(guò) NPU_OFFSET 等進(jìn)行索引
cmd-id b B23
b D465
解析出的 asm 的 cmd_id,如:
%R0, %D291 = "dma.matrix"(%G35471360, %B2420) {decompress = False} ...
value-id b %173 final.mlir 的 Operation 的前綴,如:
%173 = "tpu.Cast"(%169) {ginfo ...
目前僅匹配字符串,只要字符串中包含對應的 value-id 就視為匹配
location b #loc("conv1_glow")
b #loc(3)
final.mlir的Operation 的loc,目前僅支持 name
op-name b tpu.Load final.mlir中的Operation 的名字,如:tpu.Load
file-line b mlir:312
b asm:168
在final.mlir和asm的行號上打斷點(diǎn)

display

display目前支持的較為簡(jiǎn)陋,是通過(guò)對info函數的python調用封裝實(shí)現的:

display self.info("asm 5")

data-checker

默認在通過(guò)--ref_data傳入數據的情況下會(huì )直接開(kāi)啟。也可以通過(guò)Bmodel_checker.py?使用

print

提供了內置的一些打印功能,主要聚焦于打印當前指令以及指令對應的數據,并會(huì )在TDB每一個(gè)stop時(shí)打印待執行的下一個(gè)atomic command

info

提供了內置的一些打印功能,主要聚焦于打印出不同格式的當前指令的上下文。

實(shí)現細節

文件結構

debugger首先提供了完整的指令解析和運行功能,這一部分的核心代碼位于 debugger/target_{產(chǎn)品型號/產(chǎn)品型號/common}。其中不同處理器在指令解析、cModel運行等方式的實(shí)現均有差異,這些差異分別在各自的文件夾中實(shí)現。而一部分相同的內容和對差異行為的抽象的聲明則在 python/debugger/target_common/ 目錄下提供。這部分內容比較復雜,在后面單獨介紹。

此外,debugger下還有一些其他文件,包括

  • debugger/disassembler.py:提供對Bmodel 文件的基本解析

  • debugger/atomic_dialect.py:基于disassembler.py,將 Bmodel的內容轉換為 mlir 的類(lèi)型系統

  • debugger/final_mlir.py:解析 `final.mlir`` 文件并建立索引供 TDB使用

  • debugger/tdb_support.py:提供了基于cmd.Cmd的基本的TDB功能的實(shí)現,同時(shí)加載 bmodel、日志、斷點(diǎn)的基類(lèi)、插件系統等。

各自的target_{device} 下提供的功能在后面介紹。而target_common包括

  • context.py:提供了CModelContext 這一基類(lèi)以及相關(guān)方法的聲明

  • cmodel.py:提供了CModelRunner 和 Memory 兩個(gè)基類(lèi),提供了一些方法的聲明

  • decoder.py:提供了 Decoder 類(lèi)定義以及解析tiu dma指令方法的聲明

  • op_support.py:提供了一些類(lèi)型定義、Layout、MemoryType 等枚舉類(lèi)型的聲明、一些公共方法、以及一些Operation 基類(lèi)聲明

集成上下文環(huán)境

為了更方便的獲取不同target的相同功能(如指令解析或執行),每個(gè)target 需要繼承CModelContext并實(shí)現自己的TargetContext來(lái)主動(dòng)暴露自己提供功能。每個(gè)TargetContext需要以類(lèi)變量的方式定義:

  • MemRef:描述了一塊內存區域的view(address、dtype、layout等)

  • device:描述了該target的類(lèi)型

  • memmap:描述了處理器上的內存地址信息

  • dma_sys、tiu_sys(部份處理器):描述了停止指令的類(lèi)型

  • get_memory_type:根據輸入地址獲取地址類(lèi)型(global、local、l2等 )

  • get_runner:獲取該target運行指令的Runner實(shí)例

  • 其他,如local_layout_to_stride,

  • merge_instruction:在每個(gè)subnet中,atomic指令滿(mǎn)足DAG,所以可以進(jìn)行 topological sort(這一功能實(shí)際應該由 Decoder 提供),從而可以被順序執行

每個(gè)TDB實(shí)例在加載BModel后,會(huì )根據BModel的處理器來(lái)獲取到對應target的Context實(shí)例(是實(shí)例而不是類(lèi)),從而能實(shí)現指令的解析和執行。

指令解析

每個(gè)target都需要繼承DecoderBase并實(shí)現自己的Decoder來(lái)提供各個(gè)target的指令解析功能,每個(gè)Decoder都需要實(shí)現以下接口:

  • decode_tiu_cmd

  • decode_tiu_cmds

  • decode_dma_cmd

  • decode_dma_cmds

BModel中,指令以CmdGroup(對多核實(shí)現,通過(guò)CoreCmdGroup)的形式存儲,在python/debugger/atomic_dialect.py中定義了decode_cmdgroup,可以看做是調用Decoder方法的入口

指令運行

每個(gè)target都需要繼承MemoryBase和CModelRunner并實(shí)現自己的 Memory和TargetRunner來(lái)提供各個(gè)target的指令運行功能,其中:

  • 每個(gè)Memory都需要實(shí)現set_data、get_data、clear_memory方法

  • 每個(gè)TargetRunner都需要實(shí)現tiu_compute、dma_compute、init_memory、clear_memory、dynamic_compute 等方法

其中,Runner實(shí)例默認需要包含對應target的Memory實(shí)例。

插件系統

插件系統同時(shí)支持了指令執行回調和TDB功能擴展,相關(guān)的代碼位置包括:

  • 插件基類(lèi):tdb_support.py:TdbPlugin

  • 指令擴展基類(lèi):tdb_support.py:TdbPluginCmd

  • 回調注冊功能實(shí)現:tdb_support.py:add_callback

  • tdb 中實(shí)現相關(guān)邏輯:tdb_support.py:TdbCmdBackend.add_plugin

  • tdb 中注冊生命周期:tdb.py中各個(gè)地方添加的 add_callback 裝飾器

  • 各個(gè) plugin 的具體實(shí)現:plugins/xxx.py

總結

BModel調試不是一件容易的事情,TDB提供了一種手段,可以看到BModel內部的推理過(guò)程并進(jìn)行干預。本文介紹了TDB的使用方法和實(shí)現細節, 一方面讓大家熟悉BModel的調試方法,能夠更快地定位模型轉換過(guò)程中的問(wèn)題并修復;另一方面,可以,并分析指令的格式和內容,增加開(kāi)發(fā)的背景知識。

分享到 :
RM新时代|官方理财平台