Search Unity

(Case 940893) Physics.SyncTransforms() performance issue

Discussion in '2017.2 Beta' started by Peter77, Aug 10, 2017.

  1. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    5,603
    The Profiler in Unity 2017.2.0b6 shows that manually syncing transforms, once per update, is slower than the Physics system performance in earlier Unity builds, such as 2017.1.1p1.

    According to the Physics.autoSyncTransforms information I could find, one reason to introduce this new API in 2017.2 is to provide a way to help to improve performance.

    However, my tests show that physics performance is worse in both cases, with autoSyncTransforms enabled and disabled, compared to Unity 2017.1.1p1.

    Manually syncing transforms (using Physics.autoSyncTransforms=false and Physics.SyncTransforms()) is about 1ms slower than the physics system in 2017.1.1p1 in my tests.
    2017.2.0b6 - CPU time between 2.6ms - 5.0ms by average
    2017.1.1p1 - CPU time between 2.3ms - 4.3ms by average


    Please see the video attached to the bug-report.


    Reproduce
    • Open user attached project
    • Open Assets/Scene.unity
    • Open Window/Profiler
    • Press Play
    • Write down CPU time.
    Repeat these steps with Unity 2017.1 and observe 2017.2.0b6 is slower.


    Expected
    Physics should not be slower than in a previous version.
     
    ProtonOne, PhilSA and LeonhardP like this.
  2. MrEsquire

    MrEsquire

    Joined:
    Nov 5, 2013
    Posts:
    2,712
    Excellent bug report and find Peter good work...
     
    Peter77 likes this.
  3. davidfrk

    davidfrk

    Joined:
    Feb 13, 2017
    Posts:
    43
    From what I understand, even with the autoSync off, SyncTransforms() is called before the physics simulation step. So if you're calling SyncTransform manually once, it's actually being called twice.
    There are other things that would cause the update as you can see here.
    And maybe have a dirty bit, making the test more difficult but not less important.
     
    Peter77 likes this.
  4. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    5,603
    I think you're right. I wasn't aware it still syncs transforms even after telling the system to not do that. I've to check whether performance is OK if I remove that SyncTransforms() call.

    Thanks for the info, very helpful!
     
  5. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,599
    Excellent find. Have you tested performances in builds (not in-editor), just in case?

    I know sometimes certain features generate debug information in-editor and are therefore much slower. For instance, GetComponent() can generate GC allocs in-editor if the component was not found, because it creates a new warning message string.

    But I'm not sure if a development build would have the same problem.... maybe the only real way to "profile" it would be to make a very physics-heavy scene and then compare framerates?
     
  6. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    5,603
    Yes, the numbers I posted are from a Windows Standalone build. But I'm not sure if that's really an issue, I need to re-test without calling SyncTransforms().
     
    PhilSA likes this.
  7. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    5,603
    I profiled this case too now, where I do not call SyncTransforms(). CPU time did improve, but it's still about 0.5ms slower than 2017.1.1p1. Will update the bug-report now, to let QA know about the recent findings.
     
  8. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    4,928
    Unity just exposed physics sync in the API. Since access to the API can only be done in the main thread I wonder if this is why those old physics bits now show up in the profiler, where previously, they were done invisibly in a separate thread.
     
  9. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    3,679
    When you change a Transform in any way, an internal notification message gets sent to components on the same GO and all its children. This could become expensive depending on the components reacting to it. For physics components, often they needed to perform a (relatively) costly update to ensure that physics was synchronised. This update happened synchronous to the Transform change as well. It also meant that if you modified a Transform in multiple steps like setting position, rotation or scale separately then it happens multiple times.

    In 2017.2, due to internal requirements of the C# job system, this change notification was removed from the Transform system and replaced with an alternate method that used the C++ job system to retrieve a set of Transforms that have changed. This meant that component owners such as the 2D and 3D physics teams needed to deal with these consequences and make changes that ensured that legacy behaviour was maintained but also that the new behaviour could be used.

    Now when a Transform changes, no components are updated because there isn't a notification from the Transform system at all! This means its faster but it also means that the associated components need to be synchronised to the Transform change(s) but it is deferred until required.

    So when is it required? From the physics system POV, a SyncTransform is done prior to updating the simulation during fixed update or a manual physics simulation. This always happens. So, you can change hundreds of Transforms hundreds of times and no components get updated, so if this was a pattern in your project before, you get that back and only the Transforms that have changed get processed, just once, no matter how many times they were changed.

    Now to ensure support for previous behviour we need to perform a SyncTransform prior to any physics query to ensure that the query is using the latest changes to physics. Whilst this guarantees previous behaviour, it has a small cost associated with performing it, even when no transforms have changed. This is the AutoSyncTransforms option in 2D and 3D physics. With this off, the only update is prior to the simulation being run but means physics won't be in sync to any changes you've made until the next update. You are free to manually SyncTransforms which is the call that is made when AutoSyncTransforms is on.

    When we perform a SyncTransform, we do most of the work off the main-thread so in sum-total, the actual update should be faster as previously everything was on the main thread however, performing an AutoSyncTransform prior to any query is work we didn't do before. Even when no Transforms have changed, there's a slight cost which is a pain however the team dealing with Transform dispatch (as it's known internally) are improving this.

    Therefore, the best performance is when AutoSyncTransforms is off i.e. it's only sync'd prior to updating the simulation. Only call SyncTransforms if absolutely essential and avoid calling it if not needed.

    This is the solution we were forced to implement due to the Transform change notification being removed in the Transform system. I hope it provides some useful background on what changed.
     
    Last edited: Aug 21, 2017
    WhiteGfx, Fesener, eddyb and 4 others like this.
  10. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    5,603
    It does, thanks for the explanation!

    It's a difference of 50ms according to my tests.
    2017.1 requires about 4ms to complete one frame, 2017.2 requires 54ms. According to several other tests I did, it seems every project runs slower in 2017.2 and it seemed to me, according to the Unity project, that the cause are the physics system related changes.

    I can't afford a 10x performance degradation in my project, which is the case if I just open it in 2017.2.
    However, if it's as easy as turning off autoSyncTransforms to restore the performance of 2017.1 or make it even run faster, perhaps that should be the default setting then?
     
  11. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    3,679
    That'll break existing projects that expect the physics to be updated each time a Transform is changed. In the future, new projects will have this off by default.

    The performance is in the hands of the Transform system. The actual performing physics sync is much faster, the checking to see if any Transforms have changed is the overhead. This is the part which is out of the physics teams hands and should improve considerably, especially in the case of no Transforms changed.
     
  12. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    26,909
    Really appreciate the wealth and depth of information.
     
    MelvMay likes this.
  13. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    861
    I do wonder if there would be any performance benefit to allowing a mode where you can make particular rigidbodies never update from a transform automatically before simulation, for projects where the developer can guarantee that this will not happen.
     
  14. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    3,679
    Note that the Rigidbody(2D) won't get updated if the Transform hasn't changed. Only those Transforms that have changed update Rigidbody(2D) and Collider(2D).
     
  15. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,599
    Just dropping in to confirm that even with autoSync off and doing absolutely no manual Syncs, the FixedUpdate.ScriptRunBehaviourFixedUpdate entry in the profiler is about 2x slower than in 2017.1 for a script that does a bunch of Raycasts, CapsuleCasts and Rigidbody.MovePosition/Rotation

    (for 3D physics, in 2017.2b8)
     
    Peter77 likes this.
  16. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    3,679
    I'll speak to Anthony Y (3D physics) because that doesn't make sense. Those calls haven't changed and if AutoSync is off, then the sync before the query executes isn't run so they should be identical performance.

    Are you sure it's related to the actual queries you're performing?
     
    Last edited: Aug 22, 2017
  17. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,599
    I'll admit that I tested this with a pretty huge character controller script that does a whole bunch of stuff. I'll make a better test later today and upload it here
     
  18. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    3,679
    Thanks. I mentioned it to Anthony. I'll mention you're uploading an example.
     
  19. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,599
    Okay, my bad. I was wrong

    The test I've made shows no performance difference at all. It includes:
    • raycasts
    • capsuleCasts
    • OverlapSpheres
    • computePenetrations
    • direct rigidbody moves
    • interpolated kinematic rigidbody moves (MovePosition, MoveRotation).
    Actually 2017.2 even seems to perform slightly better for the PhysicsFixedUpdate task.

    However, I still see a performance difference for my character controller script. I'll have to keep searching for the culprit. With all those physics queries I just cleared of suspicion, it may not be physics-related at all

    I've attached the test project anyway for those who might be interested. Just open the testScene, press play, and look at the profiler.

    PS: This is to be expected, but the performance difference in 2017.2 between having AutoSync on/off is absolutely immense. 11ms versus 650ms per FixedUpdate in my case. People will really have to be well educated on this feature, otherwise they may start wondering why their 60fps game suddenly runs at 1fps. At this point, I'm wondering if activating AutoSync should be an option at all... maybe just forcing people to understand syncing and having it constantly off would be a better option? I understand that the notion of rigidbody syncing might not be understood by a large part of the community, but the performance cost is just waaaaay too huge for this to be a viable thing to do
     

    Attached Files:

    Last edited: Aug 23, 2017
    hippocoder likes this.
  20. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    981
    I dont understand why there is such a big performance regression since the engine has always been running in 'AutoSync on' mode?
     
  21. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    3,679
    No, we never did anything like that. As I described above, we never previously had to auto-sync before any query or anything that expected physics to be synchronized with the Transform components because everything was already up-to-date because when a Transform changed, we updated the respective body/collider on that Transform immediately.

    AutoSync, more specifically, SyncTransforms asks the transform system which Transforms have changed and we then update all the body/collider appropriately. We never did that before each query. Even if no Transforms have changed, this has a small overhead.

    Turning off AutoSync means it should be the same but hopefully faster than before being as physics is being updated in a batch once only prior to the simulation being run.
     
  22. pvloon

    pvloon

    Joined:
    Oct 5, 2011
    Posts:
    591
    I'm very excited about the performance gain of this new system with auto sync off and that part really sounds great!

    I am concerned however that the has been no response to the claims of the _huge_ performance regressions in autoSync=on legacy mode. I will run some tests myself too to check but if the numbers are like what's mentioned here, it could be a huge deal. A performance regression of 60x like in PhilSA's case just isn't actually backwards compatible - perf behaviour is part of expected behaviour too.
     
  23. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    5,603
    If I read between lines from MelvMay's reply, it seems this issue is kind of bouncing between teams. The Physics team says it's faster (in the Physics system) and the bottle-neck is now in the Transform system.

    I wonder if someone actually feels responsible to simply fix that it does not run slower in total, no matter what sub-system is causes it now.

    I've attached my test project to this post too. It's the project I've attached to Case 940805.

    profiler_2017_1.png

    profiler_2017_2.png

    I think from a customer point of view, it doesn't really matter what sub-system is slower. All I see is that it's 10x slower in total, which is actually a "breaking problem" I'd say.
     

    Attached Files:

    Last edited: Aug 23, 2017
  24. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    3,679
    Of course they do. Nobody said we're arguing over who's fault it is, just that I provided the information on what team is looking at it and where the improvements need to be made. This is why it's not always good to provide too much information because people start inventing two things for every one thing said. ;)

    Do you have a regression with auto-sync off?
     
  25. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,599
    I've tested Peter77's project with autosync off, and it really seems to me like the performances are identical. Sometimes you see some disparity but that may just be because you've accidentally landed on two profiler samples that are off the average due to some error margin. Actually I'm starting to think this may be the case with the difference I'm seeing for my characterController script. With the test I made yesterday and this one, I think it's safe to say that there are no problems with AutoSync off. The only real problem is AutoSync on.

    There is no doubt in my mind that the changes made to physics were a great thing. The C# jobs system looks phenomenal and it's absolutely worth making this small sacrifice for it. Actually it's not even really a sacrifice, because the performances are actually a tiny bit better now with autosync off. (Please please please do not let this AutoSync issue slow down the integration of the jobs system! )

    I honestly think the best way out of this is to not give any AutoSync option at all. The cost is just too high, people won't understand why their game runs so slow, and the work required/potential pitfalls of having it turned off are really not that serious. Unless I'm mistaken, the absolute worst case scenario is if someone tries to move a rigidbody with transform.position and then tries to raycast it at its updated position in the same frame. I really don't think this sort of thing will happen often; or at least not for the beginner users for whom the autosync option was made. In that situation, I think people generally would have the reflex to debug transform/rigidbody positions and notice that the rigidbody is only updated at the next frame. I'm sure we can afford this, from a user-experience/accessibility point of view

    Besides, if there's only one way of doing things, I think it'll be much easier to educate people about it
     
    Last edited: Aug 23, 2017
  26. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    3,679
    Unfortunately there are those that will need this and besides, when the Transform guys sort the current know issues out then this issue should pretty much go away. If turning it off works for you then you're good. We're already talking about breaking backwards compatibilty in a near future release cycle and having AutoSync off by default.

    Unity is comprised of many teams; this has no bearing on other product offerings so we're good. We're all waiting for the C# job system, even internally!
     
    Peter77 and PhilSA like this.
  27. PhilSA

    PhilSA

    Joined:
    Jul 11, 2013
    Posts:
    1,599
    That sounds like music to my ears. If you end up deciding that you should use that opportunity to fix most/all problems in Unity that are simply due to wanting to keep backwards compatibility, I'd definitely have a list of things that have to go away!

    For instance....
    • all the .materials, .vertices, .etc.... that return copies of arrays
    • all the .transform, .rigidbody that do a secret GetComponent
    • Camera.main that does a secret Find()
    • all the RaycastAll, SphereCastAll, OverlapSphere that do GC allocs
    • ...and especially this atrocity, since we have no alternative https://blogs.unity3d.com/2014/05/16/custom-operator-should-we-keep-it/
    Most of the things I mentioned may seem like it's no big deal since we're not forced to use them, but when working in teams with less experienced programmers, it would make all the difference in the world if all of those bad things were just not available at all
     
    Last edited: Aug 23, 2017
    Peter77 likes this.
  28. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    26,909
    Nah, it's always best to provide info. The community and developers can simply correct it. If there is not too much info, then there is even more guesswork, I know this from moderating this place over the years :p
     
    Peter77 likes this.
unityunity