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-126703: add freelist for PyComplexObject's by skirpichev · Pull Request #135233 · python/cpython

Conversation

@skirpichev

@skirpichev skirpichev commented Jun 7, 2025 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member
  • Issue: Use freelist for range object, iterator objects and other often used objects #126703

Micro-benchmark:

Benchmark ref patch
a+b 223 ns 198 ns: 1.13x faster
a*b 236 ns 209 ns: 1.13x faster
Geometric mean (ref) 1.13x faster
Details
# bench.py
import pyperf
from operator import add, mul
runner = pyperf.Runner()
a,b = 1+2j, -7+1.1j
runner.bench_func('a+b', add, a, b)
runner.bench_func('a*b', mul, a, b)

Sorry, something went wrong.

Uh oh!

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

efimov-mikhail reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@skirpichev
pythongh-126703: add freelist for PyComplexObject's
f031f94
@skirpichev
skirpichev requested a review from ericsnowcurrently as a code owner June 7, 2025 12:22
@skirpichev skirpichev added the skip news label Jun 7, 2025
@bedevere-app bedevere-app Bot added the awaiting review label Jun 7, 2025
@corona10
corona10 requested review from Fidget-Spinner and eendebakpt June 7, 2025 13:14
@corona10

corona10 commented Jun 7, 2025 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

@skirpichev Would you like to provide benchmark enhancement for this change?

All reactions

Sorry, something went wrong.

Uh oh!

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

@skirpichev

skirpichev commented Jun 7, 2025

Copy link
Copy Markdown
Member Author

Oops, I just forgot to post one. Description updated.

All reactions

Sorry, something went wrong.

Uh oh!

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

@corona10

corona10 commented Jun 7, 2025 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

Please share the pyperformance benchmark results.
I'm not sure how often complex types are used in real-world workloads.
Microbenchmarks like this might suggest adding every built-in type to the freelist, but I don't think that's what we want.
Most of the types we've added so far are commonly used in loop-based operations.

cc @Fidget-Spinner @encukou @eendebakpt

All reactions

Sorry, something went wrong.

Uh oh!

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

@skirpichev
skirpichev marked this pull request as draft June 7, 2025 13:51
@bedevere-app bedevere-app Bot removed the awaiting review label Jun 7, 2025
@skirpichev

skirpichev commented Jun 7, 2025

Copy link
Copy Markdown
Member Author

Please share the pyperformance benchmark results.

Well, it shouldn't be affected. This collection has no benchmarks for complex math at all:

$ git grep _E '[0-9.][jJ]|cmath|complex' pyperformance/data-files/benchmarks/||echo Oops
Oops

I'm not sure how often complex types are used in real-world workloads.

Probably less than floats, but not too much.

All reactions

Sorry, something went wrong.

Uh oh!

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

@skirpichev
skirpichev marked this pull request as ready for review June 7, 2025 14:12
@bedevere-app bedevere-app Bot added the awaiting review label Jun 7, 2025
@encukou

encukou commented Jun 7, 2025

Copy link
Copy Markdown
Member

AFAICS, real-world workloads that don't use complex numbers will pay the price of:

  • two unused words of memory
  • the maintenance burden of a (I assume!) standard and unsurprising use of _Py_freelist

In applications that do use complex numbers, is it likely that they need to create/destroy them quickly?
IMO, an educated guess is enough to answer that, and if we've established that this is what freelists help with... I'd just trust Sergey here.

To review this I'll need to teach myself about Python's freelists; I can do that next week.

All reactions

Sorry, something went wrong.

Uh oh!

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

@corona10

corona10 commented Jun 7, 2025 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

IMO, an educated guess is enough to answer that, and if we've established that this is what freelists help with... I'd just trust Sergey here.

I believe that we use pyperformance benchmark as the real world proxy. So if there is no benchmark for it, I am unsure. At least someone needs to share the benchmark for this. If not, people will add new PR for other built-in types with a microbenchmark, which would not be worth adding. We need criteria for this.

efimov-mikhail reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

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

@skirpichev

skirpichev commented Jun 7, 2025

Copy link
Copy Markdown
Member Author

two unused words of memory

Yes, just a new empty _Py_freelists.

In applications that do use complex numbers, is it likely that they need to create/destroy them quickly?

That happens in every arithmetic operation.

Here is a benchmark with a simple sin() implementation:

Benchmark ref patch
mysin(1j) 14.0 us 12.8 us: 1.09x faster
mysin(1+1j) 15.7 us 14.4 us: 1.09x faster
Geometric mean (ref) 1.09x faster
Details
# bench2.py
def mysin(z):
    i, lasts, s, fact, num, sign = 1, 0, z, 1, z, 1
    while s != lasts:
        lasts = s
        i += 2
        fact *= i*(i-1)
        num *= z*z
        sign *= -1
        s += num/fact*sign
    return s
import pyperf
runner = pyperf.Runner()
runner.bench_func('mysin(1j)', mysin, 1j)
runner.bench_func('mysin(1+1j)', mysin, 1+1j)

To review this I'll need to teach myself about Python's freelists

You are not alone, this is new for me as well :D IIUC (see help topic), this technique is not something, allowed for external C extensions.

If not, people will add new PR for other built-in types with a microbenchmark

I doubt we have too much built-in types. Being a built-in type is a sign from the real world too ;-)

All reactions

Sorry, something went wrong.

Uh oh!

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

@encukou

encukou commented Jun 9, 2025

Copy link
Copy Markdown
Member

I see this as a PR that speeds up complex numbers, not “X% of Python's real-world usage”. And that's fine.

We need criteria for this.

Why shouldn't the criteria be “any small builtin type where typical usage needs many instances”?

If not, people will add new PR for other built-in types with a microbenchmark, which would not be worth adding.

Why not? What would be the downside of all such built-in types using freelists?

skirpichev reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

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

@corona10

corona10 commented Jun 12, 2025 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

Why shouldn't the criteria be “any small builtin type where typical usage needs many instances”?
Why not? What would be the downside of all such built-in types using freelists?

Then why don’t we just register all built-in objects to the freelist? I think our primary focus is on keeping maintenance costs low. Once we add complex to the freelist, we’ll need to maintain it anyway.

We already have over 20 object types registered. If we’re going to add more, shouldn’t we also consider a more manageable way to maintain them?

We take a similar approach when deciding not to add a fast path, if the benefit isn’t significant enough, we skip it. From what I’ve observed, most recent optimizations are based on pyperformance results.

That said, if you still think we should add this, please go ahead. I just wanted to share my concern about adding it by default. Once an object is added to the freelist, it will usually see some benefit, but we should still weigh that against the maintenance burden.

All reactions

Sorry, something went wrong.

Uh oh!

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

vstinner
vstinner reviewed Jun 12, 2025
View reviewed changes
Comment thread Include/internal/pycore_freelist_state.h Resolved

Uh oh!

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

@vstinner

vstinner commented Jun 12, 2025

Copy link
Copy Markdown
Member

We already have over 20 object types registered. If we’re going to add more, shouldn’t we also consider a more manageable way to maintain them?

We already have an API for that, the _Py_freelist API which is being used in this PR, no? What do you mean by "a more manageable way to maintain them"?

All reactions

Sorry, something went wrong.

Uh oh!

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

@corona10

corona10 commented Jun 12, 2025

Copy link
Copy Markdown
Member

We already have an API for that, the _Py_freelist API which is being used in this PR, no? What do you mean by "a more manageable way to maintain them"?

I thought of managing the list of types and generating the pycore_freelist_state.h with a Python script. but it looks like not simple, though.

All reactions

Sorry, something went wrong.

Uh oh!

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

@vstinner

vstinner commented Jun 12, 2025

Copy link
Copy Markdown
Member

I thought of managing the list of types and generating the pycore_freelist_state.h with a Python script. but it looks like not simple, though.

Oh ok, I see. I'm not sure that it's worth it. This list evolves rarely and IMO the maintenance cost is low.

All reactions

Sorry, something went wrong.

Uh oh!

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

skirpichev added 2 commits June 13, 2025 06:10
@skirpichev
Merge branch 'master' into complexes-freelist/126703
cf5287a
@skirpichev
address review: _PyObject_ClearFreeLists()
b5946f0
@skirpichev
skirpichev requested a review from vstinner June 13, 2025 03:14
@skirpichev

skirpichev commented Jun 13, 2025

Copy link
Copy Markdown
Member Author

From what I’ve observed, most recent optimizations are based on pyperformance results.

But pyperformance can't measure any performance changes in the Python core type, complex. Is that a bug or a feature?

All reactions

Sorry, something went wrong.

Uh oh!

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

@corona10

corona10 commented Jun 13, 2025 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

But pyperformance can't measure any performance changes in the Python core type, complex. Is that a bug or a feature?

In the past, we observed many optimization enhancements for the binary operation, especially for the int or float types.
More worth optimization would be lowering the opcodes at the JIT optimzation what Ken Jin and Brandt is doing :)

All reactions

Sorry, something went wrong.

Uh oh!

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

@skirpichev

skirpichev commented Jun 13, 2025

Copy link
Copy Markdown
Member Author

we observed many optimization enhancements for the binary operation, especially for the int or float types.

This is possible for complex type as well, but it's another story.

All reactions

Sorry, something went wrong.

Uh oh!

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

vstinner
vstinner approved these changes Jun 13, 2025
View reviewed changes

@vstinner vstinner left a comment

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.

LGTM. The change is short and 1.09x faster on the mysin() micro-benchmark is worth it IMO.

@corona10: You consider that the change is not worth it?

Sorry, something went wrong.

Uh oh!

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

All reactions
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting review labels Jun 13, 2025
corona10
corona10 approved these changes Jun 13, 2025
View reviewed changes

@corona10 corona10 left a comment

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.

LGTM, Okay, let's consider the possibility of usage in the scientific area.

Sorry, something went wrong.

Uh oh!

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

vstinner and efimov-mikhail reacted with thumbs up emoji
All reactions
  • 👍 2 reactions
@corona10
corona10 merged commit c646846 into python:main Jun 13, 2025
@bedevere-app bedevere-app Bot removed the awaiting merge label Jun 13, 2025
@skirpichev
skirpichev deleted the complexes-freelist/126703 branch June 18, 2025 03:10
lkollar pushed a commit to lkollar/cpython that referenced this pull request Jun 19, 2025
@skirpichev @lkollar
pythongh-126703: Add freelist for PyComplexObject's (pythongh-135233)
b12ab98
Pranjal095 pushed a commit to Pranjal095/cpython that referenced this pull request Jul 12, 2025
@skirpichev @Pranjal095
pythongh-126703: Add freelist for PyComplexObject's (pythongh-135233)
acc64b6
taegyunkim pushed a commit to taegyunkim/cpython that referenced this pull request Aug 4, 2025
@skirpichev @taegyunkim
pythongh-126703: Add freelist for PyComplexObject's (pythongh-135233)
536c541
Agent-Hellboy pushed a commit to Agent-Hellboy/cpython that referenced this pull request Aug 19, 2025
@skirpichev @Agent-Hellboy
pythongh-126703: Add freelist for PyComplexObject's (pythongh-135233)
8031adf
@skirpichev skirpichev mentioned this pull request Feb 26, 2026
Add benchmarks for complex type python/pyperformance#458
Open
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@vstinner vstinner vstinner approved these changes
@corona10 corona10 corona10 approved these changes
@ericsnowcurrently ericsnowcurrently Awaiting requested review from ericsnowcurrently ericsnowcurrently is a code owner
@eendebakpt eendebakpt Awaiting requested review from eendebakpt
@Fidget-Spinner Fidget-Spinner Awaiting requested review from Fidget-Spinner

Uh oh!

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

Assignees

No one assigned

Labels

skip news

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.

4 participants

@skirpichev @corona10 @encukou @vstinner
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.