Skip to content

Performance critical context and costly methods

Matt Ellis edited this page Jul 7, 2023 · 11 revisions

Performance critical context

Unity event functions Update, LateUpdate and FixedUpdate are called very frequently, either every frame or often enough to match the fixed frame rate. Similarly, methods invoked as coroutines can be suspended and resumed per frame. It is clear that these methods can affect the performance of your game, and it is important to be aware of, and hopefully avoid, expensive operations within these methods, and within the methods that call them.

Rider will highlight these frequently called methods and each method called from them via line markers in the editor gutter. These methods are considered to be a performance critical context. Inside this context, Rider will add performance indicators to highlight expensive methods and operations.

These highlights are not traditional inspections such as warnings or suggestions - the code isn't "wrong", but is doing something that is known to be expensive, and avoiding that code pattern is likely to be a good thing for the performance of your game. Typically, there is no simple mechanical fix for these highlights, and avoiding the operations usually requires larger work, such as rewriting or even some element of rearchitecting. Essentially, these performance indicators are intended simply to provide awareness that expensive operations are taking place. It is up to you to decide if you wish to avoid these operations, and how to do so.

It is important to note that these performance indicators are not a substitute for performance profiling. While an operation might be highlighted as expensive, it is entirely possible that performance is "good enough" with the code as it stands. Always be measuring!

Expensive operations

Rider will highlight various well-known expensive operations inside a performance critical context:

  1. Calls to AddComponent methods
  2. Calls to Find methods
  3. Calls to GetComponent methods
  4. Calls to Debug.Log methods
  5. String based method invocation
  6. Usage of the Camera.main property
  7. Comparing Unity objects with null

If a method contains one of the above expensive operation, it is itself marked as expensive, and this propagates back to the original calling method. In other words, Rider will highlight any method as an expensive operation if it contains an expensive operation or calls another method that contains an expensive operation. For example, given the following:

public void Update()
{
  DoSomething();
}

private void DoSomething()
{
  DoSomethingExpensive();
}

private void DoSomethingExpensive()
{
  var c = GetComponent<Grid>();
  // ...
}

Then all methods, Update, DoSomething and DoSomethingExpensive are marked as a performance critical context, with a marker in the editor gutter. The call to GetComponent is marked as an expensive operation, and this propagates back to the original caller. So the call to DoSomethingExpensive is marked as an expensive operation, and finally the call to DoSomething is also marked as expensive.

Note that API calls will still be marked as expensive if they're wrapped in an if block. It is not possible at edit time to know how likely it is that one branch of an if statement is called. It might be that the if is only invoked once per lifetime of the object, or it might be invoked 50% of the time, or on every call. This is another reason why the highlights are informational and not treated as a warning - this code isn't wrong, it's intended to inform you that this API call is expensive.

Propagated context

Rider will propagate the performance critical context to methods called from root methods such as Update and FixedUpdate. These methods are also treated as a performance critical context, and will highlight expensive methods, and will propagate the context to other called methods. If any of the methods in the performance critical context call an expensive API, then that method is treated as expensive, which propagates back to the original method. So an Update function will highlight a method as expensive if any of the nested methods it calls uses an expensive API.

If you see that a method is marked as "frequently called", you can use the Incoming Calls action in the Alt+Enter menu. This allows seeing who is invoking this method, and can be used to walk up a call tree to find the root Update or other frequently called method.

Note that this feature is based on the call tracking feature, and can have very smart and surprising results. For example, a method can be marked as frequently called if it's passed as a delegate or Action to another method, and invoked there.

Disabling performance inspections

You can disable the expensive method highlights individually in the Preferences | Editor | Inspection Settings | Inspection Severity | C# settings page, and disable all performance inspections or the performance indicator gutter line marker in the Preferences | Languages & Frameworks | Unity Engine settings page. You can also edit the colours of these highlights in the Preferences | Editor | Color Scheme | Unity page.

Clone this wiki locally