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 — [3.14t] Free-threaded GC performance regression on tuples · Issue #142531 · python/cpython

[3.14t] Free-threaded GC performance regression on tuples #142531

New issue
Copy link
New issue
Copy link
Closed
Closed
[3.14t] Free-threaded GC performance regression on tuples#142531
Copy link
Labels
3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesperformancePerformance or resource usagePerformance or resource usagetopic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

Description

@MaxiBoether
MaxiBoether
opened on Dec 10, 2025
Issue body actions

Bug report

Bug description:

I am observing a significant performance regression in the Python 3.14.2 Free-Threading build compared to the build with GIL when constructing large lists of tuples.

This seems related to the recent work in issue #139951 and PR #140262. While the Standard 3.14.2 build appears to have resolved the performance regression, the Free-Threading build is still significantly slower in this scenario. I have confirmed that 3.14.0 (regular builld) shows the performance regression, 3.14.2 (regular) seems to have fixed it (thanks to the previous PR) but 3.14.2t (at least the version shipped on uv) still contains the issue.

I also see what is the output of gc.is_tracked (see below) for free threaded vs standard, there seems to be a difference but I did not dig into the details so far on how GC works on standard vs free threaded Python, sorry.

Benchmark Results (N=15,000,000) (r6id.8xlarge AWS instance)

Build GC State Time gc.is_tracked says
3.14.0 (Standard) Enabled 142.876s True
3.14.0 (Standard) Disabled 1.068s True
3.14.0 (Free-Threaded) Enabled 37.074s False
3.14.0 (Free-Threaded) Disabled 0.637s False
3.14.2 (Standard) Enabled 0.974s True
3.14.2 (Standard) Disabled 0.969s True
3.14.2 (Free-Threaded) Enabled 36.679s False
3.14.2 (Free-Threaded) Disabled 0.644s False

Reproduction Script

import time
import gc
import sys

def benchmark_step(disable_gc):
    if disable_gc: 
        gc.disable()
    
    t0 = time.perf_counter()
    _ = [(0, 0, i) for i in range(15_000_000)]
    dt = time.perf_counter() - t0
    
    status = "GC DISABLED" if disable_gc else "GC ENABLED "
    print(f"{status}: {dt:.3f}s")
    
    if disable_gc:
        gc.enable()

if __name__ == "__main__":
    print(f"Python Version: {sys.version}")
    sample = (0, 0, 1)
    print(f"Is tuple(int, int, int) tracked? {gc.is_tracked(sample)}")
    
    print("--- Benchmark ---")
    benchmark_step(disable_gc=False)
    benchmark_step(disable_gc=True)

In more detail this is my 3.14.2 regular build:
Python Version: 3.14.2 (main, Dec 9 2025, 19:03:28) [Clang 21.1.4 ]

And my free threaded build:
Python Version: 3.14.2 free-threading build (main, Dec 9 2025, 19:03:17) [Clang 21.1.4 ]

It's particularly weird that when disabling GC (despite the tuple being untracked) the regression goes away... Is it possible there is a disconnect between the flag is_tracked checks and the actual logic used by the free-threaded collector?

cc @colesbury @nascheme @markshannon

CPython versions tested on:

3.14

Operating systems tested on:

Linux

Linked PRs

  • gh-142531: Fix free-threaded GC performance regression #142562
  • [3.14] gh-142531: Fix free-threaded GC performance regression (gh-142562) #142617

Activity

  1. MaxiBoether
    added
    type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
    on Dec 10, 2025
  2. Eclips4
    added
    performancePerformance or resource usagePerformance or resource usage
    topic-free-threading
    on Dec 10, 2025
  3. sergey-miryanov commented on Dec 10, 2025

    @sergey-miryanov
    sergey-miryanov
    on Dec 10, 2025
    Contributor
    More actions

    Could you please do tests on 3.14.0ft?

  4. MaxiBoether commented on Dec 10, 2025

    @MaxiBoether
    MaxiBoether
    on Dec 10, 2025
    Author
    More actions

    Sure! Just added those numbers to the table

    Reacted by Sergey Miryanov
  5. sergey-miryanov commented on Dec 10, 2025

    @sergey-miryanov
    sergey-miryanov
    on Dec 10, 2025
    Contributor
    More actions

    Thanks!

  6. Eclips4
    added
    3.14bugs and security fixesbugs and security fixes
    on Dec 10, 2025
  7. colesbury commented on Dec 10, 2025

    @colesbury
    colesbury
    on Dec 10, 2025
    Contributor
    More actions

    I think the problem is that we are not counting untracked objects in "long_lived_total". The GC is scheduled in proportion to the number of live objects to avoid quadratic behavior, but untracked objects (like the tuples here) aren't being counted even though they contribute to the cost of GC. So we end up with quadratic behavior.

    The default build is different because untracked objects are removed from the GC linked lists and so don't contribute to GC cost.

    Reacted by Neil Schemenauer
  8. colesbury
    added
    3.15bugs and security fixesbugs and security fixes
    on Dec 10, 2025
  9. nascheme
    added a commit that references this issue on Dec 11, 2025

    pythongh-142531: Fix free-threaded GC performance regression

    40657c7
  10. nascheme commented on Dec 11, 2025

    @nascheme
    nascheme
    on Dec 11, 2025
    Member
    More actions

    With GH-142562:

    Python Version: 3.15.0a2+ free-threading build (heads/main-dirty:bc9e63dd9d2, Dec 10 2025, 22:54:51) [Clang 19.1.7 (3+b1)]
    Is tuple(int, int, int) tracked? False
    --- Benchmark ---
    GC ENABLED : 1.639s
    GC DISABLED: 0.389s
    

    Not as good as the default build but much improved.

    Reacted by Sergey Miryanov
    Reacted by Maximilian Böther
    Reacted by Sergey Miryanov and Chris Eibl
  11. nascheme
    added 3 commits that reference this issue on Dec 11, 2025

    Merge branch 'origin/main' into pythongh-142531-gc-untracked-tuples-l…

    4a65893

    gh-142531: Fix free-threaded GC performance regression (gh-142562)

    e38967e

    [3.14] pythongh-142531: Fix free-threaded GC performance regression (p…

    a6b237f
  12. fatelei
    added a commit that references this issue on Dec 12, 2025

    pythongh-142531: Fix free-threaded GC performance regression (pythong…

    ac2e042
  13. nascheme
    added a commit that references this issue on Dec 12, 2025

    [3.14] gh-142531: Fix free-threaded GC performance regression (gh-142562

    27f27a6
  14. colesbury commented on Dec 15, 2025

    @colesbury
    colesbury
    on Dec 15, 2025
    Contributor
    More actions

    @nascheme - can this be closed or is there more work to do?

  15. nascheme
    closed this as completedon Dec 15, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixesbugs and security fixes3.15bugs and security fixesbugs and security fixesperformancePerformance or resource usagePerformance or resource usagetopic-free-threadingtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402520 — 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.