Objective: exclude debug method calls and data computations from release build.
Solution: Conditional attribute.
From the very beginning of the StoneDrop development I was aware that methods from the
UnityEngine.Debug (docs.unity3d.com/S...) class have a significant impact on game performance. That's why I've created a wrapper class (the adapter pattern, en.wikipedia.org/w...)
Logger, which is used instead of
Debug. Such an approach allows me to use conditional compilation inside the
Logger class and omit all the debug-related code from the methods in release compilation process (figure 1).
Figure 1. Conditional compilation example in Logger class. The Debug.Log calls now will be compiled out from release builds
Nevertheless the approach with the wrapper class still has it's performance penalties even in a release build. For example, the code
Logger.Say(string.Join(", ", intArray.Select(x => x.ToString()).ToArray());
still computes argument for the
Say method in the release build. This means the
Join will be called anyway and they allocate memory (advancing the
CG.Collect call) and waste CPU cycles computing the information that will never be displayed.
Today I've discovered the existence of a
Conditional attribute (msdn.microsoft.com...) in C#. It allows to exclude not only the body of a method but also the method calls from the compilation. So if we mark
Logger.Say method with
[Conditional("DEBUG")] the argument computations will be eliminated from the release build (reminder: starting from Unity 5.0 the conditional compilation symbol
DEBUG automatically added to all development builds).
To ensure that this is the case I've made a simple test code (figure 2). It works as expected: if the
CONDITIONAL_TEST is not defined then
myInt always has 0 value which means the argument computations were excluded from the runtime code.
Figure 2. Test code to check the arguments computation of conditional method are excluded from the build
Conditional attribute can be very helpful in providing the debug functionality and excluding it's performance penalties from release builds without source code modification.
If you want to use your own compilation symbols keep in mind the method calls are excluded from the code if the compilation symbol is not presented in the file with the call, not in the file with the method declaration/implementation. More details in the official documentation: msdn.microsoft.com....
UPD March 2016: Unity doesn't exclude
Debug method calls from release builds (though it's implementation is more light-weighted in the release mode). You even can find in the official documentation an advice to use code snippet
if (Debug.isDebugBuild) Debug.Log(message);
for debug purposes.
UPD June 2016: using the static
Logger class everywhere in the project is a bad architectural design approach in terms of reusability. In such a case every class in the project is dependent on the
Logger. Some reflections on this problem are presented in the book "Game Programming Patterns" by Robert Nystrom in the "Singleton" chapter.