Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-112529: Use atomic operations for gcstate->collecting #112533

Merged
merged 2 commits into from
Dec 11, 2023

Conversation

colesbury
Copy link
Contributor

@colesbury colesbury commented Nov 29, 2023

The collecting field in GCState is used to prevent overlapping garbage collections within the same interpreter. This is updated to use atomic operations in order to be thread-safe in --disable-gil builds.

The GC code is refactored a bit to support this. More of the logic is pushed down to gc_collect_main() so that we can safely order the logic setting collecting, the selection of the generation, and the invocation of callbacks with respect to the atomic operations and the (future) stop-the-world pauses.

The change uses atomic operations for both --disable-gil and the default build (with the GIL) to avoid extra #ifdef guards and ease the maintenance burden.

The `collecting` field in `GCState` is used to prevent overlapping garbage
collections within the same interpreter. This is updated to use atomic
operations in order to be thread-safe in `--disable-gil` builds.

The GC code is refactored a bit to support this. More of the logic is pushed
down to `gc_collect_main()` so that we can safely order the logic setting
`collecting`, the selection of the generation, and the invocation of callbacks
with respect to the atomic operations and the (future) stop-the-world pauses.

The change uses atomic operations for both `--disable-gil` and the default
build (with the GIL) to avoid extra `#ifdef` guards and ease the maintenance
burden.
@@ -2271,10 +2262,6 @@ PyObject_IS_GC(PyObject *obj)
void
_Py_ScheduleGC(PyInterpreterState *interp)
{
GCState *gcstate = &interp->gc;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

fyi: _Py_ScheduleGC not public and only called from _PyObject_GC_Link, which already checks gcstate->collecting.

@colesbury colesbury marked this pull request as ready for review November 29, 2023 18:48
@colesbury colesbury requested a review from pablogsal as a code owner November 29, 2023 18:48
@colesbury
Copy link
Contributor Author

@pablogsal, would you be able to review this? The important bit is the atomically setting gcstate->collecting for thread-safety in --disable-gil builds, but there's a bunch of code that's moved around to support this.

cc @nascheme in case you have time and are interested in the GC changes, I would appreciate your feedback as well.

@pablogsal
Copy link
Member

@pablogsal, would you be able to review this? The important bit is the atomically setting gcstate->collecting for thread-safety in --disable-gil builds, but there's a bunch of code that's moved around to support this.

will review this week 👍

@colesbury
Copy link
Contributor Author

@pablogsal - gentle reminder, this is awaiting your review

@nascheme
Copy link
Member

nascheme commented Dec 8, 2023

This looks okay to me. It's a bit hard to see from the diff which code has been moved vs what's been changed. However, it seems to be mostly re-organization with essentially no behaviour change, aside from using the atomics. I'd say it can be merged.

{
GC_STAT_ADD(generation, collections, 1);
#ifdef Py_STATS
if (_Py_stats) {
Copy link

@chris-eibl chris-eibl Dec 9, 2023

Choose a reason for hiding this comment

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

Shouldn't object_visits be zeroed after the _Py_atomic_compare_exchange_int(&gcstate->collecting check or the check be moved up?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, thanks!

@chris-eibl
Copy link

I think using forward declarations might help to have less moved blocks and make the review easier?

@nascheme
Copy link
Member

nascheme commented Dec 9, 2023

I think using forward declarations might help to have less moved blocks and make the review easier?

Probably it would but I'd rather the code is cleaner (without the forward decs) and have the patch be messier.

@nascheme
Copy link
Member

nascheme commented Dec 9, 2023

I rewrote the commit to use forward declarations (as suggested by Chris), makes the review easier:

nascheme@d53784d

Aside from re-ordering the code and addition the forward defs, I didn't change anything.

Copy link
Member

@pablogsal pablogsal left a comment

Choose a reason for hiding this comment

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

I finally had time to review this. Apologies for the delay.

@pablogsal
Copy link
Member

We can probably go with the version with forward references although I don't think it makes a lot of improvements in the final version, is true that the review is easier to do on the diff alone.

@nascheme
Copy link
Member

The forward ref version was meant only for review purposes. I think we should merge Sam's (this) one.

@colesbury
Copy link
Contributor Author

I fixed the bug pointed out by @chris-eibl. Let me know if you prefer to land the forward references version. If so, I'll merge @nascheme's changes in. Otherwise, I think it's good to go now once the CI passes.

@pablogsal
Copy link
Member

I fixed the bug pointed out by @chris-eibl. Let me know if you prefer to land the forward references version. If so, I'll merge @nascheme's changes in. Otherwise, I think it's good to go now once the CI passes.

Nah, is good, let's go with this version. Thanks for the patience!

@pablogsal pablogsal enabled auto-merge (squash) December 11, 2023 18:13
@chris-eibl
Copy link

chris-eibl commented Dec 11, 2023

The forward ref version was meant only for review purposes.

Exactly that was my indention :)

@pablogsal pablogsal merged commit d70e27f into python:main Dec 11, 2023
30 checks passed
@colesbury colesbury deleted the gc-collecting branch December 11, 2023 19:38
aisk pushed a commit to aisk/cpython that referenced this pull request Feb 11, 2024
…hon#112533)

* pythongh-112529: Use atomic operations for `gcstate->collecting`

The `collecting` field in `GCState` is used to prevent overlapping garbage
collections within the same interpreter. This is updated to use atomic
operations in order to be thread-safe in `--disable-gil` builds.

The GC code is refactored a bit to support this. More of the logic is pushed
down to `gc_collect_main()` so that we can safely order the logic setting
`collecting`, the selection of the generation, and the invocation of callbacks
with respect to the atomic operations and the (future) stop-the-world pauses.

The change uses atomic operations for both `--disable-gil` and the default
build (with the GIL) to avoid extra `#ifdef` guards and ease the maintenance
burden.
Glyphack pushed a commit to Glyphack/cpython that referenced this pull request Sep 2, 2024
…hon#112533)

* pythongh-112529: Use atomic operations for `gcstate->collecting`

The `collecting` field in `GCState` is used to prevent overlapping garbage
collections within the same interpreter. This is updated to use atomic
operations in order to be thread-safe in `--disable-gil` builds.

The GC code is refactored a bit to support this. More of the logic is pushed
down to `gc_collect_main()` so that we can safely order the logic setting
`collecting`, the selection of the generation, and the invocation of callbacks
with respect to the atomic operations and the (future) stop-the-world pauses.

The change uses atomic operations for both `--disable-gil` and the default
build (with the GIL) to avoid extra `#ifdef` guards and ease the maintenance
burden.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants