python / python/cpython

Eliminate overhead of fetching and testing `NULL` attributes in `STORE_ATTR` specializations for new objects

オープン
#144,141 コメント 3 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

interpreter-core performance
主要言語
Python
スター
77.2k
フォーク
35.9k
PR マージ指標
PR 指標を取得中

説明

Consider

class C:
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c
C(1,2,3)

This produces a trace looking something like this:

...
_CHECK_AND_ALLOCATE_OBJECT
_CREATE_INIT_FRAME
_PUSH_FRAME
# Some guards
_LOAD_FAST_BORROW_1
_LOAD_FAST_BORROW_0
# Some more guards
_STORE_ATTR_INSTANCE_VALUE
# Some more guards
_LOAD_FAST_BORROW_2
_LOAD_FAST_BORROW_0
# Some more guards
_STORE_ATTR_INSTANCE_VALUE
# Some more guards
_LOAD_FAST_BORROW_3
_LOAD_FAST_BORROW_0
# Some more guards
_STORE_ATTR_INSTANCE_VALUE
...

Each of those _STORE_ATTR_INSTANCE_VALUE reads the old value out of memory and then conditionally decrefs it.
But in this case we know that the old value was NULL so we can just overwrite it.
So we can replace this:

        PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset);
        PyObject *old_value = *value_ptr;
        FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value));
        if (old_value == NULL) {
            PyDictValues *values = _PyObject_InlineValues(owner_o);
            Py_ssize_t index = value_ptr - values->values;
            _PyDictValues_AddToInsertionOrder(values, index);
        }
        Py_XDECREF(old_value);

with this:

        PyObject **value_ptr = (PyObject**)(((char *)owner_o) + offset);
        FT_ATOMIC_STORE_PTR_RELEASE(*value_ptr, PyStackRef_AsPyObjectSteal(value));
        PyDictValues *values = _PyObject_InlineValues(owner_o);
        Py_ssize_t index = value_ptr - values->values;
       _PyDictValues_AddToInsertionOrder(values, index);

On Aarch64, this reduces the number of machine instructions from 48 to 26.

The same reasoning also applies to _STORE_ATTR_SLOT where it reduces the number of machine instructions from 32 to 14.

See also https://github.com/python/cpython/issues/134584

We can probably remove some of those guards as well, but that's a separate issue.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

まず、STORE_ATTR_INSTANCE_VALUE および STORE_ATTR_SLOT という名前の CPython インタープリターの特殊化を見つけ、次に関連する issue 134584 を読んで背景を確認してください。新しく割り当てられたオブジェクトの扱いを提案されたパスと比較し、変更によって挿入順序の扱いが維持されると同時に、NULL の読み取り、decref、および報告された命令オーバーヘッドがなくなることを検証してください。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
c, python
領域
backend, performance
issue の種類
リファクタリング
難易度
4/5
見積もり時間
3〜5日
活発さ
停滞
明瞭さ
おおむね明確
初心者へのやさしさ
35/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。