Skip to content

Conversation

@ameligrana
Copy link
Member

@ameligrana ameligrana commented Nov 21, 2025

What do you think about this @mlange-42 ? It should be useful sometimes to reduce the boilerplate. E.g. in the little example SIR which I would like to add to the demos

@ameligrana ameligrana added the feature Feature requests and ideas label Nov 21, 2025
@ameligrana
Copy link
Member Author

ameligrana commented Nov 21, 2025

Maybe we can spare collect_entities since collect_entities! could always be used instead and should be better?

@mlange-42
Copy link
Member

Maybe we can spare collect_entities since collect_entities! could always be used instead and should be better?

Yeah, probably. It could also be called like this:

entities = collect_entities!(Query(...), Entity[])

I think this feature is useful enough to be added.

Removed the collect_entities function that was previously used to gather entities from a query.
@mlange-42
Copy link
Member

E.g. in the little example SIR which I would like to add to the demos.

Is it really useful there? Both loops involve drawing random numbers, so the operation it not applied to all matching entities. If an operation is applied to all, using batch operations (when implemented...) would be way more performant.

But there are definitely still use cases where collecting entities makes sense.

@github-actions
Copy link
Contributor

⚠️ 1 benchmark regressions detected!

Click to expand benchmark results

Time is per entity/N, allocations are totals. Allocations are only shown for current.

N       Time main             Time curr           Factor         Allocs         Bytes    
query_create
1000 4.51ns 4.54ns 1.01 0 0
query_posvel_1k_arch
100 4.95ns 4.90ns 0.99 0 0
1000 7.69ns 7.45ns 0.97 0 0
10000 2.12ns 1.97ns 0.93 0 0
100000 1.33ns 1.28ns 0.96 0 0
1000000 1.13ns 1.12ns 0.99 0 0
query_posvel_32_arch
100 1.69ns 1.72ns 1.02 0 0
1000 0.97ns 0.97ns 0.99 0 0
10000 0.42ns 0.41ns 0.98 0 0
100000 0.93ns 0.91ns 0.98 0 0
1000000 0.98ns 0.96ns 1.00 0 0
query_posvel_cold
100 0.63ns 0.71ns ⚠️ 1.13 0 0
1000 0.37ns 0.37ns 1.00 0 0
10000 0.39ns 0.42ns 1.08 0 0
100000 1.02ns 1.11ns 1.10 0 0
1000000 1.49ns 1.50ns 1.02 0 0
query_posvel_fields
100 0.35ns 0.35ns 0.99 0 0
1000 0.23ns 0.23ns 1.01 0 0
10000 0.34ns 0.34ns 1.01 0 0
100000 0.88ns 0.82ns 0.91 0 0
1000000 0.94ns 0.93ns 1.01 0 0
query_posvel_fields_broadcast
100 6.06ns 6.06ns 1.00 0 0
1000 5.97ns 5.97ns 1.00 0 0
10000 6.01ns 6.01ns 1.01 0 0
100000 6.14ns 6.06ns 0.92 0 0
1000000 6.35ns 6.41ns 1.04 0 0
query_posvel_hot
100 0.36ns 0.36ns 1.00 0 0
1000 0.23ns 0.23ns 1.00 0 0
10000 0.34ns 0.34ns 1.00 0 0
100000 0.89ns 0.82ns 0.90 0 0
1000000 0.97ns 0.95ns 0.98 0 0
query_posvel_soa
100 0.86ns 0.87ns 1.01 0 0
1000 0.68ns 0.68ns 1.00 0 0
10000 0.82ns 0.82ns 1.00 0 0
100000 0.98ns 0.98ns 1.00 0 0
1000000 1.06ns 1.09ns 1.03 0 0
query_posvel_soa_unpack
100 0.44ns 0.44ns 1.00 0 0
1000 0.20ns 0.20ns 1.00 0 0
10000 0.33ns 0.32ns 0.99 0 0
100000 0.86ns 0.82ns 0.92 0 0
1000000 0.95ns 0.93ns 0.99 0 0
world_add_remove_1
100 62.40ns 61.18ns 0.98 0 0
10000 63.00ns 61.97ns 0.99 0 0
world_add_remove_1_large
100 66.84ns 67.22ns 1.01 0 0
10000 67.45ns 67.89ns 1.01 0 0
world_add_remove_1_soa
100 75.76ns 74.41ns 0.98 0 0
10000 76.51ns 74.82ns 0.98 0 0
world_add_remove_8
100 156.85ns 155.76ns 0.99 0 0
10000 157.22ns 157.51ns 1.00 0 0
world_add_remove_8_large
100 156.26ns 156.68ns 1.00 0 0
10000 157.11ns 157.70ns 1.00 0 0
world_add_remove_8_soa
100 183.29ns 182.16ns 0.99 0 0
10000 184.55ns 182.81ns 0.99 0 0
world_copy_entity_5
100 52.04ns 51.42ns 0.99 0 0
10000 52.24ns 51.56ns 0.99 0 0
world_get_1
100 1.12ns 1.05ns 0.94 0 0
10000 1.03ns 0.98ns 0.95 0 0
world_get_1_soa
100 2.03ns 2.03ns 1.00 0 0
10000 1.99ns 1.99ns 1.00 0 0
world_get_5
100 2.97ns 2.93ns 0.99 0 0
10000 2.92ns 2.90ns 0.99 0 0
world_new_entities_1
100 4.07ns 4.09ns 1.01 3 128
10000 3.08ns 3.11ns 1.01 3 128
world_new_entities_1_def
100 3.85ns 3.88ns 1.01 0 0
10000 3.13ns 3.14ns 1.00 0 0
world_new_entities_5
100 6.19ns 6.25ns 1.01 3 128
10000 5.32ns 5.31ns 1.00 3 128
world_new_entities_5_def
100 5.75ns 5.74ns 1.00 0 0
10000 4.71ns 4.64ns 0.98 0 0
world_new_entity_1
100 24.28ns 24.21ns 1.00 0 0
10000 24.53ns 24.13ns 0.99 0 0
world_new_entity_1_soa
100 29.27ns 29.40ns 1.01 0 0
10000 29.42ns 29.68ns 1.01 0 0
world_new_entity_5
100 70.36ns 69.74ns 0.99 0 0
10000 71.32ns 70.84ns 0.99 0 0
world_new_entity_5_soa
100 100.20ns 99.11ns 0.99 0 0
10000 102.18ns 101.32ns 0.99 0 0
world_posvel
100 2.58ns 2.58ns 1.00 0 0
1000 2.62ns 2.63ns 1.00 0 0
10000 2.63ns 2.63ns 1.00 0 0
100000 2.64ns 2.65ns 1.00 0 0
world_resource
1 7.01ns 7.16ns 1.02 0 0
world_set_1
100 1.99ns 1.93ns 0.98 0 0
10000 2.04ns 1.98ns 0.98 0 0
world_set_1_soa
100 2.70ns 2.70ns 1.00 0 0
10000 2.76ns 2.76ns 1.00 0 0
world_set_5
100 5.89ns 5.83ns 0.99 0 0
10000 6.48ns 6.42ns 0.99 0 0
world_update_1
100 1.92ns 1.93ns 1.01 0 0
10000 1.95ns 1.97ns 1.00 0 0
world_update_5
100 9.82ns 9.96ns 1.01 0 0
10000 10.09ns 10.22ns 1.01 0 0

