Skip to content

Use freelist only on CPython#349

Merged
skirpichev merged 3 commits into
diofant:masterfrom
skirpichev:freelist/301
Jul 8, 2026
Merged

Use freelist only on CPython#349
skirpichev merged 3 commits into
diofant:masterfrom
skirpichev:freelist/301

Conversation

@skirpichev

Copy link
Copy Markdown
Member

closes #301

This optimization seems working on the GraalPy, but looks useless:

collatz0(871): Mean +- std dev: [nocache-graalpy] 2.19 ms +- 1.14 ms -> [graalpy] 5.12 ms +- 3.54 ms: 2.34x slower
collatz0((1<<128)+31): Mean +- std dev: [nocache-graalpy] 25.6 ms +- 13.5 ms -> [graalpy] 17.6 ms +- 14.4 ms: 1.45x faster
collatz1(97): Mean +- std dev: [nocache-graalpy] 4.40 ms +- 3.17 ms -> [graalpy] 2.15 ms +- 1.98 ms: 2.05x faster
collatz1(871): Mean +- std dev: [nocache-graalpy] 2.49 ms +- 2.22 ms -> [graalpy] 4.84 ms +- 3.92 ms: 1.94x slower
collatz2(871): Mean +- std dev: [nocache-graalpy] 2.24 ms +- 1.11 ms -> [graalpy] 5.06 ms +- 3.67 ms: 2.26x slower
collatz2((1<<128)+31): Mean +- std dev: [nocache-graalpy] 11.6 ms +- 8.2 ms -> [graalpy] 25.9 ms +- 15.1 ms: 2.23x slower

Benchmark hidden because not significant (3): collatz0(97), collatz1((1<<128)+31), collatz2(97)

Geometric mean: 1.26x slower

While on CPython:
collatz0(97): Mean +- std dev: [nocache-cpython] 122 us +- 2 us -> [cpython] 87.4 us +- 1.6 us: 1.40x faster
collatz0(871): Mean +- std dev: [nocache-cpython] 184 us +- 3 us -> [cpython] 131 us +- 4 us: 1.40x faster
collatz0((1<<128)+31): Mean +- std dev: [nocache-cpython] 968 us +- 17 us -> [cpython] 699 us +- 32 us: 1.38x faster
collatz1(97): Mean +- std dev: [nocache-cpython] 152 us +- 4 us -> [cpython] 105 us +- 3 us: 1.45x faster
collatz1(871): Mean +- std dev: [nocache-cpython] 231 us +- 13 us -> [cpython] 158 us +- 1 us: 1.47x faster
collatz1((1<<128)+31): Mean +- std dev: [nocache-cpython] 1.22 ms +- 0.05 ms -> [cpython] 847 us +- 14 us: 1.43x faster
collatz2(97): Mean +- std dev: [nocache-cpython] 124 us +- 2 us -> [cpython] 87.4 us +- 0.4 us: 1.41x faster
collatz2(871): Mean +- std dev: [nocache-cpython] 187 us +- 7 us -> [cpython] 131 us +- 1 us: 1.43x faster
collatz2((1<<128)+31): Mean +- std dev: [nocache-cpython] 988 us +- 24 us -> [cpython] 703 us +- 2 us: 1.41x faster

Geometric mean: 1.42x faster

This approach doesn't work on PyPy (triggers "Invalid usage of a dying
CPython object" error), but hardly it does make sense here.  For
instance, following pure-Python benchmark shows same numbers on PyPy,
regardless on freelist size:
```
import os
import pyperf
from operator import add

_freelist = []
_max_freelist_size = int(os.getenv("FREELIST_SIZE"))

class xyz:
    def __new__(cls, *args, **kwargs):
        if _freelist:
            # Reuse an existing instance from the pool
            instance = _freelist.pop()
            return instance

        # Fall back to standard memory allocation if pool is empty
        return super().__new__(cls)

    def __init__(self, value):
        self.value = value

    def __del__(self):
        if len(_freelist) < _max_freelist_size:
            # Resurrect 'self' by adding it to the free-list
            _freelist.append(self)

    def __add__(self, other):
        return xyz(self.value + other.value)

    def __repr__(self):
        return f"xyz('{self.value}')"

x, y = map(xyz, [123, 321])
runner = pyperf.Runner()
s = repr(x) + " + " + repr(y)
runner.bench_func(s, add, x, y)
```

Closes diofant#301
@skirpichev skirpichev added this to the 0.6 milestone Jul 8, 2026
@skirpichev skirpichev enabled auto-merge July 8, 2026 05:54
@skirpichev skirpichev merged commit 9fc2882 into diofant:master Jul 8, 2026
13 checks passed
@skirpichev skirpichev deleted the freelist/301 branch July 8, 2026 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement caching properly

1 participant