Larecs: a performance-centred archetype-based ECS

We have built an archetype-based ECS, mostly building on the Arche ECS in Go lang. There are still a couple of features on the road map, but the central functionality is there. In benchmarks, Larecs beats Arche in almost all test cases :-). Have a look here: https://github.com/samufi/larecs I would be super happy if others were interested in joining, and I'd greatly appreciate feedback and ideas how to bring SIMD and other Mojo perks to the world of ECS.
GitHub
GitHub - samufi/larecs: Larecs - a performance-centred archetype-ba...
Larecs - a performance-centred archetype-based ECS - samufi/larecs
13 Replies
a2svior
a2svior2w ago
Impressive 👏
ModularBot
ModularBot2w ago
Congrats @a2svior, you just advanced to level 8!
obust
obust2w ago
I am guessing that SIMD becomes relevant when you work with multiple entities (batches). Then batch queries return struct of arrays (SoA) on which you can do vectorized operations. Pushing this to the limit you can make all queries batch queries and always work with SoA. Then everything is a vector and there is only one paradigm. That is pretty much what mojo does with its scalars. Where Int16 is just an alias for SIMD[int16, 1] https://docs.modular.com/mojo/stdlib/builtin/simd/
samufi
samufiOP2w ago
To me the question is what to do if the components are structs themselves. What do you do if you have a component with components of different sizes? Edit: a component with fields of different sizes Of course you could use a larger stride, but this is something the users would need to do - as I do not see a way how Larecs could figure out the memory layout of the components.
obust
obust2w ago
Do you have toy example of a component with components of different sizes ?
samufi
samufiOP2w ago
My thought was to do something in this direction for components that are an alias for SIMD, but I am not sure how to enforce that this functionality would be used appropriately. More user friendly might be an integration of numojo data types. Well, users can come up with weird stuff sometimes. For example a position component where the z coordinate can be lower precision for some reason.
obust
obust2w ago
as long as all z are the same size then you can pack them into an array. SoA means you have 1 struct with as many arrays as you have struct fields.
samufi
samufiOP2w ago
Sorry, I may have misunderstood you. I meant the fields can have different sizes. Each struct (component) has the same size of course.
ModularBot
ModularBot2w ago
Congrats @samufi, you just advanced to level 10!
obust
obust2w ago
Right. So you can store all your components in: - an Array of Structs: [{x: 0.0, y: 1.0}, {x: 2.0, y: 3.0}] - a Struct of Arrays: {x: [0.0, 2.0], y: [1.0, 3.0]} If your batch query returns a SoA then
positions = world.get[Position](entity_ids) # positions is a SoA
positions.x = 8.0 # positions is a vector
positions = world.get[Position](entity_ids) # positions is a SoA
positions.x = 8.0 # positions is a vector
samufi
samufiOP2w ago
The components are always stored as Arrays of structs. How would the ECS know that it can split a struct into separate attributes that can be stored in separate arrays?
obust
obust2w ago
I suppose the ECS components could be stored as SoA as well. I can see an argument for queries to prefer acting on AoS, but the systems likely would be more efficient on SoA so you can do SIMD.
samufi
samufiOP2w ago
The components are already stored in SoA. Just that the arrays are filled with structs themselves. As long as each component is just a trivial SIMD, everything is fine. But if the components have multiple fields, things get tricky.

Did you find this page helpful?