如何高效开发端智能算法?MNN 工作台 Python 调试详解

本文详细介绍了如何在MNN工作台中使用Python的pdb模块进行端侧智能算法的调试。通过分析pdb的源码,理解其原理,包括基本流程、中断控制和调试命令的实现。文章还提供了实例分析,帮助读者掌握在移动端算法开发中的调试方法。
摘要由CSDN通过智能技术生成

 随着移动互联网的快速发展,人工智能在移动端上的应用越来越广泛,集团内端智能在图像识别、视频检测、数据计算等核心场景发挥着重要作用。而在开发阶段,Python 毋庸置疑是算法进行研发的首选语言。但在移动端上,进行算法的部署、调试、验证,仍处在“刀耕火种”的时代,目前算法主要通过在代码中插入日志,验证程序的运行逻辑和结果。

通过打日志当然也能验证结果和定位问题,但一旦工程稍微复杂点,生产效率会非常低。因此,在 MNN 工作台之中(点击文末阅读原文,前往 MNN 官网:www.mnn.zone 下载)嵌入了端侧 Python 调试能力。经常使用Python的同学一定熟悉pdb模块,它是Python官方标准库提供的交互式代码调试器,和任何一门语言提供的调试能力一样,pdb提供了源代码行级别的设置断点、单步执行等常规调试能力,是Python开发的一个很重要的工具模块。

今天就让我们来重点分析下官方pdb模块源码,看看其调试功能的底层技术原理。

原理

从cpython源码中可以看到,pdb模块并非c实现的内置模块,而是纯Python实现和封装的模块。核心文件是pdb.py,它继承自bdb和cmd模块:

class Pdb(bdb.Bdb, cmd.Cmd):    ...
复制代码

基本原理:利用cmd模块定义和实现一系列的调试命令的交互式输入,基于sys.settrace插桩跟踪代码运行的栈帧,针对不同的调试命令控制代码的运行和断点状态,并向控制台输出对应的信息。

cmd模块主要是提供一个控制台的命令交互能力,通过raw_input/readline这些阻塞的方法实现输入等待,然后将命令交给子类处理决定是否继续循环输入下去,就和他主要的方法名runloop一样。


cmd是一个常用的模块,并非为pdb专门设计的,pdb使用了cmd的框架从而实现了交互式自定义调试。

bdb提供了调试的核心框架,依赖sys.settrace进行代码的单步运行跟踪,然后分发对应的事件(call/line/return/exception)交给子类(pdb)处理。bdb的核心逻辑在对于调试命令的中断控制,比如输入一个单步运行的”s“命令,决定是否需要继续跟踪运行还是中断等待交互输入,中断到哪一帧等。

基本流程

  • pdb启动,当前frame绑定跟踪函数trace_dispatch
def trace_dispatch(self, frame, event, arg):
     if self.quitting:
         return # None
     if event == 'line':
         return self.dispatch_line(frame)
     if event == 'call':
         return self.dispatch_call(frame, arg)
     if event == 'return':
         return self.dispatch_return(frame, arg)
     if event == 'exception':
     ...
复制代码
  • 每一帧的不同事件的处理都会经过中断控制逻辑,主要是stop_here(line事件还会经过break_here)函数,处理后决定代码是否中断,需要中断到哪一行
  • 如需要中断,触发子类方法user_#event,子类通过interaction实现栈帧信息更新,并在控制台打印对应的信息,然后执行cmdloop让控制台处于等待交互输入
def interaction(self, frame, traceback):
     self.setup(frame, traceback) # 当前栈、frame、local vars
     self.print_stack_entry(self.stack[self.curindex])
     self.cmdloop()
     self.forget()
复制代码
  • 用户输入调试命令如“next”并回车,首先会调用set_#命令,对stopframe、returnframe、stoplineno进行设置,它会影响中断控制```stop_here``的逻辑,从而决定运行到下一帧的中断结果.
def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
     self.stopframe = stopframe
     self.returnframe = returnframe
     self.quitting = 0
     # stoplineno >= 0 means: stop at line >= the stoplineno
     # stoplineno -1 means: don't stop at all
     self.stoplineno = stoplineno
复制代码
  • 对于调试过程控制类的命令,一般do_#命令都会返回1,这样本次runloop立马结束,下次运行到某一帧触发中断会再次启动runloop(见步骤3);对于信息获取类的命令,do_#命令都没有返回值,保持当前的中断状态。
  • 代码运行到下一帧,重复步骤3
  • <
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值