count
end

function collect_entities!(q::Query, all_entities::AbstractVector{Entity})
Copy link
Member

Choose a reason for hiding this comment

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

According to the Julia style guide, the mutated arg should be the first one.

@mlange-42
Copy link
Member

mlange-42 commented Nov 21, 2025

Looking a bit ahead, maybe at this point it would be good to already implement Filter? As kind of just the filtering part (masks) of the query. We will need this when we implement batch operations, and for cached queries/filters it would probably also be useful, to stay with queries as one-time use iterators (that can also be constructed from a filter).

EDIT: Thinking a bit further, maybe it would be good then to postpone filters and collect to v0.3.0?

@ameligrana
Copy link
Member Author

ameligrana commented Nov 21, 2025

mmh, if I understand it one could do something like collect_entities!(Entity[], Filter(_ -> rand() <= prob, Query(...)) for the SIR model right? If this is the case, then, okay let's defer this to v0.3

@mlange-42
Copy link
Member

mlange-42 commented Nov 21, 2025

mmh, if I understand it one could do something like collect_entities!(Entity[], Filter(_ -> rand() <= prob, Query(...)) right? If this is the case, then, okay let's defer this to v0.3

No, that's not what I mean by filters. What I mean is just the masks part of queries in a separate object. They could be stored, created without locking the world, and used for batch operations and registered/cached filters. But there could be an implicit conversion from queries to filters, so both can be used where a filter is the actual argument.

EDIT: predicate-like filters make no sense for batch operations, as we do not really get the advantage of batching then. Or at least not all advantages.

@ameligrana
Copy link
Member Author

is there this feature in the Go Ark package?

I'm reading your edit and I'm not getting if you are saying that a Filter with predicates is not useful in any case, and what is the alternative.

@ameligrana
Copy link
Member Author

ameligrana commented Nov 21, 2025

ah okay maybe you are saying to do something like Query(..., mask=f::Function)? Why having a separate Filter object?

@mlange-42
Copy link
Member

is there this feature in the Go Ark package?

I'm reading your edit and I'm not getting if you are saying that a Filter with predicates is not useful in any case, and what is the alternative.

Yes, kind of. But with the difference that queries are always created from filters there, because of the required runtime lookup of component IDs.

https://mlange-42.github.io/ark/batch/#components

Predicates may be useful, maybe even with batch operations. We will not get the speedup of mass copying when they are used, but at least we still don't need the repeated archetype graph traversal.

But I still think that a predicate (e.g. for batches or collect) should be separated from the kind of filters I mean. These are really just a lighweight, re-usable part of the query's filtering mechanism/masks.

@ameligrana
Copy link
Member Author

Ah okay got it maybe. This is caching the already in-place mechanisms for filtering. Though, if this is the case, then collecting entities is a separate feature a bit unrelated to filtering or not?

@mlange-42
Copy link
Member

mlange-42 commented Nov 21, 2025

Ah okay got it maybe. This is caching the already in-place mechanisms for filtering. Though, if this is the case, then collecting entities is a separate feature a bit unrelated to filtering or not?

Yes, kind of, but it would make sense then to use a Filter as arg there instead of a query (where a query could still be used through conversion). So strictly speaking it would bring a breaking change, although user code would stay intact but not optimal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Feature requests and ideas

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants