Updates will be slowing down for a while as I work on multithreading for 0.12.0. This is a big and promising feature, but also a dangerous one. It’s kind of like summoning an eldritch god: you might get immortality, or your life force might be consumed to power a terrible murder portal through which demons can invade the earth.
(it’s important to make your analogies relatable)
The number one complaint on Steam is performance. And I get it. Species gets more interesting with more creatures. If you’ve got a supercomputer with a trillion cores that cost you as much as the first three Apollo missions, you’re probably going to resent it if it can’t run Species better than a machine somebody got in a garage sale for 5 bucks and may actually be a microwave. Unfortunately, there’s a good possibility it won’t because CPU core speed hasn’t significantly increased in the last decade.
Performance is not the reason I’m looking at multithreading, however.
This is how the game is currently built, using a bit of sample data taken from a quick P. specium simulation:
As you can see, each frame time is given primarily to creature AI, specifically to the method called “UpdateBehaviourals” (that big red chunk of CPU time in the middle of each frame).
Logically, then, that’s the method I should extract and put into another thread, so it can run in parallel to the other operations.
This would be the “simple” (not actually simple) way of implementing multithreading.
And to be fair, a potential 30% performance improvement (assuming ideal conditions) isn’t to be sneezed at. But to be frank, it’s not enough to justify how much development time and risk multithreading the update call introduces.
But most modern CPU’s have more than two cores, and there’s still a big chunk of time on the main thread going unused (that blue block in the picture labelled “await”), which means we’re not done. What if we could *split* the “UpdateBehaviourals” method across multiple cores, by updating some of the creatures on one, some on another, and so on?
That’s a lot better: a whopping 70% improvement! (assuming ideal conditions and that this sample data is representative).
But even more importantly, from my perspective at least, the blue ‘await’ blocks are now on the other threads.We have spare CPU cycles, not on the main thread, but on the threads doing the AI.
This is the real reason I want multithreading in 0.12.0. I still have features I want to add, specifically to Creature AI.Creatures need to be able to rationally decide what movement method to use to reach a target, which requires increased situational awareness.Predators need to be able to find food from further afield, so they can travel to more habitable areas from across the map rather than just dying off once all the prey in their area are gone.Social creatures need to communicate with one another and factor those communications into their decision-making process. And each of those features will have an associated CPU cost, which I simply can’t afford at the moment.
But if I can properly parallelize the creatures “UpdateBehaviourals” routine…that is, not just offload it to another core, but offload portions of it onto all the other cores… then I’ll get a significant amount of spare CPU cycles to work with, and I’ll be able to implement those features without worrying about them impacting performance at all!
Of course, this is even harder to implement than the aforementioned “simple” option, which itself is nothing of the sort. But I’ll have plenty of time and incentive to whinge about those problems soon enough.
For now, let’s leave it on a optimistic note: if this works performance will scale with the number of cores you have.* More cores = higher creature cap!
* (assuming ideal conditions and that the sample data is representative and that the earth hasn’t been invaded by demons pouring from a terrible murder portal)