Kotlin/Native vs. C++ vs. Freepascal vs. Python: Measuring FPS, RAM and CPU Usage, Size of the Compiled Executable File Across Codebases | by Alex Maryin | May, 2022

A comparison

Starfield animation of Python app

Hello, everyone! As I promised in the first part of this blog-post series, I pleasure to welcome you into the second part of our journey where I am trying to find the truth comparing Kotlin/Native with C++, Freepascal, and Python through its performance with openGL graphics and coding pleasure.

Contents

  1. Simple math with native apps, or who’s so clever tonight?
  2. Graphic test with SDL2, or Across the Universe with Norton Commander. — you are here —

Motivation

This post by Vyacheslav Arkhipov inspired me to start the research. If you are oldy geek you should remember that old CRT-displays for PC had a burn-in effect.

Wiki: Burn-in is when images are physically “burned” into the screen of the CRT; This occurs due to the degradation of the phosphors due to prolonged electron bombardment of the phosphors, and happens when a fixed image or logo is left for too long on the screen, causing it to appear as a “ghost” image or, in severe cases, also when the CRT is off. To counter this, screensavers were used in computers to minimize burn-in. Burn-in is not exclusive to CRTs, as it also happens to plasma displays and OLED displays.

And the one of the famous screensavers for PC was Starfield which you should see below the title of this post. Imagine you are commander Jameson inside of the Cobra MK3 and you are enrouting across the universe searching for Targoids craft. Stars are rushing around and you faster than lightning in a hundred times…

Starting from Python

I have updated a little the code from original source to print FPS in the window’s title, to use other drawing functions for getting anti-aliasing effect and to add variable radius property for star, thus stars got a smooth growing effect:

It’s complete code in Python, but don’t forget to install Pygame library if you want to reproduce this one on your machine.

The hardest part is to turn it into other languages. Pygame library itself uses SDL graphic library to encapsulate low-level interfaces with openGL (or DirectX on Windows). All we need is to write our own xxGame engine for each language… Uuh. Let’s go.

C++ pole-position

I think, the simple way to begin is to implement the Starfield is on the native platform for SDL, ie C++ language, and then turn it into Kotlin or Freepascal variants.

Disclaimer: Because I am not familiar a lot with direct SDL programming on C++ I have studied its basics from video series by Carl Birch on YouTube here and I recommend them as a perfect start.

Let’s get away from Python code above and use ++ benefits of the language. C++ has two kinds of classes which we can use: class itself and struct. The difference between them is how class members are declared by default, as private or as public members. Otherwise both class and struct are similar.

I declare the struct Star and encapsulate its behavior for creating, updating and revival:

It has a default constructor which invokes the newStar function and similar also happens when this star is moved off the screen. We will use an array (vector in the words of C++ STL) of Star objects instead of global list with unnamed parameters as presented in Python.

Of course, we could use a static array in plain C++ instead of a dynamic vector because we already know it’s size, but I prefer to make code with some opportunities for future enhancement. For example, we can dynamically increase or decrease stars amount with vector in runtime.

At the beginning of our main function in C++ program we should prepare SDL engine for drawing:

Here two pointers will be created for the SDL window and Render context. Yes, we could create any number of windows and render contexts with SDL. All the next used SDL functions which perform drawing should use render context and some other functions need a window pointer for execution.

But there is a little problem… SDL has no function to draw a filled or an outlined circle from the box! Thanks to Github, I found the necessary algorithm in a matter of seconds. That code uses Bresenham’s circle algorithm and is provided us by Gumichan01 under the MIT license. All brilliant — just! Look, how’s simple to draw a rastered circle:

So, now we are ready to the main code:

I’ve skipped some parts of the code but you may clone the full project from my repository.

So, as you can see I wrote a very simple code in C++ and it is almost similar to Python code with the only difference being the use struct and encapsulating some behaviour. This code should be a start point for the next one, in Kotlin. Let’s see, how we could enhance this code without performance breaks.

