Skip to content

Performance regression: O(N²) compile time for large constant tuples after const folding moved to CFG #146455

Description

@zSirius

Bug report

Bug description:

After gh-126835 moved constant folding from AST to CFG (specifically gh-130769 for tuple folding and gh-129550 for unary/binary op folding), compiling files with large constant tuples suffers from an O(N²) slowdown.

The root cause is add_const() in Python/flowgraph.c — it does a linear scan over the consts list to find a constant's index by identity:

for (index=0; index<PyList_GET_SIZE(consts); index++) {
if (PyList_GET_ITEM(consts, index) ==newconst) {
break;
}
}

Before gh-126835, large constant tuples were folded in one shot at the AST stage, so add_const was rarely called with big consts lists. After gh-130769 moved tuple folding to CFG, fold_tuple_of_constants() calls add_const() once per inner tuple — N calls × O(N) scan = O(N²).

This also affects unary/binary op folding (fold_const_unaryop, fold_const_binop) moved to CFG in gh-129550:

  • (-1, -2, ..., -N) — each UNARY_NEGATIVE folded via add_const, 31.7x slower than 3.11 at N=100K
  • (0+1, 0+2, ..., 0+N) — each BINARY_OP folded via add_const, 9.7x slower at N=100K

perf profiling shows add_const taking 83.76% of CPU time at N=100K.

Performance impact (N=100K):

Scenario3.113.14 (regression)Slowdown
Nested tuples ((f, f), ...)1.24s10.38s8.4x
Unary neg (-1, -2, ..., -N)0.22s6.86s31.7x
Binary add (0+1, 0+2, ..., 0+N)0.27s2.59s9.7x

Reproducer:

importsys, timeN=int(sys.argv[1]) iflen(sys.argv) >1else100000elements=", ".join(f"({i*0.001:.6f}, {i*0.002:.6f})"foriinrange(N))
source=f"vertices = ({elements},)"t0=time.perf_counter()
code_obj=compile(source, "<test>", "exec")
t1=time.perf_counter()
print(f"Compile time: {t1-t0:.4f}s", flush=True)

Discussion: https://discuss.python.org/t/o-n-compile-time-regression-for-large-constant-tuples-after-const-folding-moved-to-cfg/106609

CPython versions tested on:

3.14, 3.15

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixes3.15pre-release feature fixes, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)performancePerformance or resource usagetype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions