python / python/cpython

`TO_BOOL_INT` repeatedly misses for non-compact exact integers

未关闭
#155,486 4 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

interpreter-core performance type-bug
主要语言
Python
星标
77.2k
派生
35.9k
PR 合并指标
PR 指标待抓取

描述

Feature or enhancement

Proposal:

Versions

CPython 3.15.0b4, Ubuntu 24.04.4 LTS, gcc 13.3.0

Enhancement

I noticed that the specialization function for TO_BOOL and the guard used by TO_BOOL_INT accept different sets of integers.

_Py_Specialize_ToBool() selects TO_BOOL_INT for any exact integer:

if (PyLong_CheckExact(value)) {
    specialized_op = TO_BOOL_INT;
    goto success;
}

However, the TO_BOOL_INT macro uses _GUARD_TOS_INT, and that requires the integer to be compact:

op(_GUARD_TOS_INT, (value -- value)) {
    PyObject *value_o = PyStackRef_AsPyObjectBorrow(value);
    EXIT_IF(!_PyLong_CheckExactAndCompact(value_o));
}

As a result, a non-compact exact integer can cause TO_BOOL_INT to be selected and then immediately miss its guard.

This mismatch appears to have been introduced by GH-143759. Before the refactoring, TO_BOOL_INT had its own PyLong_CheckExact() guard. The refactoring replaced it with a macro using the shared _GUARD_TOS_INT, whose domain is narrower.

I see two alternative ways to fix this.

Option 1: narrow the specialization function

One option would be to change the integer check in _Py_Specialize_ToBool() so that it agrees with the existing guard:

if (_PyLong_CheckExactAndCompact(value)) {
    specialized_op = TO_BOOL_INT;
    goto success;
}

With this change, non-compact integers remain on the generic TO_BOOL path instead of repeatedly entering and missing TO_BOOL_INT.

My main concern with this option was whether the additional compactness check in the specialization function could regress the common case (compact int), so I benchmarked both compact and non-compact integers.

The benchmark target contained 100 TO_BOOL sites and was warmed up before each measurement:

start = time.perf_counter_ns()
for _ in range(10_000):
    target(value)
elapsed = time.perf_counter_ns() - start

Positive values mean that the patched build was faster:

Version Input Performance change
CPython 3.15 non-compact exact int +2.21% (95% CI: +1.64% to +2.86%)
CPython 3.15 compact exact int +0.31% (95% CI: −0.15% to +0.70%)
CPython main non-compact exact int +4.03% (95% CI: +1.43% to +7.10%)
CPython main compact exact int −0.23% (95% CI: −0.50% to +0.07%)

The non-compact case improved because it no longer repeatedly enters and misses TO_BOOL_INT. For compact integers, both confidence intervals include zero, so I did not find evidence that the stronger specialization check causes a regression.

Option 2: give TO_BOOL_INT an exact-int guard

The other option is to keep _Py_Specialize_ToBool() unchanged and add a guard that checks exact type without requiring compactness:

op(_GUARD_TOS_EXACT_INT, (value -- value)) {
    PyObject *value_o = PyStackRef_AsPyObjectBorrow(value);
    EXIT_IF(!PyLong_CheckExact(value_o));
}

The TO_BOOL_INT macro would then use the new guard:

macro(TO_BOOL_INT) =
    _GUARD_TOS_EXACT_INT +
    unused/1 +
    unused/2 +
    _TO_BOOL_INT +
    _POP_TOP_INT;

This would restore the specialization domain from before GH-143759.


I am not sure which of these two options is preferable, but the current mismatch seems worth fixing, so I am opening this issue to get feedback on which direction would be better.

Has this already been discussed elsewhere?

No response given

Links to previous discussion of this feature:

No response

Linked PRs
  • gh-155531
  • gh-155699
  • gh-155700

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从 Python/specialize.c 中的 _Py_Specialize_ToBool() 以及 Python/bytecodes.c 中的 TO_BOOL_INT 和 _GUARD_TOS_INT 开始。查看关联的 PR gh-155531、gh-155699 和 gh-155700,然后复现所述的预热基准测试;当 specialization 域和 guard 域达成一致且不再反复 miss 时,即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
c, python
领域
compilers, performance
Issue 类型
功能
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
35/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。