Programming on plain openGL and SDL is a solid structural sequence of functions without any logical blocks or functional scopes inside. The following pseudo-code is showing literally what I mean:

init all;
clear screen; // suppose, 1st frame
draw point;
swap buffers;
clear screen; // 2nd frame
draw lines;
draw triangles;
draw anything else;
swap buffers;
clear screen; // 3rd frame, etc.

This is a standard flow that could be run in any C/C++ program. Of course, you could use logical blocks and drawing organize frames yourself, but the framework doesn’t force you to it.

Kotlin brings opportunities to build your code in declarative style using DSL. With DSL you can wrap one logical block into another and specify restrictions for its scope or sequence of invocation of blocks with clear and concise syntax. If you are already familiar with Ktor or another Kotlin framework built with DSL style, you understand me. By the way, 2D game engine LibGDX famous in JVM world has Kotlin enhancements called LibKTX which makes possible to use DSL style and develop games faster with clear, auto-explaining code.

I was studying how to use this framework on the series of video by Quillraven ‘LibGDX Kotlin tutorial’ until I built my first simple multi-platform game Deter revolution. And now Quillraven is building his own lightweight ECS (entity component system) engine called Fleks on the top of LibGDX using Kotlin DSL.

But, no words! Let code to show what I mean:

SDL Engine {
init Engine()
init Environment()
add Event Listener {
for quit event -> stop engine and close app
}
start Infinite Loop {
on Each Frame {
draw magic
show FPS
}
}
}

That’s how I imagine the main code of Kotlin variant of Starfield! You may be amazed that DSL allows to turn that pseudo-code in Kotlin literally one-to-one:

It’s beautiful, isn’t it? This is a whole main function. SDLEngine is a function with the receiver of an Engine class. Inside of lambda (which is a last parameter of function), the instance of this class is available as this variable, and you can exclude it in codeword this if it isn’t interfering with any other upward scope receiver.

I moved engine initialization parameters into SDLEngine function — width and height of the window. addEventListener is a function inside the engine scope that would be invoked on each event from the engine.

startInfiniteLoop is also a function inside the engine scope which turns graphic renderer on. In my simple engine this function will be running until the window be closed. onEachFrame is the function with receiver of SDL Renderer pointer which needs for any SDL drawing function. I declared renderer as a private member of the Engine class and you won’t get it outside of onEachFrame function, so you can’t draw anything outside frame.

In my opinion, that declarative style allows you to avoid mistakes and brings more clarity and simplicity. But for the first…

How to include SDL lib in Kotlin/Native

This was really complicated part of my discovery, but my present body of knowledge allows you to pass this way faster. At first, you should install SDL2 it into your machine. I used Ubuntu and all what I need is sudo apt install libsdl2-dev. Installation is more different for other platforms.

Then you should study carefully backward and forwards next tutorials and articles from official Kotlin docs:

  1. Get started with Kotlin/Native in IntelliJ IDEA. This tutorial introduces basics of native application building in Kotlin using IDEA.
  2. Interoperability with C. This is the most important part! It describes how to include 3rd parties dynamic libraries into your project. There are a lot of specific things with each library concerning only it. And don’t skip the part of Bindings! It’s very very important if you plan to use C++ types like pointers, enums, classes/structs and callbacks.
  3. Mapping primitive data types from C. As I didn’t still say that it’s a very important part too?

So, having regard to that tutorials, I created the next directories inside the project: project/src/nativeInterop/citerop and put a file sdl2.def into it. The file contains this:

package = platform.SDL2
headers = SDL2/SDL.h
compilerOpts = -I/usr/include -I/usr/include/x86_64-linux-gnu -I/usr/include/SDL2 -D_POSIX_SOURCE
compilerOpts.linux = -D_REENTRANT
linkerOpts = -L/usr/lib/x86_64-linux-gnu/ -L/usr/lib64 -lSDL2

Then, I edited build.gradle.kts project file adding to kotlin/nativeTarget extension the following:

compilations.getByName("main") {
cinterops {
val sdl2 by creating
}
}

After that (and of course Gradle sync) I found a new task called cinteropSdl2Native in the Gradle tasks tool window. It’s necessary to run this task before you try to use any of the headers from *.def files.

It’s not a finish! After all of that, it’s time to rebuild the project. And now we can import new package platform.SDL2 (name is defined in .def file).

So, now we can turn DSL to SDL! That’s a pretty anagram. Here is a full code of file with my SDL engine:

It’s doing anything the same as his C++ brother but encapsulating it away from user [of SDL]. Star class I defined is a plain class, not a data class, because it allows to avoid unnecessary generated code which is helpful for data classes when they compares with each other. This is not needed for my program.

The repository with rest of code you may find here on my Github.

Freepascal SDL usage

Freepascal includes SDL headers from the box since version 2.2.2. But we need SDL2 headers. The site https://www.freepascal-meets-sdl.net/ can help us. Also, it is a perfect place to start studying SDL2 in Pascal if you are new to it.

Download Pascal headers for SDL2 from this Github repo and place it into preferable directory (I always set default directory which Lazarus created in /home/user/.lazarus).

Then please carefully read tutorials from the mentioned site and read.me from the repository, because Pascal interop modules have other type names not similar for C++ types. As well as Kotlin c-interop preparations, doesn’t it?

Below is the function converted from C++ for circle drawing in Freepascal:

And this is a complete code for Freepascal similar to the C++ variant:

Contest and results

Finally, we can start with our beginning idea. Let’s build a release for each language (I know, I know, Python, you can’t) and see how fast is it and how small is it.

This is a specification of my laptop which I have used for coding and testing: Acer Aspire 3, 8 Gb RAM, CPU Intel Core i3–1005G1, 240 Gb NVME m.2 disk, Ubuntu 22.04 x64, OpenGL 4.6, SDL2, and last versions of Intellij IDEA, VS Code, Lazarus and PyCharm, OBS for screen capturing.

I’ve measured the size of the executable file, FPS with 200 stars, and used memory and CPU loading. I’ve captured with OBS how all of the programs ran but OBS has eaten almost a half of all resources, that’s why FPS on the video was smaller than in pure tests:

I got the following pure results with 200 stars of Starfield:

FPS with 200 stars

The result is the proof of all proofs. But think, I won’t go so far if I say that a little difference between C++, Freepascal, and Kotlin is only statistical.

Talking Python, I think, PyGame has its own optimization strategy and FPS smaller than 500 is not a ground for tragedy. Also, I don’t know what circle algorithm PyGame uses exactly, but it seems a little different than our custom one for others.

But let’s shake the machine and get away from childish things. Who’s need 200 stars? Let it draw 5000!

During the screen capturing when OBS was eating a half of resources again (and my knees were burning by laptop’s heat) the FPS was almost the same for all of our contestants! And it was amazing for me. But the results of pure test surprised me even more:

FPS with 5000 stars

Are you seeing this? Pure C++ program, pure Freepascal program, and pure Kotlin/Native program take literally the same resources and gives literally the same FPS. But if you scroll up it will be clear, that the code of the Kotlin program is more complicated than the code of C++ and Freepascal one. We wrote a complex DSL logic for our comfort later, but it does not affect runtime performance — it needs the same RAM, the same CPU load as the smaller low-level code. Even the size of the exe file is smaller by 3 times than Freepascal file (without debug info).

Of course, Kotlin as a young language doesn’t have a big, commerce graphic engine like Unity3D for C# or UnrealEngine for C++, but it has a great opportunity to get its own place in this world. I believe it’s only beginning of great and long story!

As for me, I’ve got all evidence that choosing Kotlin was the right decision of my recent years: Android mobile, back-end, desktop applications, 2D and 3D games — all of these roads are opened for Kotlin.

Thank you for completely reading to this finish line!

Leave a Comment