python3.13字节码特化的简单讨论
python3.13字节码特化的简单讨论
前置阅读
要点
在DSL的语法规则当中,有这样一条:
stream:
    NAME "/" size
这里的stream是指字节码的缓存大小。
有关于模块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仓库当中,与这部分逻辑有关的代码:
我把高度相关的部分放在这里:


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

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号