In this video I spent some time benchmarking my ECS (Entity Component System) framework against the popular Rust ECS, Bevy. We had to do some performance analysis and optimize a few things, but all things considered, we ended up doing pretty well. Specifically, we optimized by doing bounds check elimination (BCE), inlining, and using the recently released Go generics
// Socials
⁍ Twitter: [ Ссылка ]
⁍ Discord: [ Ссылка ]
// Code
⁍ Go Code: [ Ссылка ]
⁍ Rust Code: [ Ссылка ]
// Good Article
⁍ PlanetScale: [ Ссылка ]
// Errata
1. Calling Monomorphization "The other end of the spectrum" from GC shape stenciling is a bit overblown. Go stencils (ie monomorphizes) its generics based on the GC shape, so there still is some monomorphization happening which can give you nice performance gains for things with different GC shapes. The actual "Other end of the spectrum" is probably something like doing a full dictionary-based boxing and doing no stenciling at all.
2. Why does Bevy Run Slower than Go?
I apologize for not covering this in the video. I think number 1 and 2 are probably the biggest contributors to Bevy running slow.
a. Bevy has A LOT more features than my ECS, each of those features might contribute to a global optimization for most cases, but in my benchmark contribute to a slowdown. I expect that most people aren't disabling multithreading and the system scheduler and manually executing every game loop.
b. Bevy has a few different layers at which you can use the ECS, I'm not a bevy expert, so I may have written the code in an abnormal way where bevy ran slower than it usually would have. Very specifically, Bevy seemed to slow down the more I started adding and deleting components, I'm not sure the limitation there, but I thought it was notable.
c. Bevy isn't the fastest Rust ECS framework according to this: [ Ссылка ] - I learned this actually kind of recently after all my code was written for bevy
d. Pointed out by laundmo in the comments:
1. "by default, bevy uses what it calls "Table" storage for components - this is fast to iterate but slow to update. In use cases where you might want to add/remove components a lot, you can switch to SparseSet storage on a per-component basis." - I didn't know this, but it does align with what I saw where Bevy slowed down once I started deleting entities every frame.
2. "The ECS benchmark [in errata C] you mentioned is outdated by 2 years, and was also recently archived to represent this. Bevy has had multiple optimizations since then. I see you using bevy_ecs 0.7 - in 0.9 there were some decent performance improvements which would be interesting to see."
Ещё видео!