Optimize systems
Every system has a fixed performance overhead. When you create a system it always has the following default behaviors:
- Each system accesses a structure called EntityTypeHandleto iterate over the chunks that match anEntityQuery. BecauseEntityTypeHandlestructs are invalidated by structural changes, each system gets its own copy before eachOnUpdate, so the CPU overhead of these accesses grows linearly with the number of active systems.
- When scheduling or running a job, your code might need to get a ComponentLookupor aBufferLookupto pass to the job. An application with a lot of systems might end up creating the same lookup structures in different systems. This means that those copies need to be updated every frame the system uses the lookup, which is necessary to account for possible structural changes.
- Every system contains one JobHandlenamedDependency, either in theSystemStateobject or theSystemBaseclass. There's overhead involved in calculating before executing the system, and in considering the system's scheduled jobs for the next system'sDependencyhandle. More systems in an application means more jobs and a more complex chain ofJobHandledependencies.
Managing OnUpdate calls
You can add the [RequireMatchingQueriesForUpdate] attribute to the system to instruct it to only execute its OnUpdate method when there's data to process. However, the system still performs a check every frame to find if any entities match any of the queries the system uses.
Systems that have matching entities run their Update methods, and systems with none don't update. The test is fast, but the time adds up in applications with many systems. As an alternative, you can use an if check at the top of OnUpdate, which can be faster than [RequireMatchingQueriesForUpdate], depending on what you put in the check.
Also, avoid using the [RequireMatchingQueriesForUpdate] attribute on systems that don't run all or most of the time. For example, a system related to a player character doesn't need to check for matching queries because the player character exists all the time. However, a system related to a specific level of a game can use the [RequireMatchingQueriesForUpdate] attribute if it only needs to run at a certain point in your application.
Burst compiler behavior
If you use the Burst compiler, the overhead is lower on systems created with ISystem, than those created with SystemBase. To get the best performance while using Burst, use ISystem based systems.