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-115999: Add free-threaded specialization for `UNPACK_SEQUENCE` by Eclips4 · Pull Request #126600 · python/cpython

Conversation

@Eclips4

@Eclips4 Eclips4 commented Nov 8, 2024 •
edited by bedevere-app Bot
Loading

Uh oh!

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

Copy link
Copy Markdown
Member
  • Issue: Make the specializing interpreter thread-safe in --disable-gil builds #115999

Sorry, something went wrong.

Uh oh!

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

DmitryHudrich reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
Eclips4 added 2 commits November 8, 2024 15:52
@Eclips4
Add FT specialization
5e0d875
@Eclips4
Add test case
fa8ff2f
@Eclips4 Eclips4 added skip news topic-free-threading labels Nov 8, 2024
@Eclips4
Eclips4 requested a review from mpage November 8, 2024 20:14
@Eclips4
Eclips4 requested a review from markshannon as a code owner November 8, 2024 20:14
@bedevere-app bedevere-app Bot added the awaiting core review label Nov 8, 2024
@bedevere-app bedevere-app Bot mentioned this pull request Nov 8, 2024
Make the specializing interpreter thread-safe in --disable-gil builds #115999
Closed
brandtbucher
brandtbucher reviewed Nov 8, 2024
View reviewed changes
Comment thread Lib/test/test_opcache.py
def test_unpack_sequence(self):
def f():
for _ in range(100):
a, b = 1, 2

@brandtbucher brandtbucher Nov 8, 2024

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.

Sort of unrelated to this PR, but I'm surprised constant unpacking like this isn't peepholed into LOAD_CONST, STORE_FAST, LOAD_CONST, STORE_FAST. Maybe because it's actually a longer instruction sequence than the original? It certainly does less work.

@iritkatriel, thoughts?

Sorry, something went wrong.

Uh oh!

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

All reactions
mpage
mpage requested changes Nov 8, 2024
View reviewed changes

@mpage mpage left a comment •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Contributor

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.

Thanks for doing this! The changes look good. I think the current implementations of UNPACK_SEQUENCE_{TUPLE,TWO_TUPLE} are already thread-safe since tuples are immutable. The implementation of UNPACK_SEQUENCE_LIST isn't thread-safe (there is nothing preventing another thread from adding or removing items from the list while the instruction is executing) so we're going to need a slightly different implementation in the free-threaded build.

I would suggest taking a critical section around the list size check and the code that pushes items onto the stack. Something like:

inst(UNPACK_SEQUENCE_LIST, (unused/1, seq -- values[oparg])) {
    PyObject *seq_o = PyStackRef_AsPyObjectBorrow(seq);
    DEOPT_IF(!PyList_CheckExact(seq_o));
    int should_deopt = 0;
    Py_BEGIN_CRITICAL_SECTION(seq_o);
    should_deopt = PyList_GET_SIZE(seq_o) != oparg;
    if (!should_deopt) {
        STAT_INC(UNPACK_SEQUENCE, hit);
        PyObject **items = _PyList_ITEMS(seq_o);
        for (int i = oparg; --i >= 0; ) {
            *values++ = PyStackRef_FromPyObjectNew(items[i]);
        }
    }
    Py_END_CRITICAL_SECTION();
    DEOPT_IF(should_deopt);
    DECREF_INPUTS();
}

Sorry, something went wrong.

Uh oh!

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

Eclips4 reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
Comment thread Python/bytecodes.c Resolved

Uh oh!

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

@bedevere-app bedevere-app Bot removed the awaiting core review label Nov 8, 2024
@bedevere-app

bedevere-app Bot commented Nov 8, 2024

Copy link
Copy Markdown

When you're done making the requested changes, leave the comment: I have made the requested changes; please review again.

All reactions

Sorry, something went wrong.

Uh oh!

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

@bedevere-app bedevere-app Bot added the awaiting changes label Nov 8, 2024
@Eclips4
Address Matt's review
d49e9e6
@Eclips4
Eclips4 requested a review from mpage November 8, 2024 21:57
mpage
mpage approved these changes Nov 8, 2024
View reviewed changes

@mpage mpage left a comment

Copy link
Copy Markdown
Contributor

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!

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 changes labels Nov 8, 2024
ruidazeng
ruidazeng approved these changes Nov 9, 2024
View reviewed changes
markshannon
markshannon reviewed Nov 12, 2024
View reviewed changes
Comment thread Python/bytecodes.c Outdated
*values++ = PyStackRef_FromPyObjectNew(items[i]);
int should_deopt = 0;
Py_BEGIN_CRITICAL_SECTION(seq_o);
should_deopt = PyList_GET_SIZE(seq_o) != oparg;

@markshannon markshannon Nov 12, 2024

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.

Could this be rewritten as something like:

    if (PyList_GET_SIZE(seq_o) != oparg) {
         END_CRITICAL_SECTION
         DEOPT_IF(true);
    }

