当前位置: 首页 > article >正文

对subprocess启动的子进程使用VSCode python debugger

文章目录

  • 1 情况概要(和文件结构)
  • 2 具体设置和启动步骤
    • 2.1 具体配置
      • Step 1 针对attach debugger到子进程
      • Step 2 针对子进程的暂停
      • (可选) Step 3 判断哪个进程id是需要的子进程
    • 2.2 启动步骤和过程
  • 3 其他问题解决
    • 3.1
    • 3.2 ptrace: Operation not permitted
  • 其他解决方案*2
    • 方案一(ChatGPT提供,对我不可行)
    • 方案二(Github issue翻到)
  • 参考

1 情况概要(和文件结构)

环境:Linux Ubuntu

最近在跑大模型,遇到一份代码的具体程序是通过subprocess.run()来启动的,而vscode的debug功能无法追踪进去。也就是说,我有父进程launch.py来启动subprocess.run(),调用子进程文件run.py。我可以单步调试追踪到subprocess这一步并进入run()函数,但是无法继续进入子进程的工作,无法追踪到run.py看我真正想看的代码。

这里父进程文件和子进程文件的概念我没有细究,大概意思是主动调用subprocess.run()来创建子进程的是父进程文件,被subprocess.run()跑起来的是子进程文件。

附上文件结构的简单示意。

  1. test.sh:python launch.py并传一堆参数

  2. launch.py:父进程,主要内容为

def python_launch(args):
    """
    Vanilla python launcher for degbugging purposes
    """
    # ....
    # 构造cmd
    cmd = f"python {args.run_file}" # 省略一堆参数
    # 启动subprocess
    subprocess.run(cmd, shell=True)
    
  1. run.py:子进程,主要内容为
def main(cfg):
 
    # 环境变量设置,数据读取,新建文件夹之类的之类的
    # ...
    
    # 初始化trainer并训练
    trainer = build_trainer(cfg)
    trainer.run()

2 具体设置和启动步骤

我们的目标是,我从某个地方把程序起起来并创建了子进程,然后把debugger连接到子进程上,于是它可以在子进程的断点地方停下、正常调试。

那么我们需要做到两件事情:1)把Debugger attach到子进程;2)子进程要能等待我们attach,而不是一股脑往下运行,那就来不及停在断点。

2.1 具体配置

我们分别对这两件事情做配置。

Step 1 针对attach debugger到子进程

采用vscode的python debugger插件,新建debugger config如下(编辑的是launch.json)

{
    "name": "Python: Attach to Subprocess", //随便起名
    "type": "python",
    "request": "attach", //附加到子进程
    "processId": "${command:pickProcess}" //选择进程id
}

这里用${command:pickProcess}是采用vscode自带的命令,从进程列表中手动选择,而不是写死进程id。
实测这些内容就够了,不需要其他key比如ChatGPT建议的justMyCode和subProcess。

Step 2 针对子进程的暂停

在子进程文件,你需要断点的代码前面,或者索性最前面,加上一行:

    input("Continue...")

这行会让代码停下,直到你在命令行中随便敲点什么,回车也行,才继续执行。

(可选) Step 3 判断哪个进程id是需要的子进程

因为我实在小白,我不确定哪个进程才是我要的,所以我在子进程文件里加了几行,输出父进程id和子进程id。

    print(f"Parent PID (PPID): {os.getppid()}")
    print(f"Current PID: {os.getpid()}")

Current PID就是我们要的子进程id

以上,配置完了,我的run.py最终长这样:

def main(cfg):

    #### for debug #########
    # 输出父进程和子进程id
    print(f"Parent PID (PPID): {os.getppid()}")
    print(f"Current PID: {os.getpid()}")
    
    # 可选,用来检查user id,原因后面说
    print(f"UID: {os.getuid()}, EUID: {os.geteuid()}") 
    
    # 暂停
    input("Continue...")
    #########################
    
    # 环境变量设置,数据读取,新建文件夹之类的之类的
    # ...
    
    trainer = build_trainer(cfg)
    trainer.run()
    

