A lot of powerful language features like LINQ require massive performance hits, but today we’ll discuss some easy, low-overhead ways to add some safety and usability to C#.
Posts Tagged performance
Writing multi-threaded code is one of the keys to maximizing performance. Currently, this means creating your own threads and synchronizing them with C# keywords like
volatile as well as .NET classes like
Interlocked. Today we’ll take a look at how these are implemented behind the scenes by IL2CPP to get some understanding of what we’re really telling the computer to do when we use them.
C# has some powerful features like
fixed-size buffers, pointers, and unmanaged local variable arrays courtesy of
stackalloc. These are deemed “unsafe” since they all deal with unmanaged memory. We should know what we’re ultimately instructing the CPU to execute when we use these features, so today we’ll take a look at the C++ output from IL2CPP and the assembly output from the C++ compiler to find out just that.
Unity’s GC is a continual thorn in our sides. We’re constantly working around it by pooling objects, limiting use of language features, and avoiding APIs. We even call
GC.Collect on load screens in the hopes that the GC won’t run during gameplay. Today’s article goes one step further and shows how to disable the GC completely so there’s zero chance it’ll run. We’ll also see how to turn it back on when we’re ready for it again.
There are many permutations of loops we can write, but what do they compile to? We should know the consequences of using an array versus a
Length, and other factors. So today’s article dives into the C++ code that IL2CPP outputs when we write these various types of loops to examine the differences. We’ll even go further and look at the ARM assembly that the C++ compiles to and really find out how much overhead our choices are costing us.
This week we continue to look at the C++ that IL2CPP outputs for C# to get a better understanding of what our C# is really doing. Today we’ll look at how abstract methods work, whether casting of sealed classes is faster than non-sealed classes, and what happens when creating a delegate.
The last time we looked at performance was way back in part four of the series. Ever since then we’ve been relentlessly adding more and more features to the C++ scripting system. So today we’ll take a break from feature additions to improve the system’s performance in a couple of key areas.
Last week in the series we took a step back to verify that the C++ plugin’s performance was acceptable. With that confirmed, we’ll continue this week by making our programming lives easier. One pain point so far has been with exposing new Unity APIs to C++. It’s not that it’s difficult to do this, but there’s a lot of boilerplate required. That boilerplate takes time to write and it’s easy to make mistakes copying and pasting existing functions. So this week’s article introduces a code generator that will write the boilerplate for us! We’ll also reorganize the project a little so the code that supports C++ scripting is separated away from our game code. That’ll make it easy to add support for C++ scripting to any Unity project.
In the first three parts of this series, we focused on setting up a development environment that makes it easy and safe to write our game code in C++. Today’s article takes a step back to assess where we are in terms of performance. Is what we’ve built so far viable, or are the calls between C# and C++ too expensive? To find out we’ll use the existing framework to write some simple performance tests.