下载
中文
注册

TIK功能调试

功能介绍

用户开发完TIK算子之后,建议使用TIK调试工具进行算子调试,这样可以通过模拟算子运行的过程,解决算子的绝大部分功能问题(例如数据越界)。

TIK功能调试用于调试TIK DSL的执行行为。该调试功能通过TIK模块的tik.tikdb对象提供。tik.tikdb对象通过tik.Tik对象的tik_instance.tikdb()方法获得,并针对这个TIK对象进行调试。

tikdb提供类似pdb(The Python Debugger)的调试命令行界面。调试者通过tikdb.start_debug()函数启动一个调试过程(需要给定用于测试的TIK DSL程序的输入参数,详细可参考start_debug),tikdb将根据TIK的Dprofile启动一个本地的模拟器,模拟执行TIK定义的执行过程。执行过程遇到断点,tikdb会进入调试命令行界面,详细可参考4

支持的型号

Atlas 200/300/500 推理产品

Atlas 训练系列产品

Atlas 推理系列产品

Atlas A2训练系列产品/Atlas 800I A2推理产品

Atlas 200/500 A2推理产品

使用方法

  1. 在进行功能调试前,需要在定义TIK实例时设置disable_debug参数为False,该参数默认值为“True”,代表默认不开启调试功能,详细参数含义可参见TIK类构造函数
    tik_instance = tik.Tik(disable_debug=False)

    注意:开启调试功能会影响算子性能,开发者完成功能调试后可以删除disable_debug参数或将disable_debug参数手动置为True,禁用调试功能,可以降低编译时间时长,提升部分性能。

    debug调试中使用到的API接口主要包括:
    • start_debug:启动调试并在调试结束后返回输出结果。
    • debug_print:可选接口,为了方便用户打印算子运行过程中的数据。在TIK DSL中插入一个对表达式求值并打印结果的语句。调试器执行到这行代码时会对表达式求值并将结果打印在屏幕上。

    更多接口介绍请参考功能调试

  2. 准备调试数据。

    可以通过numpy生成随机数或者从文件中读取。

    完整代码示例参考如下,文件名以simple_add.py为例。

    import numpy as np
    
    from tbe import tik
    from tbe.common.platform import set_current_compile_soc_info
    
    def simple_add():
        tik_instance = tik.Tik(disable_debug=False)
        kernel_name = "tik_vec_add_128_float32"
        dst_ub = tik_instance.Tensor("float32", [128], tik.scope_ubuf, "dst_ub")
        dst_gm = tik_instance.Tensor("float32", (128,), tik.scope_gm,  "dst_gm")
        src0_gm = tik_instance.Tensor("float32", (128,), tik.scope_gm, "src0_gm")
        src0_ub = tik_instance.Tensor("float32", (128,), tik.scope_ubuf, "src0_ub")
        src1_gm = tik_instance.Tensor("float32", (128,), tik.scope_gm, "src1_gm")
        src1_ub = tik_instance.Tensor("float32", (128,), tik.scope_ubuf, "src1_ub")
    
        tik_instance.data_move(src0_ub, src0_gm, 0, 1, 16, 0, 0)
        tik_instance.data_move(src1_ub, src1_gm, 0, 1, 16, 0, 0)
        tik_instance.vec_add(64, dst_ub, src0_ub, src1_ub, 2, 8, 8, 8)
        tik_instance.data_move(dst_gm, dst_ub, 0, 1, 16, 0, 0)
        tik_instance.BuildCCE(kernel_name, [src0_gm, src1_gm], [dst_gm])
    
        return tik_instance
    
    if __name__=='__main__':
        # 请根据实际昇腾AI处理器型号进行设置
        soc_version="xxx"
        set_current_compile_soc_info(soc_version)   # 请根据AI处理器实际版本设置,具体请参考set_current_compile_soc_info接口说明
        tik_instance = simple_add()
        data_x = np.ones((128,)).astype("float32")
        data_y = np.ones((128,)).astype("float32")
        feed_dict = {'src0_gm': data_x, 'src1_gm': data_y}
        model_data, = tik_instance.tikdb.start_debug(feed_dict=feed_dict,interactive=True)
        print(model_data)
  3. 运行算子文件进入TIK调试器的交互命令行。
    1. 请参见环境准备配置好相关环境变量。
    2. 运行算子文件。

      调用tikdb.start_debug()函数且interactive参数为True后,运行算子文件进入TIK调试器的交互命令行,此时调试器会停止在执行第一条TIK DSL之前。如下图所示。

  4. 在TIK调试器交互命令行模式下,用户可输入调试命令,详细调试命令请参考调试命令参考

    com(mand) param1 [param2]

    • com(mand) 为命令的名字,可以是command,也可缩写为com。
    • param1不带中括号,表示必选参数。
    • [param2]带中括号,表示可选参数。
    • 其他使用说明:
      • 若命令行提示符中输入空白符,表示重复执行上一条命令。
      • 在debug 调试下,可以进行单步调试,也可以执行至下一个断点或程序结束。如果程序功能正确,则运行到程序结束可以看到debug产生的数据和期望数据的差别为0。

