Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-112087: Make list_repr and list_length to be thread-safe#114582

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
corona10 merged 3 commits intopython:mainfromcorona10:gh-112087-repr-length
Jan 26, 2024

Conversation

@corona10
Copy link
Member

@corona10corona10 commentedJan 26, 2024
edited by bedevere-appbot
Loading

@corona10
Copy link
MemberAuthor

corona10 commentedJan 26, 2024
edited
Loading

I just worked on 2 methods becauselist_length is the first method that requires_Py_atomic_load_ssize_relaxed which creates fragmented implementation. until now, just usingPy_BEGIN_CRITICAL_SECTION API or@critical_section annotation was enough, but from now it's not.

So from now, I would like to check other core devs opinions about this.

I expect that@serhiy-storchaka can propose a better solution :)
Also,@ambv can have other ideas about this.
The reference implementation is based oncolesbury/nogil-3.12@df4c51f82b

Once we decide about the fragmented implementations with atomic API, we can start to implement the rest of things in a unified and satisfied way.

@corona10corona10 requested a review fromambvJanuary 26, 2024 08:16
@encukou
Copy link
Member

This looks maintainable enough to me.

I can't quite check if it's “thread safe” -- AFAIK we don't really define what that is, yet.
One thing that's not clear to me is whetherPy_SIZE itself should be atomic, or if all calls to it should be replaced by an atomic load (or in critical sections).

corona10 and serhiy-storchaka reacted with thumbs up emoji

#ifdefPy_GIL_DISABLED
return_Py_atomic_load_ssize_relaxed(&(_PyVarObject_CAST(a)->ob_size));
#else
returnPy_SIZE(a);
Copy link
MemberAuthor

@corona10corona10Jan 26, 2024
edited
Loading

Choose a reason for hiding this comment

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

@encukou said that makingPy_SIZE to be thread-safe for free-threaded build would be beneficial rather than implementinglist_length with macro if possible :)

Copy link
Member

Choose a reason for hiding this comment

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

Itcould. I don't know enough about the grand plan to know for sure :)

Copy link
Contributor

Choose a reason for hiding this comment

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

I think pushing the atomic load down toPy_SIZE() is reasonable and will probably simplify call sites.

That was something I tried and then abandoned in nogil-3.9 because at the time the macro was also used as an l-value likePy_SIZE(ob) = 1. Fortunately, that's no longer a concern.

erlend-aasland reacted with thumbs up emoji
Copy link
Contributor

Choose a reason for hiding this comment

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

Alternatively, we could just do the atomic load inPyList_GET_SIZE() and consistently use that within this file. I think I'd prefer that.

There are some loops that usePy_SIZE() on immutable objects that might slow down if we makePy_SIZE use an atomic load. For example, incodeobject.c:

while (entry_point<Py_SIZE(co)&&
_PyCode_CODE(co)[entry_point].op.code!=RESUME) {
entry_point++;
}

The compiler will currently lift thePy_SIZE() load outside the loop. But it won't do that optimization with an atomic load.

It's hard to know if these sorts of things will make a difference overall, but it's often easier to avoid the potential performance issues in the first place than trying to find, benchmark, and fix the issues later.

erlend-aasland reacted with thumbs up emoji
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, my opinion keeps changing as I read throughlistobject.c. Changing all thePy_SIZE() calls toPyList_GET_SIZE() seems like it would be a lot of noise. To be honest, I think there are a lot of reasonable approaches, and whatever you decide to do is fine with me. Here is my current thinking:

  • Most of thePy_SIZE() calls are reads from functions that will be within critical sections in the future. Those are fine as is.
  • If we readob_size outside of a critical section, it should use an atomic load. Either directly or indirectly, such as by callinglist_length().

Forlist_repr, my inclination would be to push the zero-size check down into the critical section, but using an atomic load also seems fine.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fortunately, that's no longer a concern.

Thanks to@vstinner for fixing this! 👏

corona10 reacted with thumbs up emoji
Copy link
MemberAuthor

@corona10corona10Jan 26, 2024
edited
Loading

Choose a reason for hiding this comment

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

Hmm.. well, from the view of maintaining implementation detail as not changed as possible for the list object itself, updating PyList_GET_SIZE() to be an atomic operation is worth doing. It's good negotiation point I guess.

If we need to make Py_SIZE() as atomic operation, we can handle it later.

@serhiy-storchaka
Copy link
Member

I think that either all reads and writes ofob_size should be atomic, or they all should be in critical sections.

@corona10
Copy link
MemberAuthor

corona10 commentedJan 26, 2024
edited
Loading

@colesbury
What about makingPy_SIZE() to be atomic instead of touching this from runtime implementation?
A side effect is that there will be some minor effect to something like a tuple, but not that huge IIUC.

If we are okay with this, I will submit a new PR.

@corona10
Copy link
MemberAuthor

@colesbury

Updated! The implementations become more clear and easy to maintain.
Now I understand our consensus about how to handle atomic operations in runtime.
I will submit PRs with similar approaches.

@colesbury
Copy link
Contributor

@serhiy-storchaka wrote:

I think that either all reads and writes of ob_size should be atomic, or they all should be in critical sections.

I think we should follow slightly different pattern inlist:

  • Writes toob_size should be atomic AND in critical sections
  • Reads fromob_size should be either atomic OR in critical sections

Exceptions: initialization, deallocation, and certain special functions can use plain accesses without critical sections (e.g.,PyList_New(),list_dealloc,list_traverse).

The motivation behind this is that we will have some accesses outside of critical sections (see"Optimistic dict and list Access Summary" in PEP 703), so we can't use critical sections everywhere, but we will use them for most operations.

At the same time, I think we should prefer plain, non-atomic reads from within critical sections. We could conservatively use atomic reads and still be correct, but my experience is that adding atomic operations where they are not necessary tends to hide data races from thread sanitizer.

Note that writes toob_size have to be at atomic even if they are within critical sections because there might be concurrent reads.

erlend-aasland and corona10 reacted with thumbs up emoji

@serhiy-storchaka
Copy link
Member

You at least need to make writing the list size atomic.

@colesbury
Copy link
Contributor

You at least need to make writing the list size atomic.

I agree, but I don't think we should do that in this PR. I think it's easier to write and review the PRs organized around functions than around fields (i.e., "fix list_repr" instead of "fix ob_size"). It keeps the changes smaller and close together.

The current changes look sufficient to me if we later address all the functions that write toob_size.

erlend-aasland reacted with thumbs up emoji

Copy link
Contributor

@colesburycolesbury left a comment

Choose a reason for hiding this comment

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

This LGTM

@corona10
Copy link
MemberAuthor

The current changes look sufficient to me if we later address all the functions that write to ob_size.

Yeah, I will prepare another PR for this.

@corona10
Copy link
MemberAuthor

Thank you@serhiy-storchaka,@encukou and@colesbury about discussing how we handle atomic operation issue :)
It's now become clear :)

@corona10corona10 merged commitf9c5056 intopython:mainJan 26, 2024
@corona10corona10 deleted the gh-112087-repr-length branchJanuary 26, 2024 16:20
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@encukouencukouencukou left review comments

@erlend-aaslanderlend-aaslanderlend-aasland left review comments

@colesburycolesburycolesbury approved these changes

@DinoVDinoVAwaiting requested review from DinoV

@serhiy-storchakaserhiy-storchakaAwaiting requested review from serhiy-storchaka

@ambvambvAwaiting requested review from ambv

Assignees

No one assigned

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

5 participants

@corona10@encukou@serhiy-storchaka@colesbury@erlend-aasland

[8]ページ先頭

©2009-2025 Movatter.jp