-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Uncached Queries #21607
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
base: main
Are you sure you want to change the base?
Uncached Queries #21607
Conversation
Ignoring the WIP nature of the PR, this seems like broadly the correct approach to me i.e. splitting up the query state such that the "cache" portion is responsible for managing a list of storages to iterate. Having an additional generic on all these query related structs and traits is an ergonomic hit, the bigger these definitions get the "scarier" they get in the sense that they become harder and harder to grok, but none of the alternatives are free either. |
It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note. Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes. |
As SME-ECS, I'm broadly on board with this direction and excite to see this evolve! |
Updated the PR to make the tests pass. Things i'd like to change:
|
This seems like a simpler design. Explore that and report back? |
Change-Id: I688258fc8dd59674ad6ba252b9d8dde7e8d8daaf
Change-Id: I0953e9836f8ddfd8923c4b00132d9e653c575572
6931681
to
16bbc33
Compare
I haven't read through all the code here yet, but I wanted to brainstorm some possible connections: Could this supersede #18162 and #19787? The goal there was to make I've also started suspecting that we'll want to split the typed Hmm, I see you're adding a type parameter to |
Maybe? I'm less familiar with QueryLens; if I understand correctly they are just a place to store the new QueryState when we are transmuting a Query (because Query only borrows QueryState).
My plan here (I talked a bit about it in #ecs-dev) was to have the query logic be entirely dynamic; the QueryState would just store an untyped QueryPlan that would help you get the correct ECS data.
Yes I was thinking of doing this, I think that's the correct approach!
is a better version of my
|
Objective
Adds uncached queries: queries that don't cache in memory the list of archetypes that match. These queries can be contrasted with the current cached Queries: every time a query operation is done on cached queries, they start by iterating through new archetypes to check which of these new archetypes match the query.
When we do an operation on a cached query (iter/get/etc.), we use the cached list of sorted archetypes. But for uncached queries, we instead go through world archetypes from scratch to check which archetypes match the query. (Note that we do not go through all the archetypes because we can use the ComponentIndex to reduce the number of archetypes that we have to go through.)
Solution
For cached queries, the cache is populated by iterating through new archetypes and checking with the uncached version of the query if those archetypes match.
iterate_archetypes
for uncached queries does the job of checking if an archetype matches the query. In contrast,iterate_archetypes
for cached queries just goes through the cached list of matching archetypes.Implements uncached queries by adding a 3rd generic
QueryCache
toQueryState
. That generic can essentially have 2 values:CacheState
orUncached
.I opted for this so that:
we statically know if the query is cached or uncached so we don't pay the cost of
if is_cached()
callswe don't need to write new implementations for all the
QueryState
functions, only a couple of functions change and are implemented differently forQueryState<CacheState>
vsQueryState<Uncached>
Added a
DefaultCache
which can beCacheState
(cached) orUncached
depending on a feature. This lets us run all existing query tests in both cached or uncached mode.Added some type aliases
UncachedQuery
andUncachedQueryState
, as well as methods on World (query_uncached
, etc.)Open questions
For simplification I removed the check of
DefaultQueryFilters::is_dense
to check if a query is dense. I believe that it doesn't make sense for a DefulatQueryFilter to not be dense, since we need it to be dense to efficiently filter disabled vs non-disabled queries. We should probably add some error (panic?) if a user tries to register a non-dense component as a DefaultQueryFilter.Some operations are slower than necessary for uncached queries. For instance
query.iter().sort()
will go through all archetypes twice: once for the iter() and once for the sort(). This might be avoidable but I think it can be punted to a future PR.