2.2 启动步骤和过程

需要你操作的地方写了人工,其他的是自动执行顺序。

  1. (人工)正常通过命令行执行sh test.sh,启动脚本

  2. 程序进入launch.py,启动subprocess

  3. 程序进入run.py
    3.1. 输出父进程id和子进程id供参考
    3.2. 在input(Continue...)处暂停,等待键入字符才能继续执行
    在这里插入图片描述

  4. (人工)启动debug的Subprocess Attach,选择子进程,附加到正确的id上,等待…
    在这里插入图片描述
    在这里插入图片描述

  5. attach到子进程,可能需要一会。
    在DEBUG CONSOLE里会提示结果,要么是attach成功(如图),要么是弹窗报错然后在DEBUG CONSOLE里看错误信息。
    此时可以看到调试工具栏表示正在执行、没有暂停,因为我们还在被input()暂停着。
    在这里插入图片描述

  6. (人工)在命令行里敲个回车,跳出input(Continue...)

  7. 断点停止在run.py中的对应位置

  8. (人工)正常调试

3 其他问题解决

3.1

--- Starting attach to pid: 1103 ---
/bin/sh: 1: gdb: not found

解决方案是安装gdb

apt-get update
apt-get upgrade -y
apt-get install gdb

3.2 ptrace: Operation not permitted

解释一下前面python里为什么写了一句进程创建用户id查询

我在第5步attach环节遇到了一个错误,ptrace: Operation not permitted,是个权限错误。

--- Starting attach to pid: 654608 ---
Could not attach to process.  If your uid matches the uid of the target
process, check the setting of /proc/sys/kernel/yama/ptrace_scope, or try
again as the root user.  For more details, see /etc/sysctl.d/10-ptrace.conf
ptrace: Operation not permitted.

问了下ChatGPT:

/proc/sys/kernel/yama/ptrace_scope 文件
这个文件控制了 ptrace 系统调用的访问权限。ptrace 是 Linux 的一个系统调用,允许一个进程跟踪和控制另一个进程,是调试器工作的核心。
ptrace_scope 参数的值
0: 允许任何进程使用 ptrace 附加到其他进程(受用户权限约束)。
1: 仅允许父进程(如直接启动的调试器进程)附加到子进程。
2: 禁止所有非父子关系的调试。
3: 禁止所有 ptrace 附加操作。
默认值通常为 1,为了安全性避免恶意进程滥用 ptrace。

查询了一下这个值(cat /proc/sys/kernel/yama/ptrace_scope),输出是1。但是显然我的父进程和子进程都是同一个user启用的,不懂为什么说我权限错误。

查询进程创建用户有好几个方法,我是在python里写了一句这个。(解释了前文的查询用户id是啥用)

print(f"UID: {os.getuid()}, EUID: {os.geteuid()}") 

但是到处折腾了一圈别的方案没解决,还是回来把这个值设为0了,真就解决了。

这个值的设置需要root权限。废话,如果本来就是用root在跑的话权限统一也不会报这个错了。

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

