-
Notifications
You must be signed in to change notification settings - Fork 784
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
Optimize nth and nth_back for BoundListIterator #4810
base: main
Are you sure you want to change the base?
Optimize nth and nth_back for BoundListIterator #4810
Conversation
Awesome, thanks! Will seek to review soon. I guess we can do the same thing for tuple iteration? |
Yup - I'll file a PR to optimise tuple iterator after the holiday =) |
src/types/list.rs
Outdated
let length = self.length.min(self.list.len()); | ||
let target_index = self.index + n; | ||
if self.index + n < length { | ||
let item = unsafe { self.get_item(target_index) }; |
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.
I wonder, is there a time-of-check to time-of-use bug here on the length? Not one for this PR, but a follow up I will try not to forget...
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.
Yup I think that's a potential TOCTOU bug here. This particular implementation assumes the user ensures proper synchronization if they intend to use the iterator in a multi-threaded or mutable environment.
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.
I think the current implementation of next
also has a potential TOCTOU bug:
https://github.com/PyO3/pyo3/blob/main/src/types/list.rs#L495-L498
Thanks for working on this! Hopefully my PR should be merged in the next few days and then you can rebase this. |
It might also make sense to implement advance_by on nightly. |
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.
See inline comments, I think there are some issues in how this is set up for the limited API. I also think we should define nth
and nth_back
for all non-nightly builds. I also don't think it's necessary to call get_item
in advance_by
, per my reading of the advance_by
docs.
src/types/list.rs
Outdated
let length = length.0.min(list.len()); | ||
let target_index = index.0 + n; | ||
if index.0 + n < length { | ||
let item = list.get_item(target_index); |
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.
I don't think we need to actually do the get_item
or check for an Err
value, we only need to advance the iterator, which just requires the index.0 + n < length
check.
src/types/list.rs
Outdated
@@ -750,6 +807,27 @@ impl<'py> Iterator for BoundListIterator<'py> { | |||
None | |||
}) | |||
} | |||
|
|||
#[inline] | |||
#[cfg(all(Py_GIL_DISABLED, feature = "nightly"))] |
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.
#[cfg(all(Py_GIL_DISABLED, feature = "nightly"))] | |
#[cfg(feature = "nightly")] |
I think the critical section is necessary though, since another thread might try to use the list while you're in advance_by
. You don't need to be in a Py_GIL_DISABLED
cfg block to use a critical section, it's a no-op on the GIL-enabled build.
src/types/list.rs
Outdated
@@ -772,6 +850,14 @@ impl DoubleEndedIterator for BoundListIterator<'_> { | |||
} | |||
} | |||
|
|||
#[inline] | |||
#[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))] |
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.
#[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))] | |
#[cfg(feature = "nightly")] |
src/types/list.rs
Outdated
@@ -625,6 +674,14 @@ impl<'py> Iterator for BoundListIterator<'py> { | |||
} | |||
} | |||
|
|||
#[inline] | |||
#[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))] |
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.
#[cfg(all(Py_GIL_DISABLED, not(feature = "nightly")))] | |
#[cfg(feature = "nightly")] |
/// access to the list by holding a lock or by holding the innermost | ||
/// critical section on the list. | ||
#[inline] | ||
#[cfg(not(Py_LIMITED_API))] |
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.
you should also add branches to nth
and nth_back
that use get_item
instead of get_item_unchecked
on the limited API
@@ -66,6 +92,8 @@ fn sequence_from_list(b: &mut Bencher<'_>) { | |||
fn criterion_benchmark(c: &mut Criterion) { | |||
c.bench_function("iter_list", iter_list); | |||
c.bench_function("list_new", list_new); | |||
c.bench_function("list_nth", list_nth); | |||
c.bench_function("list_nth_back", list_nth_back); |
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.
Totally missed this when I added the new free-threaded implementations for folding operations in list. I'll add benchmarks for those in a separate PR.
noxfile.py
Outdated
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.
changes in this file seem unrelated, maybe send in a separate PR so we can get these ruff fixes merged quickly?
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.
yeah - I noticed that ruff has released 0.9.0
2 hours ago and the CI didn't pin the ruff version, hence I hit this error which doesn't exist when the latest MR is merged.
I'll file another MR to quickly format this file
See #4787
This PR optimizes
nth
andnth_back
forBoundListIterator
, and added unittest & benchmarks for these 2 APIs. Here are the benchmark of the optimizednth
andnth_back
:On Stable toolchain
With Optimization
The default
nth
andnth_back
implementationOn nightly toolchain
With Optimization
The default
nth
andnth_back
implementation