Hot-cold splitting in the cases generator and JIT optimizer.
还没有人认领这个 Issue。
- 主要语言
- Python
- 星标
- 77.2k
- 派生
- 35.9k
- PR 合并指标
- PR 指标待抓取
描述
https://github.com/python/cpython/issues/143158 describes hot-cold splitting in the JIT, but that is too late for optimizations that sink code onto exits.
To support those optimizations, we need to split uops as defined into bytecodes.c into "hot" and "cold" ops.
From https://github.com/python/cpython/issues/143158#issuecomment-4544178632
For example, we want to transform this:
op (_GUARD_IS_NONE_POP, (val -- )) {
int is_none = PyStackRef_IsNone(val);
if (!is_none) {
PyStackRef_CLOSE(val);
AT_END_EXIT_IF(1);
}
DEAD(val);
}
into this:
op (_GUARD_IS_NONE_POP, (val -- )) {
int is_none = PyStackRef_IsNone(val);
if (!is_none) {
goto _GUARD_IS_NONE_POP_COLD; // tail call
}
DEAD(val);
}
op (_GUARD_IS_NONE_POP_COLD, (val -- )) {
PyStackRef_CLOSE(val);
AT_END_EXIT_IF(1);
}
Currently, during lowering of the uop trace to a form suitable for execution we need to insert an _EXIT_TRACE uop as the target for exit jumps in the uop. We want to replace those with the "cold" uop followed by the exit, allowing compensation code to be more easily sunk onto side exits.
While it is appealing to do this automatically, it might make more sense to do the splitting manually, and add support for custom exits to the tooling.
We could mark ops as exit and explicitly state which exit is being used (with _EXIT_TRACE as the default exit).
So _GUARD_IS_NONE_POP would be rewritten as:
op (_GUARD_IS_NONE_POP, (val -- )) {
int is_none = PyStackRef_IsNone(val);
if (!is_none) {
EXIT_TO(POP_TOP_EXIT);
}
DEAD(val);
}
exit op (POP_TOP_EXIT, (val -- )) {
PyStackRef_CLOSE(val);
}
Likewise, _ITER_NEXT_INLINE would be rewritten as:
tier2 op(_ITER_NEXT_INLINE, (iternext_fn/4, iter, null_or_index -- iter, null_or_index, next)) {
assert(sizeof(iternextfunc) == sizeof(uintptr_t));
volatile iternextfunc iternext_v = (iternextfunc)iternext_fn;
PyObject *item = iternext_v(PyStackRef_AsPyObjectBorrow(iter));
if (item == NULL) {
EXIT_TO(_ITER_NEXT_INLINE_EXIT);
}
STAT_INC(FOR_ITER, hit);
next = PyStackRef_FromPyObjectSteal(item);
}
exit op(_ITER_NEXT_INLINE_EXIT, ( -- )) {
if (_PyErr_Occurred(tstate)) {
if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
_PyEval_MonitorRaise(tstate, frame, frame->instr_ptr);
_PyErr_Clear(tstate);
}
else {
ERROR_NO_POP();
}
}
}
贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
调研方向
从 bytecodes.c 和 issue 143158 中关于 hot-cold splitting 的讨论开始,然后追踪 uop traces 如何被 lowered,以及 tooling 如何表示 exits。定义 exit ops 和 custom exits 如何替换插入的 _EXIT_TRACE targets,并验证 side-exit 补偿代码能够按预期被表示和 sink。
由索引模型根据 Issue 内容生成。
评估
- 技术栈
- c, python
- 领域
- compilers, performance
- Issue 类型
- 功能
- 难度
- 5/5
- 预计耗时
- 一周以上
- 活跃度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 35/100