IceGuye Blog

Performance Matters, Even for Your First Personal Project

"You guys need to grow up. Most your projects will run well even in Pentium 4 with a slower programming language. " This is usually how some experts tell newbies not to worry about performance issues, and choose one of the simplest platforms to learn. It is true that many computer science departments in universities choose Python or JavaScript to start their 101 class, and yes, they can find a job, and they can learn something more serious later.

They Are Not Neccessary Accurate...

However, when it comes to your real personal projects, the statement at the very beginning of this article seems inaccurate. Even for a small project, performance matters. It can highly affect the usability of your projects.

Two Examples

Two personal projects are used here for the comparison. The first is IcePiano (https://gitlab.com/iceguye/icepiano), the other is IcePiano-R (https://gitlab.com/iceguye/icepiano-r). The two projects do the exact same thing -- receiving the midi signal from a midi piano and play the sound, or to be simplified, they are midi virtual piano. They also have a graphical interface (a window) to displace which notes are playing, and how strong they are hit. They both use SDL2 as a backend to process the sound and the window.

They have their differences. The first project, IcePiano, is written in Python, and the other one, IcePiano-R is written in Rust. The Python one is clipping occassionally while playing. After being used for a while, it was rewritten in Rust, and the Rust version runs very well, and is still being used for today.

But Isn't SDL2 Written in C, and C is Fast?

C has been used for decades, especially in lower level programming. Hundreds of C programs are running as essential system components. It is very common that newer programming languages need to more or less wrap some C libraries. It is a common misconception that if the programming language (C in this case) which is wrapped is fast, the whole program will be fast, and the performance of the higher level programming language should not affect the speed.

This is true only if you carefully use the slower and higher level language to program the light jobs, and are able to seamlessly pass all the heavy duty jobs to the C program. Otherwise, the project will run slow. Think about that, everything will go to assembly and eventually binary, aren't they even faster?

So, What Exactly Happens in the Two Examples?

Let's go back to our two examples. Before SDL2 processing the sound you wanted to play, a fixed size buffer needs to be assigned to the SDL2. The size can be anywhere from 128 to 4096. It may be allowed to be higher. If the buffer is too small, then you will hear the sound clipping; if it is too big, the sound play will be delayed. In the case of midi piano playing, you will feel like you are playing a lagged and low fps video game. (Technically it is a video game).

The SDL2 will copy a part of the sound data to the buffer, then the sound card (DAC) will take the sound from the buffer, then play it. The sound card is blasting fast to take and play the sound, because it is designed to only do that with a smaller instruction set. On the other hand, your CPU is much slower to copy the data into the buffer. Even if the CPU is fast for this single job, it will need to do something else too. Therefore, there will be gaps between each buffer feeding.

If the buffer is too small, when the sound card already finish playing the current part of the sound, the CPU still has no time and no power to feed the next part into the buffer. When the CPU finally can do that, it will not continue to feed the next part. Instead, it will skip the next part, and feed the part after the next part, because it wants to catch up the sound card.

If the buffer is too big, the sound card will also take longer time to finish playing each part. After the sound card already finishing each part, the next buffer is ready, because the CPU also has enough time to feed the buffer. However, the CPU will take longer time and more power to copy each buffer, so it may not have enough time to deal with other jobs. This is why you may feel the program being lagging.

In a modern CPU, the SDL2 suggests that the buffer size somewhere from 512 to 2048 will be a good balance to eliminate both clipping and lagging. However, this does not happen in the Python version of IcePiano. It is either clipping or lagging, and sometime you can even feel both. The Python codes which handling all the other calculations except for the sound and graphics consume too much CPU power, so the CPU simply does not have enough time to handle the sound buffers.

The Rust version of IcePiano (IcePiano-R) do not have this issue. It works well with the buffer size from 256 all the way to 4096, no clipping, no lagging. It takes the benefits from the compiled binary and concurrent features from Rust. The compiled binary program is significantly faster than interpreted scripting language. The concurrent programming seperates the midi receiving, note volume and velocity calculation, graphical interface to different threads.

Although both IcePiano and IcePiano-R are considered as video games, their loops are not running in 60hz or 144hz, which is common in many other conventional games. In those 60hz or 144hz conventional game, programmers usually believe that they have enough time to calculate many things in each frame. Even if they cannot, they probably can consider distributing those worker threads to different frames. In conventional games, people don't feel lagging in 30ms, but in midi piano program, pianists can play a dozen of notes in the same time, thousands of nano seconds of lagging between each note can be easily detected.

So Let's Listen to the Sound?

PerfectHS is one of my early piano works which was played on the Python version of Icepiano: https://gitlab.com/ice-foss-music/foss-music-2021-07-03/-/blob/master/perfecths.webm

You may or may not be able to hear the clipping, but if you open the sound file in some audio editing software, such as Audacity, you can see some of them in the waveform.

The Moonlight Night is one of my recent piano works played on the IcePiano-R (the Rust rewritten of IcePiano). You will not hear any clipping, and even if you open it on an audio editor, you will not see any clipping in the waveform. https://arweave.net/jVid2TTQ1g9j_sU6_4AlJm6hkAKiNznUYLCTEx-fobk/the-moonlight-night.mp4




Back to Blog's index