Quillraven / Fleks

Fast, lightweight, multi-platform entity component system in Kotlin
MIT License
180 stars 20 forks source link

Optimization and cleanup for bit arrays. #111

Closed tommyettinger closed 1 year ago

tommyettinger commented 1 year ago

This is organized logically by commit, and each commit has a (sometimes long-winded) comment. Long story short, addRemove() in the benchmarks goes from 1327 ops/second to 2161 ops/second. The number seems large because I tested with 1000 entities (instead of 10,000) and 5 world updates (instead of 1000) so that I could get meaningful results with short-ish iteration times. That mattered because the benchmark seems to have problems running out of heap if it spends too long on one iteration, though I don't think I encountered this with Fleks -- it was an issue with the Artemis benchmark.

There's lots of bitwise magic here. I'm more than happy to explain any part that doesn't make sense. Bitwise operations are usually quite fast compared to anything that deals with objects, so I'm always happy to see them being put to productive use. The main thing I tried to do was to strip down any of the places where indices 0-63 were looped over in each Long, since that takes more time than necessary in a sparse Long (one with few bits set). There's a new clearEnsuringCapacity() method in MutableEntityBag; it is functionally just like:

clear()
ensureCapacity(capacity)

But avoids copying the empty array without the need to. This is something that some of libGDX's collections also have.

Let me know what I can do to help!

Quillraven commented 1 year ago

Very cool stuff, thank you! I thought I removed the redundant % 64 operations in BitArray but seems like I forgot to push at some point and it got lost. You fixed that now as well :)

Just fyi, I also get the heap memory issue in the Artemis benchmark from time to time. Normally a simple restart of the benchmark solves it.