调试命令参考

调试器命令行模式下包括如下几种命令:

  1. block [block_idx1] [block_idx2] ... [block_idxn]
    • 功能说明:对于多核用例,用于核状态查询、调试核切换,该命令对单核用例无效。
    • 参数说明:block_idxn对应多核用例中的block_num取值。
    • 查询核状态:执行到多核对应的with tik_instance.for_range()及之后语句,"block"命令可以查询所有核对应的状态,输出信息说明:
      • Block表示核编号。
      • Status表示当前核状态,包括:Stepping(交互状态),Running(非交互运行状态),Finished(运行结束)。
      • Current表示当前调试核;包括True(当前调试核),False(当前非调试核)。
      图1 多核交互信息查询
    • 核切换:执行到多核对应的with tik_instance.for_range()及之后语句,"block block_idx"命令进行核切换,从当前核切换到block_idx对应的核进行调试。
      图2 多核切换调试
  2. b(reak) [tag] [block block_idx1 [block_idx2] ... [block_idxn]]
    • 功能说明:在TIK DSL对应的tag上设置断点、查询断点。
    • 参数说明
      • tag:TIK DSL程序的断点标记,内容为:
        该TIK DSL定义函数所在的文件名:该TIK DSL定义函数所在函数的行号

        若不设置任何参数,则直接列出所有已设置断点的信息,包含断点的编号,断点的使能状态,断点对应的tag。其中断点的编号从“0”开始按照设置先后顺序递增。

        需要注意:若设置断点格式不准确或者断点处语句非TIK DSL语句均会提示断点设置失败。支持设置断点的语句包括Tensor定义、if-else语句、for语句以及所有的指令(如data_move、vadd等)。

      • block:仅对多核用例有效,对单核用例无效。通过命令“block”指定断点对所有核生效(Running和Finished状态的核无效);通过命令“block block_idx1 block_idx2 ...”指定断点对特定的核生效。
      • 样例说明:以上文的simple_add.py为例。
        • b或者break(显示当前所有断点)

          Num表示断点编号;Type表示类型为断点;Enb表示断点状态;where表示断点所在文件名和代码行号。

        • b simple_add.py(输入格式不匹配)
        • b simple_add.py:16(输入准确)
        • b simple_add.py:100(行号超过文件代码行数或该行代码不会执行)
        • b simple_add.py:1(行号对应代码非TIK原语代码)
        • b others.py:18(设置其它文件断点)
        • b others.py:19 block 1 2 (如果是多核用例,通过block指定该断点只对核1、2生效)
        图3 设置断点示例
  3. clear [bpnumber] [block block_idx1 [block_idx2] ... [block_idxn]]
    • 功能说明:清除指定编号的断点,如果不指定参数,将清除所有断点。
    • 参数说明:
      • bpnumber:断点的编号,即为b(reak)命令查询到的Num。
      • block:仅对多核用例有效,对单核用例无效。通过命令“block”清除所有核的断点(Running和Finished状态的核无效);通过命令“block block_idx1 block_idx2 ...”清除特定核的指定断点。
    • 样例说明:以上文的simple_add.py为例。
      • clear (清除所有断点)
      • clear 1 (断点存在)
      • clear 10 (断点不存在)
      • clear cc (编号不规范)
      • clear 1 block 2 3 (对于多核用例,指定清除核2、3上的断点1)
      图4 清除断点示例
  4. disable [bpnumber] [block block_idx1 [block_idx2] ... [block_idxn]]
    • 功能说明:禁用指定编号的断点。
    • 参数说明:
      • bpnumber:断点的编号,即为b(reak)命令查询到的Num。
      • block:仅对多核用例有效,对单核用例无效。通过命令“block”禁用所有核的断点(Running和Finished状态的核无效),通过命令“block block_idx1 block_idx2 ...”禁用特定核的指定断点。
    • 样例说明:以上文的simple_add.py为例。
      • disable 2 (断点存在)
      • disable 11 (断点不存在)
      • disable aa (编号不规范)
      • disable 1 block 2 3 (对于多核用例,禁用核2、3上对应的断点1)
      图5 禁用指定编号断点示例
  5. enable [bpnumber] [block block_idx1 [block_idx2] ... [block_idxn]]
    • 功能说明:使能指定编号的断点。
    • 参数说明:
      • bpnumber:断点的编号,即为b(reak)命令查询到的Num。
      • block:仅对多核用例有效,对单核用例无效。通过命令“block”使能所有核的断点(Running和Finished状态的核无效);通过命令“block block_idx1 block_idx2 ...”指定使能特定核的指定断点。
    • 样例说明:以上文的simple_add.py为例。
      • enable 2 (断点存在)
      • enable 11 (断点不存在)
      • enable bb (编号不规范)
      • enable 1 block 2 3(对于多核用例,使能核2、3上对应的断点1)
      图6 使能指定编号断点示例
  6. n(ext)
    • 功能说明:执行至下一个TIK DSL语句。
    • 参数说明:无。
  7. c(ontinue) [-a(ll)]
    • 功能说明:执行至程序结束,如果遇到断点或异常,会重新进入交互模式。
    • 参数说明:-a或-all仅对多核用例有效,c(ontinue)只会对当前调试进程生效,c(ontinue) -ac(ontinue) -all会对所有进程生效。
  8. l(ist)或w(here)
    • 功能说明:打印出将要执行的TIK DSL代码对应的Python代码及上下文。
    • 参数说明:无。
    • 样例说明:如图7所示,总共打印出7行代码。
      图7 list和where代码示例
  9. p(rint) expression
    • 功能说明:对表达式求值并打印结果。
    • 参数说明:expression可以是任意Python表达式。expression可以使用的变量有TIK DSL当前作用域的Tensor和Scalar。其中Tensor会被替换为与Tensor等价的numpy.ndarray,这个numpy对象的形状、类型和数据都与Tensor一致,Scalar会被求值并替换为Python的float或int类型的数值。expr也可以传入纯字符串或者字符串与表达式的复合情况。
    • 样例说明:如图8所示。
      图8 print示例
  10. q(uit)
    • 功能说明:退出调试器并终止当前执行的程序。
    • 参数说明:无。
    • 样例说明:如图9所示。
      图9 quit示例

