Very Poor Performance On Mobille When Having a lot of system

[PerforamnceBug]
Recently I found CPU Time(about 10ms+) is very high in my project when running on SnapDragon845 Android Devices.This project have about 300~500 system,I found that the System.OnUpdate overhead is very hight.So I did some reseacrh to find out wheather it is my code issue or the ECS FrameWork’s issue.Then I find an Unity Test Case On github.
[https://github.com/Unity-Technologies/EntityComponentSystemSamples/tree/master/ECSSamples/Assets/StressTests/ManySystems_Linear].
I built an Android apk and Windows Build,and found that On PC,1000 System cost about 0.65ms,this is good,but on Android it cost 2~3ms on Snapdragon845 just running Empty System Which is unacceptable in a mobile game,Beacause in a real project,300~500 System is very common,and it’s .I think this maybe the DOTS Codegen performnce bug(Entitie.Foreach ?) or Entity Query Performance bug.

The Image below shows the test result

Unity Github Test Cast on PC(i9-9900k) Test

Unity Github Test Cast on Android Snapdragon845 Test

RealProject Test

3 Likes

@Joachim_Ante_1 Looking for your response,Thanks

1 Like

Why is LogicLayerGroup running in FixedStepSimulationSystemGroup?
It’s running 2 times. From my experience FixedStepSimulationSystemGroup should rarely be used, especially not for CPU intensive tasks. You can use a TickSystem if you need a fixed frame rate.
Otherwise you have to look into why it’s running 2 times.
Also, are you using Run, Schedule or ScheduleParallel? Run will perform a lot better with low entity counts.

Hi.Why the LogicUpdate group is running twice is beacuse the Targert FixedFrameStep is 16ms.If the “Many System performance issuse” is fixed this will not happen. My goal is to figure how to optimize code and let LogicUpdate cost under 4ms on SnapDragon845.By the way,the third pic is just a reference from a real game project to see how “many system performance” bad,the first and the second pic is the official test case.

Help~

From what I understand, sadly currently it’s really slow at mobile platform especially for mid end and low end phone. I really hope next version update will fix this performance issue.

2 Likes

This is a known issue. More managed systems you add - more overhead you get. Its more noticeable on mobile.

Currently, you can bypass this by aggregating logic into less systems.

There’s also a separate issue with job scheduling on newer processors that aren’t mapped correctly on some Unity versions. In this case all jobs are scheduled on a single thread, which might be a bottleneck as well.

Check Profiler’s Timeline to see if you’re hitting this bug.

Thanks for reply!

“There’s also a separate issue with job scheduling on newer processors that aren’t mapped correctly on some Unity versions. In this case all jobs are scheduled on a single thread, which might be a bottleneck as well.” Did this bug found on mobile device?

Thanks for reply.I think snapdragon845 not low-end device,but mid-high end device,I’m very much looking forward the Unity DOTS team can solve this this problem. @Joachim_Ante_1 Thanks~

Yes, specifically on Snapdragon as well.

E.g.
https://issuetracker.unity3d.com/issues/android-unity-detects-only-1-big-core-on-snapdragon-888-devices

Nexus 6P (Snapdragon 810), 1000 Systems, 1 Entity:
.Run = 5ms
.Schedule = 30ms
1000 GameObject Update calls = 3ms

My Samsung S4 Exynos gets similar results.

Joachim has said a couple of things (2 years ago):

  1. That he expects to have 1-2k systems on mobile at 60fps. This doesn’t tell us much as he didn’t specify what mobile.
  2. More meaningful was his statement that they expect 1 entity being processed by 1 system to significantly beat MonoBehaviour performance.

Currently it’s about twice as slow but if a System update call could get as fast as a GameObject Update call, I’d at least be happy with that.

1 Like

Thats what we are working towards. Essentially we are working on struct based ISystem.Those are systems where you can fully bursted the whole OnUpdate method. Hence all the base overhead of system code gets burst optimization. But also any other of your own code that runs outside of Entities.ForEach / jobs will get faster too.
So far we are seeing roughly 2-3x speedups in ISystem overhead from that (Iterating 1 entity and just copying an int from one component to another)

Additionally IJobEntityBatch has faster iteration due to caching the array of chunks that need to processed from frame to frame more effectively. Also optimisations to getting & resolving componenttype handles more efficiently. All of that is used by Entities.ForEach automatically.

ISystem & these optimizations are in the next entities release. (No date on that yet…)

32 Likes

Out of curiousity, is this ISystem just a renaming of ISystemBase or is it something new? I’m guessing it’s the same thing.

PS: Lovely as usual to get these small posts with hints on what might come :slight_smile:

@Joachim_Ante_1 Awesome. Btw can you improve class based system too? From what I observe, one reason why it’s slow is caused by usage of reflection. Remove it should able to speed it up a lot. Another issue I found is there are so many methods call even u just do a super simple operation i.e. get one component and increment by 1 and run on main thread. Since new Entities now is using rosyln codegen, maybe can make it even smarter that codegen only required method instead of like current Entities version that dump all the methods call by default to make it even faster I dunno.

1 Like

Thanks for reply.But can you improve class base system too?This is very common in real game project,Is these system performance not been improved,a lot of game dev team maybe not using dots in my experience,excpets DOTS fans :slight_smile:

By the way,Is there anything i can do NOW,to improve the System performance right now?

Yes…

Use less systems. Not the answer you want but it is the issue isn’t it?

2 Likes

Combine 300 systems into 10 GIANT systems

I don’t know enough about your project to know if this is viable for you, but one thing I do is put systems into ComponentSystemGroups and then disable the ComponentSystemGroup when none of the systems inside need to run. This skips all the EntityQuery evaluations and Dependency management while the group is disabled.

3 Likes

How do you check the systemGroup need to run or not ? I think a system need to run when its query is not empty,thus having a query.