GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-146455: Fix O(N²) in add_const() after constant folding moved to CFG by zSirius · Pull Request #146456 · python/cpython

Conversation

@zSirius

@zSirius zSirius commented Mar 26, 2026 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Fix O(N²) performance regression in add_const() introduced by moving constant folding from AST to CFG optimizer (gh-126835).

Problem

After gh-130769 moved tuple folding to CFG, fold_tuple_of_constants() calls add_const() once per inner tuple element. add_const() does a linear scan over the consts list to find the index, so N calls × O(N) scan = O(N²).

The same issue affects unary/binary op folding moved in gh-129550 (fold_const_unaryop, fold_const_binop).

perf profiling shows add_const taking 83.76% of CPU time when compiling 100K nested constant tuples.

Fix

Maintain an auxiliary _Py_hashtable_t (pointer → index mapping) alongside the consts list, providing O(1) constant lookup. The hashtable:

  • Uses _Py_hashtable_hash_ptr / _Py_hashtable_compare_direct — pure pointer ops, no Python object overhead
  • Is created at the start of _PyCfg_OptimizeCodeUnit() and destroyed after optimize_cfg(), before remove_unused_consts() reindexes the list
  • Works correctly because _PyCompile_ConstCacheMergeOne() already guarantees identity uniqueness (equal-valued constants share the same pointer)

All modified functions are static — no public API changes.

Performance (N=100K)

Scenario 3.11 3.14 (before) 3.14 (after fix)
Nested tuples ((f, f), ...) 1.24s 10.38s 1.48s
Unary neg (-1, -2, ..., -N) 0.22s 6.86s 1.12s
Binary add (0+1, 0+2, ..., 0+N) 0.27s 2.59s 1.40s

All existing tests pass: test_compile, test_peepholer, test_ast, test_dis.

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

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
zhuangjinkai
pythongh-146455: Fix O(N²) in add_const() after constant folding move…
2a67136
…d to CFG

The add_const() function in flowgraph.c uses a linear search over the
consts list to find the index of a constant. After pythongh-126835 moved
constant folding from the AST optimizer to the CFG optimizer, this
function is now called N times for N inner tuple elements during
fold_tuple_of_constants(), resulting in O(N²) total time.

Fix by maintaining an auxiliary _Py_hashtable_t that maps object
pointers to their indices in the consts list, providing O(1) lookup.

For a file with 100,000 constant 2-tuples:
- Before: 10.38s (add_const occupies 83.76% of CPU time)
- After:  1.48s
@zSirius
zSirius requested review from iritkatriel and markshannon as code owners March 26, 2026 08:39
@bedevere-app

bedevere-app Bot commented Mar 26, 2026

Copy link
Copy Markdown

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot mentioned this pull request Mar 26, 2026
Performance regression: O(N²) compile time for large constant tuples after const folding moved to CFG #146455
Closed
@bedevere-app bedevere-app Bot added the awaiting review label Mar 26, 2026
zhuangjinkai
📜🤖 Added by blurb_it.
cebc9fc
@Eclips4
Eclips4 self-requested a review March 26, 2026 13:06
Eclips4
Eclips4 reviewed Apr 21, 2026
View reviewed changes
Comment thread Python/flowgraph.c Outdated
Comment on lines +1337 to +1365
/* O(1) lookup via pointer-keyed hashtable (replaces linear search). */
_Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(consts_index, (void *)newconst);
if (entry != NULL) {
/* Already exists */
Py_DECREF(newconst);
return (int)(uintptr_t)entry->value;
}
if (index == PyList_GET_SIZE(consts)) {
if ((size_t)index >= (size_t)INT_MAX - 1) {
PyErr_SetString(PyExc_OverflowError, "too many constants");
Py_DECREF(newconst);
return -1;
}
if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst);
return -1;
}

/* Not found – append to consts list */
Py_ssize_t index = PyList_GET_SIZE(consts);
if ((size_t)index >= (size_t)INT_MAX - 1) {
PyErr_SetString(PyExc_OverflowError, "too many constants");
Py_DECREF(newconst);
return -1;
}
if (PyList_Append(consts, newconst)) {
Py_DECREF(newconst);
return -1;
}

/* Update index (must be after successful append) */
if (_Py_hashtable_set(consts_index, (void *)newconst, (void *)(uintptr_t)index) < 0) {
/* OOM – rollback append for consistency */
PyList_SetSlice(consts, index, index + 1, NULL);
Py_DECREF(newconst);
PyErr_NoMemory();
return -1;
}

@Eclips4 Eclips4 Apr 21, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please remove those comments? They're unnecessary since the code is pretty straightforward

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@zSirius zSirius Apr 22, 2026

