Introduction

Since I’ve already described ECS before on my previous post, I won’t be explaining it here. If you want to learn more about that, you can do so here: Learning about ECS. Basically it is a way to structure your code by using entities, components, and systems.

ECS is used a lot more in Rust game development rather than anywhere else and the cause of that may be because Rust really likes the composition over inheritance principle, like for example, using traits rather than inheritance.
There is a lot of ECS libraries for Rust and in this post, we will be benchmarking a couple of ECS libraries that I found interesting.

Libraries we will be covering

Libraries we will be covering for this post are:

There are still a lot more ECS libraries for Rust, but these are the ones that I found interesting for some kind of reason.

Note: Bevy ECS is actually a part of another library called Bevy which is a full game framework

Benchmarks

The benchmarks for the libraries are gonna be:

  • unbatched_spawn: Spawn n amount of entities by spawning them one by one.
  • batched_spawn: Spawn n amount of entities batched
  • add_remove: Add a component to n amount of entities and then remove the component
  • iter: Iterate over n amount of entities
  • multiple_iter: Iterate over n amount of entities with different components parallelly
  • multiple_iter_same: Iterate over n amount of entities with the same components parallelly
  • iter_mut: Iterate mutably over n amount of entities
  • multiple_iter_mut: Iterate mutably over n amount of entities with different components parallelly
  • multiple_iter_mut_same: Iterate mutably over n amount of entities with the same components parallelly

In the project page, n is three values: 1,000, 100,000, and 1,000,000. For this post, we’re gonna cover only the last part. Be sure to check out the full project.

Results

The full project is at https://github.com/ManicMarrc/ecs_benchmark/tree/main.

unbatched_spawn

Violin Graph

As you can see from the graph, edict is the slowest of them and hecs being the fastest one. This is the only one time where Edict is slow as you’ll see for the next few benchmarks.

batched_spawn

Violin Graph

You may have noticed that Edict isn’t anywhere in this graph. That’s because it is way faster than the others, so fast in fact, it’s not even visible on the graph as the others are too slow!

add_remove

Violin Graph

Again in this graph, Edict is not visible at all. Bevy ECS being the slowest one out of all of them and Shipyard being the second fastest.

iter

Violin Graph

Are you seeing a pattern here? Cause I am. Basically the same as the add_remove benchmark with Bevy ECS being the slowest one.

multiple_iter

Violin Graph

Edict is actually visible on this graph being only one pixel. Again, the same pattern as the aforementioned benchmarks.

multiple_iter_same

Violin Graph

The pattern still repeats for this one.

iter_mut

Violin Graph

This one is actually interesting. While Edict and Bevy ECS stays the same in their position, Shipyard and Hecs are fighting to be in the second position. Shipyard averagely performs better than Hecs, but sometimes, Hecs performs better than Shipyard.

multiple_iter_mut

Violin Graph

This one follows the original pattern, nothing interesting.

multiple_iter_mut_same

Violin Graph

For this one, Hecs gets kinda close to Shipyard but is still a little bit slower than it.

Summary

Although Edict was the slowest one by far for the unbatched_spawn benchmark, it passed every other libraries in the other benchmarks. Bevy ECS was by far the slowest one of them all, being last in every single benchmark except for the unbatched_spawn benchmark. Hecs and Shipyard have close speed, with Shipyard being faster in most cases.

Ending Off

Note that these benchmarks are ran on my super old computer which may affect the benchmark results. You can benchmark them yourself easily by just cloning the Github page and running cargo bench and wait a while.

That’s all for this post, see you and goodbye!