I’ve recently used the Kivy framework for a job, and when you use Kivy It’s impossible not to stumble upon KivEnt sooner or later. KivEnt is an awesome game engine, and its main developer is my good IRC friend Jacob Kovac (aka “Kovak”).
I’ve always been curious on what to expect from KivEnt in terms of performance. I grew to love C# recently, and it can be considered my main language, but Python is very high on my list, it’s the language that I used to learn OOP and its productivity is incredibly high.
Kivy uses a lot of Cython for its high performance code. I’ve always been a fan of Cython and I’ve followed engines like Ignifuga for some time. KivEnt also uses Cython and encourages you to use it on the expensive parts of your code.
Today I decided to take some time to benchmark KivEnt. In the tests I’m comparing it to Unity Game Engine, which is a tool that I really like and use professionally, so I chose it mostly because it’s not going to take too much time since I’m a little short on time these days. The comparison with Unity is a bit “apples vs oranges” because they have very different approaches, but both have a component-based architecture and analogue objects, and both have the same purpose, so it’s not completely invalid to compare them in my opinion, although Unity is also suitable for 3D games while KivEnt at the moment is mostly focused on 2D.
For the tests I’ve used a hardware I generally use for testing the specifications of the games I develop which can be considered a low-end rig these days, at least for gamers, it’s proven to be a pretty good system for determining the specifications of my games and having a grasp on how they will perform in real-life. I plan to run these tests on an even older rig but it’s not available at the moment. The rig specs are: G3220, 4GB@1333, GTX550Ti. OS is Win 7 64-bit. (Note: the links are not ads; they point to the official specs pages)
Please note that I couldn’t get predictable and stable numbers with no vsync, so all tests are with vsync on what can be a deal-breaker for some people, but since this is focused on real-world results, I think it should be fine for most people.
The first thing I wanted to try was actually the performance of the 2D physics engine KivEnt uses: Cymunk, which is a Cython wrapper for Chipmunk (not to be confused with Pymunk). It’s complicated to compare two different physics engines (Unity uses Box2D), and I decided that a somewhat fair comparison would be a 2D “pyramid” scene for which I would tune both physics engines to yield similar results, because what matters here is what we see in practice. I started with the default/recommended iteration/quality numbers and fine-tuned them until the results were similar, basically it’s the least expensive settings needed to have a stable simulation of the pyramid in which the rows pieces stay at the correct positions after falling.
The squares (or “boxes”) are 1×1 and the space between the rows at the start is 1, here’s what the code looks like in Unity:
public class MakePyramid : MonoBehaviour
public GameObject box;
public int qty;
for (int i = 0; i < qty; i++)
for (int j = 0; j < qty - i; j++)
Instantiate(box, new Vector3(i + j * 0.5f, j * 2f), Quaternion.identity);
Here are the results with a Renderer component for visual feedback:
Please note that any small change on the settings on either tests would produce totally different results, with pieces falling or pushing the ones below to the sides, especially the top pieces are highly sensitive to any minimal change since they depend on the bottom ones. It was very hard to tune both tests to produce similar results with that amount of pieces.
Note: I didn’t use rendering for the actual benchmarks, there was no Renderer component (in Unity) or system (in KivEnt) on the objects.
The results are not distant from what I was expecting (FPS/Pyramid Width):
Min / Stable
Min / Stable
|20||60/60 (vsync)||60/60 (vsync)|
As you can see from these results, Cymunk doesn’t scale very well. It scales somewhat linearly and gets too slow with not so many bodies, so it’s not very suitable for games that abuse the physics at the moment. The good news is that Kovak has plans to make a new wrapper based on Cymunk specifically designed for KivEnt and using a newer version of Chipmunk. So, I hope soon the benchmark above won’t be relevant any longer. Chipmunk 7 is known to be faster than Box2D, in some situations substantially.
Unity performs as I expected. It experiences a performance spike when the squares are falling, thus that 30/60, but the load soon stabilizes when the bodies are seemingly static (but not “sleeping”). I’ve plenty of experience with Unity and the benchmarks are just fine. In terms of performance it’s not very impressive, especially if you’ve used Box2D directly or Farseer, but it’s certainly OK for most real-world games. Cymunk on the other hand apparently spikes when the boxes are all in contact (what makes sense), and it stays like that, never increasing the framerate. I think the penetration compensation calculations on the Box2D version Unity use are expensive, that’s why it spikes when the bodies are falling. I could very well be wrong here, but that doesn’t change the results.
The next test is entity updating. I’ve benchmarked the engines with the most basic entity setup necessary to have objects moving. In Unity each GameObject has only a single C# script component (since a Transform is mandatory) that on “Start” caches a random vector (Random.insideUnitCircle) and uses that on each Update() to update the Transform position. On KivEnt each object only has a Position and a Velocity2D “system” (similar to Unity’s components). KivEnt has two versions, the code is exactly the same except that on the “Cython” version the Velocity2D module is “cythonized”. I’ve used a slightly modified version of the KivEnt example #3 for the test. Since I’m not rendering anything there’s no point in showing screenshots, so here are the results on entities updating (FPS/Entities, Log):
|Amount of Entities||FPS Unity||FPS KivEnt Cython||FPS KivEnt Python|
I’ve benchmarked KivEnt Cython with 172k,174k and 176k entities to know exactly when it drops and what kind of curve it has, the curve is very steep and after 176k it simply stops working. The Python version also is very unstable with more than 7k entities.
Unity has a “long tail” (not very noticeable on the graph which is logarithmic and doesn’t include the last number) that I don’t remember last time I benchmarked it (and as far as I know is unusual on performance benchmarks). I double-checked those numbers and they are correct though. Whatever is happening in Unity, is not important because it happens well below any playable framerate, and also well past any reasonable quantity of entities. If you have literally a million of “dynamic” objects in your game you’re possibly doing it wrong. (optional read: If you’re curious, the long tail can be somewhat explained by the fact that when the framerate drops, you have more time ‘to update’ each object, since Update() is framerate dependent. That’s why you should use FixedUpdate() carefully, because when framerate drops Update() will be called less frequently as opposite to FixedUpdate(). Of course that also depends on your ‘time’ settings, but as a rule of thumb, any ‘fixed’ stepping will ‘try’ to execute based on the real time, so you shouldn’t count on it to scale well when the framerate drops. This is an indication that the engine core is well optimized so it scales linearly in terms of load which is distributed proportionally across frames).
In that test you can see how Python really falls short very quickly when it comes to real-time stuff. With just 7500 entities the pure Python version already dropped to unplayable framerates. It may be suitable for some simpler games though. 7000 units is a respectable number for dynamic entities, but the requirements are somewhat unreasonable for what the test does.
However, when you ‘cythonize’ just a small part of your code (that in this example happens to be a huge bottleneck), that’s when KivEnt really shines. The ‘cythonized’ version is extremely fast and I could hardly believe when I made the first tests. I had to triple-check those numbers but they are correct. It turns out that it’s capable of pumping out a total of 172k entity updates at playable framerates (that is 172k entities, updating 60 times per second). I wasn’t expecting Unity to perform especially well here, and it’s not because the Mono that ships with Unity is ancient and terribly slow (especially since the C# code is minimal), but I’d never expect Unity –which is a general-purpose engine– to be suitable for such a massive number of entities. It’s perfectly fine for 99% of real-world applications, and the results really don’t discredit it because 80k objects updating at 33fps is a very decent result on that hardware.
The comparison with Unity shows that KivEnt is capable of providing similar or better performance, what’s a really good thing, but KivEnt is much more ‘bare bones’ compared to Unity; Unity has a powerful scriptable editor and provides out of the box pretty much all the features you’ll need for most games, not to mention the very nice asset pipeline. KivEnt also gives you access to some pretty useful technologies like a very good entity-component architecture that’s not limited to creating ‘components’ and allows you to use a data-oriented approach on your code, and most notably you have prompt access to Kivy, which is a top-notch UI library that’s been around for some time and is very stable and usable at the moment, so UIs for your game are going to be a breeze to make.
I’ve tested various open-source engines in the past. Some don’t have friendly scripting languages and the ones that have (like GDScript/Lua/Python) aren’t exactly high performance. I’d say that KivEnt (with a bit of Cython) is by far the most performant 2D open-source game engine with friendly scripting. I’m not planning to do any 2D game in the near future, especially with VR being a reality nowadays, but I’ll surely consider KivEnt for my future 2D games.
From now on when people on IRC say that open-source game engines either have bad performance or are hard to use, you can tell them that a notable exception to that statement is KivEnt.
KivEnt also has the advantage that the knowledge needed to use it is applicable for other things beyond games when you consider for example that Kivy can be used to make apps (non-game) for many platforms. Once you learn it you will be able to build not only games but also ‘serious’ apps with high productivity. That’s not the case with most other game engines, in which what you learn generally is specific for that engine and the knowledge can’t be used elsewhere. If you don’t know Python, that’s yet another reason why KivEnt should be on top of your list in my opinion. Python is extremely valuable and I use it almost daily, be it for small automation scripts to perform boring tasks on my system, or for a server back-end.
As requested, I’m posting the Unity entity update long tail graph here, please note that this graph uses the same data as above, but it’s not on a logarithmic scale, so you can clearly see the typical “long tail” shape: