If I have a function like this:
public void DispatchMessage(MessageIDEnum enMsgID)
{
DoReceiveMessage(enMsgID, (Parameters)m_arrayMessageParams[m_arrayMessageParams.Count - 1]);
}
Does C# have any means of forcing this function to be expanded inline like in C++?
You retain the coding illusion of a hierarchical chain of function calls but without the CPU overhead.
I can do it with this particular function call, but in general…
1 Like
For the most part the compiler makes better inlining decisions than you do. Do you have a specific use case where there is some kind of measurably better result due to inlining?
Well then that is one less thing to worry about if C# takes care of all that.
In C++, with class member function, you can implement the functions in the header file and allow the compiler to decide whether or not to inline it, or else you can use the inline key word which forces the compiler to inline a simple function no matter what.
C++ compiler will take care of itself too. Generally the inline keyword doesn’t force the compiler to inline, its a hint which the compiler can choose to ignore. See for example ms C++ compile: Inline Functions (C++) | Microsoft Learn (this does have __forceinline). Its also overused!
C# does have a similar directive (MethodImplOptions.AggressiveInlining ) but I’ve never had need to use it in Unity (not even sure Unity/Mono compiler will consider your hint). It also makes less sense in a JIT environment. So short answer: don’t bother.
Stumbled across this and sadly this is not the case:
Unity doesn’t inline as well as it should an encourages manual inlining when needed
I would agree with JohnnyA that its likely the C# hint will be ignored. I have used it in my code but not tested if it made a difference. I should probably go do that…
1 Like
A few comments on this.
First, it absolutely doesn’t encourage manual inlining- “when needed” needs to be bolded, italicized, and maybe even tattooed somewhere (this isn’t a correction, merely a clarification). As noted at the top of that page, doing any of the things in the “special optimizations” section before profiling and seeing that there’s a problem somewhere is a premature optimization. It sacrifices readability in a big way, and teaches bad habits that are only born out of Unity/Mono’s particular eccentricities here. Anywhere else in the animal kingdom, the compiler is going to optimize most of those things better than most programmers can (or should).
Also, some of the information is a bit misleading. The section on reducing method call overhead makes a couple of “optimizations” simultaneously- assigning the array length to a variable before the loop, and using a field over a property. The latter has a performance benefit, but the former does not (at least, not one that’s reasonable to justify it). It mostly just makes the code less readable. I verified this with a test of a million assignments in a single frame, and the field approach takes ~2ms, while the property approach takes ~8ms. There was zero measurable difference in the overhead of calling .Count or .Length in the loop over using a local integer variable at that level, and anything over that starts to feel incredibly contrived.
Tests were performed on the Standard 2.0-compliant compiler.
Also worth noting that if performance of these optimizations is a serious concern, you may want to simply pre-compile your libraries elsewhere (for instance, using Visual Studio). Compiling for .NET Standard 2.0 will make libraries that can be used in Unity just fine, but still have all of the nice micro-optimizations that the Unity/Mono compilers are missing, presumably. I tend to do this anyways for the framework-libraries and only use loose scripts / Unity assembly definitions for the things specific to any individual project.
1 Like
Some quotes from the page:
“The primary issue here is that Unity performs very little method inlining, if any. Even under IL2CPP
, many methods do not currently inline properly. This is especially true of properties. Further, virtual and interface methods cannot be inlined at all.”
“Trivial methods are trickier. It is extremely useful to be able to declare functionality once and reuse it elsewhere. However, in tight inner loops, it may be necessary to depart from good coding practices and instead “manually inline” certain code.”
Remember Unity takes your C# and converts it to C++ so its effectively the compiler since (now my C++ is rusty and this is an assumption from a quick google) you need to manually use the inline keyword for the C++ compiler to do any inlining.
So if Unity is not adding those inlining tags, nothing is! (This is my assumption)
However compiling a library elsewhere is an interesting idea, sadly also tedious when it comes to debugging etc but a good idea to get around this.
As a note my project has up to 500 million blocks in the scene at any time, all built from procedural meshes. The amount of data processed to generate the meshes means things like inlining are absolutely not a premature optimisation in this case.
1 Like
This assumption is wrong. C++ compiler inlines methods if it thinks the method worth inlining. This decision is based on compilation settings. More here https://stackoverflow.com/questions/1443982/when-do-compilers-inline-c-code
Hmm… this doesn’t fill me with 100% confidence! So the post does strongly agree most compilers just auto inline. However:
“Your compiler’s documentation should tell you since it is implementation dependent. For example, GCC according to its manual never inlines any code unless optimisation is applied.”
Since the Unity page states it performs very little inlining maybe the compiler it uses is less automatic. Again, a complete assumption here and couldn’t see what C++ compiler Unity uses from another quick google.
Does anyone know for sure which compiler they use under the hood?
Edit: at this stage I just need to run some damn tests
1 Like
Docs only states IL2CPP compiles converted code with “platform native compiler”, so make sure you’ve tested all platforms you’d like to develop for.
1 Like
Finally did some testing on this last night and we found that Unity indeed does not inline your methods, even if they have nothing to do with Unitys code. You have to use the aggressive inlining flag to make it inline anything, at least we think that is the case! So we made a very simple method that just did a couple addition operations, then we compiled a windows build using IL2CPP.
We then compared the contents of the folder Test_BackUpThisFolder_ButDontShipItWithYourGame/il2cppOutput (Test was the name of our Unity project) against two versions, one with and without the aggressive inline flag.
These are the results, left had the flag, right didn’t. Stupidly I deleted the code we used to generate this… but it was super simple (whilst also ensuring it was so simple as to be optimised out by the compiler which we can see in the c++ anyway)
1 Like