多核调试示例

完整代码示例参考如下,文件名以tik_multi_core_debug.py为例。

import numpy as np

from tbe.common.platform import set_current_compile_soc_info
from tbe import tik


def simple_add_multi_core():
    tik_instance = tik.Tik(disable_debug=False)
    kernel_name = "tik_multi_core_debug"
    dtype = "float16"
    block_nums = 3


    dst_gm = tik_instance.Tensor(dtype, (block_nums*128,), tik.scope_gm, "dst_gm")
    src0_gm = tik_instance.Tensor(dtype, (block_nums*128,), tik.scope_gm, "src0_gm")
    src1_gm = tik_instance.Tensor(dtype, (block_nums*128,), tik.scope_gm, "src1_gm")

    with tik_instance.for_range(0, block_nums, block_num=block_nums) as blk_idx:
        dst_ub = tik_instance.Tensor(dtype, (128,), tik.scope_ubuf, "dst_ub")
        src0_ub = tik_instance.Tensor(dtype, (128,), tik.scope_ubuf, "src0_ub")
        src1_ub = tik_instance.Tensor(dtype, (128,), tik.scope_ubuf, "src1_ub")

        tik_instance.data_move(src0_ub, src0_gm[blk_idx*128], 0, 1, 8, 0, 0)
        tik_instance.data_move(src1_ub, src1_gm[blk_idx*128], 0, 1, 8, 0, 0)
        tik_instance.vec_add(128, dst_ub, src0_ub, src1_ub, 1, 8, 8, 8)
        tik_instance.data_move(dst_gm[blk_idx*128], dst_ub, 0, 8, 1, 0, 0)

    tik_instance.BuildCCE(kernel_name, [src0_gm, src1_gm], [dst_gm])
    return tik_instance