ChatGPT也说了,这个值设置为0的话不太安全,建议用完就给它改回去。于是写了个脚本方便切换值,插入在.bashrc文件里(vim ~/.bashrc

ptrace_scope() {
	current_value=$(cat /proc/sys/kernel/yama/ptrace_scope) 
	echo "[INTRO] Script for changing between 0 & 1 value for /proc/sys/kernel/yama/ptrace_scope. The value should vary from [0,3] for different safety levels, default as 1"
    echo; # 换行
    echo "current value = $current_value" # 获取当前值
    
    # 根据当前值,在0和1之间切换
    if [ "$current_value" -eq 1 ]; then
        echo "Now changing to 0..."
        echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
    elif [ "$current_value" -eq 0 ]; then
        echo "Now changing to 1 ..."
        echo 1 | sudo tee /proc/sys/kernel/yama/ptrace_scope
    else
        echo "[Warning] Unknown ptrace_scope current value. Nothing takes effect."
        exit 1
    fi

    # 检查是否执行成功,并提醒恢复0值
    current_value=$(cat /proc/sys/kernel/yama/ptrace_scope)
    echo "[INFO] ptrace_scope changed to $current_value"
    echo;
    if [ "$current_value" -eq 1 ]; then
        echo "[INFO] Safe default setting ^-^"
    elif [ "$current_value" -eq 0 ]; then
        echo "[INFO] Unsafe setting, remember to change back to value = 1."
    fi

    echo;
}

记得source ~/.bashrc使配置生效。

效果如下,通过ptrace_scope change指令实现0-1切换。
在这里插入图片描述

其他解决方案*2

方案一(ChatGPT提供,对我不可行)

针对debugger监听子进程这个事情,ChatGPT还给了我一套方案,但用不了。记一下大概配置,哪哪都折腾过了,这个debugpy的wait for client啊就是不知道wait到了什么,直接就监听到了,但我明明还没开debugger的attach!

在子进程文件里写

import debugpy

int main():
	# 启动调试服务
	debugpy.listen(("0.0.0.0", 5678))
	print("Debugpy is listening on port 5678")
	# 等待客户端连接
	debugpy.wait_for_client()
	print("Debugger is attached!")

	# trainer.......

在debugger config里写一个针对test脚本执行的config,和debug普通python文件一个写法。另外再写一个attach用的config,用的监听路径,大概如下:

{
    "name": "Python: Attach to Subprocess",
    "type": "python",
    "request": "attach",
    "connect": {
        "host": "localhost",
        "port": 5678
    },
    "justMyCode": false,
    "subProcess": false
}

方案二(Github issue翻到)

还看到一个更暴力的是是直接改写,不用subprocess,见GitHub: embodied-generalist/issues/33
因为它只是inference但是我要train…小白还不知道不开子进程会不会有影响,就没碰

参考

  1. StackOverflow Attaching a VSCode Debugger to a Sub Process in Python
  2. GitHub: embodied-generalist/issues/33

http://www.kler.cn/a/404560.html

相关文章:

  • windows的WSL Ubuntu子系统重置root或其他用户的密码
  • Jenkins更换主题颜色+登录页面LOGO图片
  • 【已解决】“EndNote could not connect to the online sync service”问题的解决
  • Kubernetes 安装配置ingress controller
  • React的hook✅
  • Rust 力扣 - 746. 使用最小花费爬楼梯
  • 【Linux】软件包管理器yum、编辑器vim
  • Kafka中ACKS LSO LEO LW HW AR ISR OSR解析
  • Spring Bean 的生命周期详解
  • 笔记--(Shell脚本01)、正则表达式与文本处理器
  • 零基础Java第二十二期:异常(二)
  • 【Nginx从入门到精通】05-安装部署-虚拟机不能上网简单排错
  • 大语言模型与图结构的融合: 推荐系统中的新兴范式
  • 基于LLama_factory的Qwen2.5大模型的微调笔记
  • Scala中的集合复习(1)
  • 2024中国报业技术年会 | 文盾信息聚焦AI大模型的内容安全风控实践
  • Easyexcel(3-文件导出)
  • 鸿蒙多线程开发——线程间数据通信对象02
  • 用Python爬虫“偷窥”1688商品详情:一场数据的奇妙冒险
  • Scala的Array多维数组
  • 介绍一下strncmp(c基础)
  • 大学课程项目中的记忆深刻 Bug —— 一次意外的数组越界
  • 【Linux】系统调用和库函数汇总整理
  • Ubuntu安装sublime Tex
  • FreeRTOS消息队列实验与出现的问题
  • uni-app 修改复选框checkbox选中后背景和字体颜色