python3.13字节码特化的简单讨论

python3.13字节码特化的简单讨论

前置阅读

要点

  1. Python字节码DSL规则

在DSL的语法规则当中,有这样一条:

stream:
    NAME "/" size

这里的stream是指字节码的缓存大小。

  1. 有关Faster-Python的总结 from miaomiao's blog

有关于模块frozen的解释:python模块frozen原理

背景

最近在PaddleClas的测试中遇到一个大面积挂的问题,报错信息是函数调用缺少一个位置参数,经定位后问题如下:

错误发生的New Code forward#xxx,被执行了两次,在第二执行的时候命中了Cache:

  • 在设置MIN_GRAPH_SIZE=10的时候,在第二次执行Forward New Code时,命中Cache并且触发了Python的字节码特化,把MethodVariable特化成了FunctionVariable,而我们的栈布局是 Callable | NULL ,如果从MethodVariable变成了FunctionVariable,因为我们没有在栈上存放self,就会因为FunctionVariable没有这类信息,导致在真正CALL函数的时候,因为没有self而缺失positional parameters.

  • 在设置MIN_GRAPH_SIZE=0的时候,我们没有从原始字节码copy这部分逻辑,而是自己生成了这部分代码,在这个结果中把一个LOAD_METHOD + NULL|SELF 拆成了一个LOAD_ATTR + PUSH_NULL,不会触发特化,从而避免了这个错误。

修复方案

通过在3.13中,对LOAD_ATTR进行预拆分来避免这个特化。

疑惑

特化一般在执行次数超过8次之后才会发生,为什么在这里2次就出现了特化?

探索

我们去寻找Cpython仓库当中,与这部分逻辑有关的代码:
我把高度相关的部分放在这里:
image

image

因为高度封装,以我个人的水平已经难以找到给counter赋初值的逻辑在哪里,也只能就此搁置了,不过整体的上下游逻辑至此已经大致成型,再遇到同类问题时,也可以优先考虑是特化产生的结果。

posted @ 2025-01-23 16:59  Gold_stein  阅读(29)  评论(0)    收藏  举报