if __name__ == '__main__':
    # 请根据实际昇腾AI处理器型号进行设置
    soc_version="xxx"
    set_current_compile_soc_info(soc_version)   # 请根据AI处理器实际版本设置,具体请参考set_current_compile_soc_info接口说明
    tik_instance = simple_add_multi_core()
    data_x = np.ones((3*128,)).astype("float16")
    data_y = np.ones((3*128,)).astype("float16")
    feed_dict = {'src0_gm': data_x, 'src1_gm': data_y}
    model_data, = tik_instance.tikdb.start_debug(feed_dict=feed_dict, interactive=True)
    print(model_data)
  1. 对于多核用例,在进入多核for_range语句(tik_instance.for_range(0, block_nums, block_num=block_nums))之前,可以通过打断点指定哪些核进入交互模式,或者通过单步走(默认所有核都会进入交互模式)。对于不进入交互模式的核,会自动执行结束。
    图10 单步走所有核进入交互模式
    图11 通过打断点指定特定核进入交互模式

    如果断点不指定核,默认对所有核打断点。

    图12 单步调试及多核切换执行

    单步调试及多核切换,单步调试过程中只有当前核会执行代码,其它核保持原位置不变。

  2. 多核断点相关测试。

    在进入多核for_range循环(tik_instance.for_range(0, block_nums, block_num=block_nums))之前,如果设置断点,会对所有的核生效,并且会将所有核设置进入交互模式;

    如果已经进入多核for_range循环,设置断点默认对所有可交互核生效,“Running”、“Finished”状态的核无效;

    如果只想对特定的核设置断点,可以通过字符“block index1 index2 …”指定核编号;

    图13 进入多核for_range之前设置断点

    断点0对所有核生效,断点1只对核0、1生效,断点2只对核1、2生效。

    图14 进入多核for_range之前设置断点指定特定核进入交互状态

    断点只对核1、2生效,执行c,可以看到执行到断点处停止,同时核0状态为“Finished”,表示执行结束,不会进入交互模式。

    图15 进入多核for_range之后指定核设置断点

    设置断点指定核0、1、2,核0已经处于“Finished”状态,不能设置断点,给出告警提示信息,其它两个核设置断点成功。

    对于断点disable、enable、clear与设置断点指令类似,在此不再赘述。

    图16 enable、disable多核断点
    图17 clear命令测试
  3. continue、quit命令测试。

    进入多核交互模式之后,continue命令只会对当前核生效,如果想所有核都继续执行,输入命令“continue -a” or “continue -all”or “c -a”or “c -all”。

    quit命令直接退出执行。

    图18 continue命令测试
    图19 quit命令测试