Sorry, something went wrong.

Uh oh!

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

All reactions

@mpage mpage Nov 13, 2024

Copy link
Copy Markdown
Contributor

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.

We can't use the macros because they introduce and close a new scope.

I don't think there's precedence in CPython for using the critical section functions manually (everything uses the macros), but if it's important that we maintain the structure you're suggesting we could do something like

#ifdef Py_GIL_DISABLED
PyCriticalSection _py_cs;
PyCriticalSection_Begin(&_py_cs, seq_o);
#endif
if (PyList_GET_SIZE(seq_o) != oparg) {
    #ifdef Py_GIL_DISABLED
    PyCriticalSection_End(&_py_cs);
    #endif
    DEOPT_IF(true);
}
STAT_INC(UNPACK_SEQUENCE, hit);
PyObject **items = _PyList_ITEMS(seq_o);
for (int i = oparg; --i >= 0; ) {
    *values++ = PyStackRef_FromPyObjectNew(items[i]);
}
#ifdef Py_GIL_DISABLED
PyCriticalSection_End(&_py_cs);
#endif
DECREF_INPUTS();

Note that the preprocessor guards are not necessary for correctness; the critical section functions are a no-op in default builds.

Sorry, something went wrong.

Uh oh!

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

All reactions
markshannon
markshannon reviewed Nov 12, 2024
View reviewed changes

@markshannon markshannon 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.

This doesn't fit into the general pattern of specialized instructions:

  • One or more guards
  • Zero or one actions

See the docs for why this matters.

Has this been benchmarked?

Sorry, something went wrong.

Uh oh!

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

All reactions
@mpage

mpage commented Nov 13, 2024 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Contributor

Has this been benchmarked?

Performance is neutral overall on the default build. Though strangely the results for the unpack sequence benchmark look like this change is significantly faster. I'm not sure how reliable that benchmark is, however.

Performance is improved by 2% overall on the free-threaded build.

All reactions

Sorry, something went wrong.

Uh oh!

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

@mpage
Refactor UNPACK_SEQUENCE_LIST
ea1abf3
@mpage

mpage commented Nov 16, 2024

Copy link
Copy Markdown
Contributor

@markshannon - Please have another look at this.

All reactions

Sorry, something went wrong.

Uh oh!

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

@mpage
mpage requested a review from markshannon November 16, 2024 00:42
Eclips4 added 2 commits November 21, 2024 13:50
@Eclips4
Merge branch 'main' into ft-specialize-unpack-sequence
7ad46ad
@Eclips4
Align PR with recent changes
66a2d67
@Eclips4
Eclips4 requested a review from mpage November 21, 2024 12:01
mpage
mpage approved these changes Nov 21, 2024
View reviewed changes

@mpage mpage left a comment

Copy link
Copy Markdown
Contributor

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!

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread Python/specialize.c Resolved

Uh oh!

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

@Eclips4 @mpage
Update Python/specialize.c
16093d6
Co-authored-by: mpage <[email protected]>
@mpage

mpage commented Nov 22, 2024

Copy link
Copy Markdown
Contributor

@Eclips4 - I think it would be fine to merge this PR. We can put up follow up PRs if any subsequent changes are required.

Eclips4 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.

@Eclips4
Eclips4 merged commit 27486c3 into python:main Nov 22, 2024
@bedevere-app bedevere-app Bot removed the awaiting merge label Nov 22, 2024
@Eclips4
Eclips4 deleted the ft-specialize-unpack-sequence branch November 22, 2024 17:00
ebonnal pushed a commit to ebonnal/cpython that referenced this pull request Jan 12, 2025
@Eclips4 @mpage @ebonnal
pythongh-115999: Add free-threaded specialization for `UNPACK_SEQUENC…
11761fc
…E` (python#126600)

Add free-threaded specialization for `UNPACK_SEQUENCE` opcode.
`UNPACK_SEQUENCE_TUPLE/UNPACK_SEQUENCE_TWO_TUPLE` are already thread safe since tuples are immutable.
`UNPACK_SEQUENCE_LIST` is not thread safe because of nature of lists (there is nothing preventing another thread from adding items to or removing them the list while the instruction is executing). To achieve thread safety we add a critical section to the implementation of `UNPACK_SEQUENCE_LIST`, especially around the parts where we check the size of the list and push items onto the stack.


---------

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

Reviewers

@brandtbucher brandtbucher brandtbucher left review comments
@mpage mpage mpage approved these changes
@markshannon markshannon Awaiting requested review from markshannon markshannon is a code owner
+1 more reviewer
@ruidazeng ruidazeng ruidazeng approved these changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

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

Assignees

No one assigned

Labels

skip news topic-free-threading

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.

5 participants

@Eclips4 @mpage @markshannon @ruidazeng @brandtbucher
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 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.