Scratch param - #24140
Conversation
|
There was a suggestion on the original issue to make |
052f442 to
b8ee91e
Compare
Is it possible to overcome this? Also |
I don't think so. Not at least while maintaining panic safety. The way it would work is we would add a new method to // ...
let params = unsafe {
F::Param::get_param(&mut state.param, &self.system_meta, world, change_tick)
}?;
/// <ignore hotpatching impl>
let out = self.func.run(input, params);
/// We would add a `post_system_run` call here
self.system_meta.last_run = change_tick;If |
|
I'm pulling this out of draft since this version is mostly done. I'll hold off on writing the showcase until I get at least one review. Hopefully, the safety issue can be hashed out and we get to push the best versions of this across the finish line. |
| } | ||
|
|
||
| /// SAFETY: We only access world change ticks immutably. We can't conflict with anything. | ||
| unsafe impl<'a, T: ClearableCollection + FromWorld + Send + Sync + 'static> SystemParam |
There was a problem hiding this comment.
Local does not require Sync, why Scratch require it?
This was the whole motivation for this code.
| // at the first system run and when the change ticks overflow. Both events | ||
| // are rare enough and the cost of getting it wrong is so low (we shrink the allocations) | ||
| // that we just ignore it. | ||
| let offset = change_tick.relative_to(system_meta.last_run); |
There was a problem hiding this comment.
I wonder if we can improve this for the first system run case, because that seems like a bit of a sore point. I don't think we have to worry about the overflow case, but the first run feels like something we do want to worry about.
There was a problem hiding this comment.
The code fires before the system gets to execute for the first time. Most collections will not have allocated at this point. The shrinking will be a no-op.
We could switch to counting system runs. This would fix the unnecessary shrinks, but it would mean wasting more memory on systems that use run conditions.
There was a problem hiding this comment.
Then it is probably not a case to worry about, if it just becomes a no-op. I was just wondering if there was a path for better, but if the trade-offs aren't worth, then let's just keep it as is (as it is documented anyway).
Co-authored-by: Gonçalo Rica Pais da Silva <bluefinger@gmail.com>
Is it feasible to implement Drop for Scratch and call clear on drop, instead of on get_param? Since Scratch should be dropped even if the system panics after running. |
|
| pub trait ClearableCollection { | ||
| /// The current capacity. | ||
| fn capacity(&self) -> usize; | ||
| /// Attempts to shrink the capacity of the collection. |
There was a problem hiding this comment.
The word Attempts is doing some heavy lifting here.
It would be nice to add an extra line reassuring users that not shrinking the capacity is allowed.
| } | ||
|
|
||
| /// A clearable collection that can be used as a [`Scratch`] type. | ||
| pub trait ClearableCollection { |
There was a problem hiding this comment.
Consider adding default bodies for capacity and shrink_to, to support the common case where the implementation is clearing a non-collection.
Alternatively you could add a non-collection example to the documentation.
| const ASSUMED_TICKS_PER_FRAME: u32 = 1000; | ||
|
|
||
| // 1000 change ticks in a frame * 10 frames | ||
| const DEFAULT_SHRINK_DELAY: Saturating<u32> = Saturating(ASSUMED_TICKS_PER_FRAME * 10); |
There was a problem hiding this comment.
Perhaps 10 frames should be the default of an associated const in the trait ClearableCollection.
There was a problem hiding this comment.
While being possible overridable on the param:
Scratch<T, const DEFAULT_SHRINK_DELAY: usize = <T as ClearableCollection>::DEFAULT_SHRINK_DELAY>(if this compiles)
There was a problem hiding this comment.
Unfortunately that would require the unstable feature min_generic_const_args.

Objective
Introduce a system param for collections holding scratch data.
Closes #23775
Solution
Implement two new items to
bevy_ecs:ScratchandClearableCollection.Scratchis the new system param for hodling scratch data. It holds aClearableCollectionwhich it clears on every system run.I went with a trait based solution instead of
ScratchVec<T>to prevent duplication of the capacity management code. That said I tried to not over-complicate the capacity management code itself. It currently just runs a 10 000 tick timer that resets every time the allocation capacity grows. If it runs down we try to halve the allocation size.Testing
The PR comes with 2 new tests, but I still want to benchmark how using this affects render asset extraction (which is why this pr is a draft for now).
Showcase
TODO