-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
747b004
commit 4e83077
Showing
1 changed file
with
184 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
--- | ||
slug: velaptor-release-v1.0.0-preview.31 | ||
title: Velaptor Release v1.0.0-preview.31 | ||
authors: kinson | ||
tags: [releases, velaptor] | ||
--- | ||
|
||
import URL from "@site/src/components/URL"; | ||
|
||
## Intro | ||
|
||
Welcome to the latest update on our exciting 2D game development framework <URL link='https://github.com/KinsonDigital/Velaptor' text='Velaptor'/>! | ||
We're thrilled to announce that our newest release is now live which consists of some technical debt cleanup, updates to the CICD | ||
system, and some other developer experience items, this release is all about performance. | ||
|
||
{/*truncate*/} | ||
|
||
When it comes to game development, performance is very important. With game development libraries it becomes even more | ||
important than the development of the game itself. Why is this? Game libraries such as game frameworks, | ||
game engines, and other types of libraries used to develop games are developer tools. These tools are used directly in | ||
the game and their performance characteristics directly affect the performance of the game. The more performant the library, | ||
the more "bandwidth" you are giving to the game developer for each frame of the game. | ||
|
||
This is why we will always take performance very seriously with Velaptor. We not only write code to be performant while | ||
we develop new features and make changes, but we also will take the time to further improve existing features and systems | ||
in Velaptor. | ||
|
||
## Performance Improvements | ||
|
||
The performance improvements for this release are for the most part related to the keyboard and mouse input systems. | ||
When a game is built, you never know when the user will press a key or move the mouse. Because of this, you have to poll | ||
for the state of the keyboard and mouse for every frame. Anything that ends up being executed as part of the game loop | ||
can be a candidate for performance improvement or degradation. | ||
|
||
Specifically, this release focuses on improvements in getting the state of the keyboard and the mouse using the `Keyboard.GetState()` | ||
and `Mouse.GetState()` methods. The types `KeyboardState` and `MouseState` returned by the methods mentioned above have | ||
also been improved. The improvements involve not only the performance of collecting the state but also reducing the | ||
memory allocations that were occurring during the collection of the state. | ||
|
||
When developing games with garbage-collected languages such as C#, you have to take memory allocations into account. | ||
The more memory you allocate on the heap during the game loop, the more often your game could trigger garbage collection. | ||
|
||
:::info NOTE | ||
Garbage collection is a process that runs in the background of your application and cleans up memory that is no longer | ||
being used. This process can be expensive when it comes to the time constraints of video games. This is not to say that | ||
garbage collection is bad in video games, it is just that too many collections that affect the performance of YOUR game can | ||
be problematic. | ||
::: | ||
|
||
C# is a great choice for game development and has a lot of successful 2D and 3D games that have been developed with it. | ||
|
||
## Tools used to collect performance data | ||
|
||
When it comes to collecting and measuring the performance of C# code, the best tool in my opinion that exists for this is | ||
<URL link='https://github.com/dotnet/BenchmarkDotNet' text='BenchmarkDotNet'/>. This tool is used by the .NET team to | ||
measure the performance of the .NET runtime and the .NET libraries. It is also used by many other open-source projects | ||
to measure the performance of their code. | ||
|
||
## Improvement Results | ||
|
||
The performance gains that were achieved were impressive. Though these gains might not be noticeable for some games, indeed | ||
they would be for others. Remember, not all games are created equal and some games require more performance than others. As | ||
mentioned before, these efforts matter because our goal is to not be the bottleneck for your game. The gains here are always | ||
about and will always be about giving you more "bandwidth" to work with as well as reducing allocations. | ||
|
||
It was important to improve these _**classes**_ and _**structs**_ because they are used in the game loop of 99% of games. | ||
These types were great candidates for improvement. | ||
|
||
The types that were improved were `KeyboardState`, `MouseState`, and `Keyboard`. When measuring performance, it is important to | ||
get a good baseline before making any changes. So we created a <URL link="https://github.com/KinsonDigital/Velaptor/tree/preview/Performance/KeyboardPerf" text="performance project"/> | ||
to accomplish this. | ||
|
||
Here are the baseline results for the `KeyboardState` and `Keyboard` types. | ||
| Method | Mean | Memory Allocations | | ||
|---------------------------------------- |---------:|-------------------:| | ||
| KeyboardState.IsKeyDown | 1.965 us | 8.2 KB | | ||
| KeyboardState.IsKeyUp | 1.971 us | 8.2 KB | | ||
| KeyboardState.SetKeyState | 2.042 us | 8.2 KB | | ||
| KeyboardState.KeyToChar | 1.980 us | 8.25 KB | | ||
| KeyboardState.GetDownKeys | 2.136 us | 8.23 KB | | ||
| KeyboardState.AnyAltKeysDown | 2.054 us | 8.2 KB | | ||
| KeyboardState.AnyCtrlKeysDown | 2.100 us | 8.2 KB | | ||
| KeyboardState.AnyShiftKeysDown | 2.571 us | 8.2 KB | | ||
| KeyboardState.AnyNumpadNumberKeysDown | 2.061 us | 8.23 KB | | ||
| KeyboardState.AnyStandardNumberKeysDown | 1.985 us | 8.23 KB | | ||
| KeyboardState.IsLeftAltKeyDown | 1.684 us | 8.2 KB | | ||
| KeyboardState.IsLeftCtrlKeyDown | 1.969 us | 8.2 KB | | ||
| KeyboardState.IsLeftShiftKeyDown | 1.940 us | 8.2 KB | | ||
| KeyboardState.IsRightAltKeyDown | 1.894 us | 8.2 KB | | ||
| KeyboardState.IsRightCtrlKeyDown | 1.966 us | 8.2 KB | | ||
| KeyboardState.IsRightShiftKeyDown | 1.933 us | 8.2 KB | | ||
| Keyboard.GetState | 3.230 us | 8.2 KB | | ||
|
||
As you can see, many games would probably be ok with these results if you had a simple game or more importantly did not have | ||
a lot of input-related code. The time unit of measurement here is microseconds. A microsecond is 1 millionth of a second. | ||
Though this might seem like a small amount of time, it can add up quickly when you are running at 60 frames per second. This | ||
of course depends on the type of game you are building. There are other things in the game loop besides collecting the state | ||
of the keyboard and mouse. You would be surprised how quickly those things can add up. | ||
|
||
One way I like to think of it is the "bandwidth" that you are working with every frame. This helps put things into perspective | ||
in regards to how a certain part of your game might affect everything else. If the game was running at 60 frames per second, | ||
then you have 16.67 milliseconds to work with. If you were to convert this into microseconds, you would have 16,660 microseconds | ||
to work with for the entire frame. That number does not sound so great when you could have many other things in your game | ||
that need some of that frame bandwidth. | ||
|
||
Here are the results after all of the improvements were made. | ||
| Method | Mean | Allocated | | ||
|---------------------------------------- |-----------:|----------:| | ||
| KeyboardState.IsKeyDown | 2.926 ns | - | | ||
| KeyboardState.IsKeyUp | 2.570 ns | - | | ||
| KeyboardState.SetKeyState | 3.417 ns | - | | ||
| KeyboardState.KeyToChar | 7.785 ns | - | | ||
| KeyboardState.GetDownKeys | 128.989 ns | 104 B | | ||
| KeyboardState.AnyAltKeysDown | 4.244 ns | - | | ||
| KeyboardState.AnyCtrlKeysDown | 4.240 ns | - | | ||
| KeyboardState.AnyShiftKeysDown | 4.302 ns | - | | ||
| KeyboardState.AnyNumpadNumberKeysDown | 17.443 ns | - | | ||
| KeyboardState.AnyStandardNumberKeysDown | 21.220 ns | - | | ||
| KeyboardState.IsLeftAltKeyDown | 2.119 ns | - | | ||
| KeyboardState.IsLeftCtrlKeyDown | 2.161 ns | - | | ||
| KeyboardState.IsLeftShiftKeyDown | 2.128 ns | - | | ||
| KeyboardState.IsRightAltKeyDown | 2.140 ns | - | | ||
| KeyboardState.IsRightCtrlKeyDown | 2.210 ns | - | | ||
| KeyboardState.IsRightShiftKeyDown | 2.188 ns | - | | ||
| Keyboard.GetState | 591.791 ns | 2752 B | | ||
|
||
The results are impressive. Notice that the timescale has changed from 'us' to 'ns'. 'ns' stands for nanoseconds which | ||
is 1 billionth of a second. This is a very small amount of time. At this scale, there are 16,660,000 nanoseconds in a | ||
single frame. This is huge!! Another thing to notice is the huge amount of reduction in memory allocations. | ||
|
||
To help put this improvement into perspective, refer to the table below with the time scale of the baseline converted | ||
into nanoseconds. | ||
| Method | Time Before | Time After | Perf Improvement | | ||
|----------------------------------------:|------------:|-----------:|-----------------:| | ||
| KeyboardState.IsKeyDown | 2042 ns | 2.926 ns | 99.83% | | ||
| KeyboardState.IsKeyUp | 2164 ns | 2.570 ns | 97.63% | | ||
| KeyboardState.SetKeyState | 2136 ns | 3.417 ns | 93.96% | | ||
| KeyboardState.KeyToChar | 2061 ns | 7.785 ns | 99.15% | | ||
| KeyboardState.GetDownKeys | 1965 ns | 128.989 ns | 99.85% | | ||
| KeyboardState.AnyAltKeysDown | 1971 ns | 4.244 ns | 99.87% | | ||
| KeyboardState.AnyCtrlKeysDown | 1980 ns | 4.240 ns | 99.61% | | ||
| KeyboardState.AnyShiftKeysDown | 2054 ns | 4.302 ns | 99.79% | | ||
| KeyboardState.AnyNumpadNumberKeysDown | 2100 ns | 17.443 ns | 99.80% | | ||
| KeyboardState.AnyStandardNumberKeysDown | 2571 ns | 21.220 ns | 99.83% | | ||
| KeyboardState.IsLeftAltKeyDown | 1684 ns | 2.119 ns | 99.87% | | ||
| KeyboardState.IsLeftCtrlKeyDown | 1969 ns | 2.161 ns | 99.89% | | ||
| KeyboardState.IsLeftShiftKeyDown | 1940 ns | 2.128 ns | 99.89% | | ||
| KeyboardState.IsRightAltKeyDown | 1894 ns | 2.140 ns | 99.89% | | ||
| KeyboardState.IsRightCtrlKeyDown | 1966 ns | 2.210 ns | 99.89% | | ||
| KeyboardState.IsRightShiftKeyDown | 1933 ns | 2.188 ns | 99.89% | | ||
| Keyboard.GetState | 3230 ns | 591.791 ns | 81.68% | | ||
|
||
This is an average improvement of 98.25% across the board for the keyboard. | ||
|
||
Here is the comparison of the memory allocations. | ||
| Method | Before | After | | ||
|----------------------------------------:|--------:|--------:| | ||
| KeyboardState.IsKeyDown | 8.2 KB | 0 B | | ||
| KeyboardState.IsKeyUp | 8.2 KB | 0 B | | ||
| KeyboardState.SetKeyState | 8.2 KB | 0 B | | ||
| KeyboardState.KeyToChar | 8.25 KB | 0 B | | ||
| KeyboardState.GetDownKeys | 8.23 KB | 104 B | | ||
| KeyboardState.AnyAltKeysDown | 8.2 KB | 0 B | | ||
| KeyboardState.AnyCtrlKeysDown | 8.2 KB | 0 B | | ||
| KeyboardState.AnyShiftKeysDown | 8.2 KB | 0 B | | ||
| KeyboardState.AnyNumpadNumberKeysDown | 8.23 KB | 0 B | | ||
| KeyboardState.AnyStandardNumberKeysDown | 8.23 KB | 0 B | | ||
| KeyboardState.IsLeftAltKeyDown | 8.2 KB | 0 B | | ||
| KeyboardState.IsLeftCtrlKeyDown | 8.2 KB | 0 B | | ||
| KeyboardState.IsLeftShiftKeyDown | 8.2 KB | 0 B | | ||
| KeyboardState.IsRightAltKeyDown | 8.2 KB | 0 B | | ||
| KeyboardState.IsRightCtrlKeyDown | 8.2 KB | 0 B | | ||
| KeyboardState.IsRightShiftKeyDown | 8.2 KB | 0 B | | ||
| Keyboard.GetState | 8.2 KB | 2752 B | | ||
|
||
For the methods that still cause allocations, the average improvement is 97.95% decrease in allocations. | ||
The rest of the methods have no allocations at all, which is ideal and what we are looking for. | ||
|
||
This would arguably be a bigger win vs the processing time improvements. | ||
|
||
## Improvement Methods | ||
|
||
|
||
## TODO: Link to the code changes of the PR if people are interested |