Hot-cold splitting in the cases generator and JIT optimizer.
まだ誰も着手していません。
- 主要言語
- 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 にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
調査の方向性
bytecodes.c と issue 143158 の hot-cold splitting に関する議論から始め、uop traces がどのように lower され、tooling が exits をどのように表現するかを追跡します。exit ops と custom exits が挿入された _EXIT_TRACE targets をどのように置き換えるかを定義し、side-exit の補償コードを意図どおりに表現して sink できることを確認します。
索引モデルが issue の本文から書いたものです。
評価
- 技術スタック
- c, python
- 領域
- compilers, performance
- issue の種類
- 機能追加
- 難易度
- 5/5
- 見積もり時間
- 1週間以上
- 活発さ
- 静か
- 明瞭さ
- おおむね明確
- 初心者へのやさしさ
- 35/100