Copy link
Copy Markdown
Contributor Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed all comments.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Eclips4
Eclips4 reviewed Apr 21, 2026
View reviewed changes
Comment thread Python/flowgraph.c Outdated
Comment on lines +3691 to +3715
/* Auxiliary pointer→index hashtable for O(1) lookup in add_const. */
_Py_hashtable_t *consts_index = _Py_hashtable_new(
_Py_hashtable_hash_ptr, _Py_hashtable_compare_direct);
if (consts_index == NULL) {
PyErr_NoMemory();
return ERROR;
}

/* Seed the index with pre-existing constants. */
for (Py_ssize_t i = 0; i < PyList_GET_SIZE(consts); i++) {
PyObject *item = PyList_GET_ITEM(consts, i);
if (_Py_hashtable_get_entry(consts_index, (void *)item) != NULL) {
continue; /* duplicate pointer; keep first occurrence */
}
if (_Py_hashtable_set(consts_index, (void *)item,
(void *)(uintptr_t)i) < 0) {
_Py_hashtable_destroy(consts_index);
PyErr_NoMemory();
return ERROR;
}
}

int ret = optimize_cfg(g, consts, const_cache, consts_index, firstlineno);

/* consts_index is invalid after this (consts list may be modified). */

@Eclips4 Eclips4 Apr 21, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And those comments also.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
zhuangjinkai
Remove unnecessary comments
ef2e494
@Eclips4
Eclips4 self-requested a review April 22, 2026 16:21
@Eclips4 Eclips4 mentioned this pull request Apr 26, 2026
sets with >30 elements not constant-folded in in/not in and for loops #148817
Closed
@Eclips4

Eclips4 commented Apr 26, 2026

Copy link
Copy Markdown
Member

FWIW, I've run refleak tests and everything seems to be fine.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Eclips4

Eclips4 commented Apr 26, 2026

Copy link
Copy Markdown
Member

The results from the issue are confirmed.

After this PR (I took the example from the issue), Macbook Pro M3 Pro:
Compile time: 1.2689s
Before this PR:
Compile time: 8.6341s

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Eclips4
Eclips4 merged commit 5d41632 into python:main Apr 26, 2026
54 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting review label Apr 26, 2026
@Eclips4

Eclips4 commented Apr 26, 2026

Copy link
Copy Markdown
Member

Thank you @zSirius!

zSirius reacted with laugh emoji
All reactions
  • 😄 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Eclips4 Eclips4 added the needs backport to 3.14 bugs and security fixes label Apr 26, 2026
@miss-islington-app

miss-islington-app Bot commented Apr 26, 2026

Copy link
Copy Markdown

Thanks @zSirius for the PR, and @Eclips4 for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14.
🐍🍒⛏🤖

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app

bedevere-app Bot commented Apr 26, 2026

Copy link
Copy Markdown

GH-149011 is a backport of this pull request to the 3.14 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label Apr 26, 2026
@Eclips4

Eclips4 commented Apr 26, 2026

Copy link
Copy Markdown
Member

@zSirius Can you please sign the CLA in #149011?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

iritkatriel
iritkatriel reviewed Apr 26, 2026
View reviewed changes
Comment thread Python/flowgraph.c
PyErr_NoMemory();
return ERROR;
}
}

@iritkatriel iritkatriel Apr 26, 2026

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can make const_cache be a data structure that maps bi-directionally, so that we don't need to do this here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Eclips4 pushed a commit that referenced this pull request Apr 26, 2026
@miss-islington @zSirius
[3.14] gh-146455: Fix O(N²) in add_const() after constant folding mov…
78c5e54
…ed to CFG (GH-146456) (#149011)

gh-146455: Fix O(N²) in add_const() after constant folding moved to CFG (GH-146456)

The add_const() function in flowgraph.c uses a linear search over the
consts list to find the index of a constant. After gh-126835 moved
constant folding from the AST optimizer to the CFG optimizer, this
function is now called N times for N inner tuple elements during
fold_tuple_of_constants(), resulting in O(N²) total time.

Fix by maintaining an auxiliary _Py_hashtable_t that maps object
pointers to their indices in the consts list, providing O(1) lookup.

For a file with 100,000 constant 2-tuples:
- Before: 10.38s (add_const occupies 83.76% of CPU time)
- After:  1.48s
(cherry picked from commit 5d41632)

Co-authored-by: zSirius <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@iritkatriel iritkatriel iritkatriel left review comments
@markshannon markshannon Awaiting requested review from markshannon markshannon is a code owner
@Eclips4 Eclips4 Awaiting requested review from Eclips4 Eclips4 is a code owner

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@zSirius @Eclips4 @iritkatriel
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.