Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice
  2. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  3. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Extremely poor Transform.SetParent performance

Discussion in '5.4 Beta' started by SLGEric, May 25, 2016.

  1. SLGEric

    SLGEric

    Joined:
    Aug 4, 2014
    Posts:
    7
    We commonly instantiate up to 100 or so objects, set their transform localPosition, and then reparent them to a container object (with worldPositionStays = false). Prior to unity 5.4, this has never shown up on the profiler as an issue, but in 5.4 it is commonly taking up to ~1ms per call, resulting in huge 100+ms spikes.

    is this a known issue at all?

    GameObject newObj = (GameObject)GameObject.Instantiate(prefab, position, Quaternion.Euler(0, degrees, 0));
    newObj.transform.localPosition = position;
    newObj.transform.localScale = new Vector3(1, scale, 1);
    newObj.transform.SetParent(parent, false);

     

    Attached Files:

    Harinezumi likes this.
  2. SLGEric

    SLGEric

    Joined:
    Aug 4, 2014
    Posts:
    7
    this seems to mostly be caused by the non-uniform localScale. If I don't set the scale of the instantiated objects, I no longer see huge spikes.

    But again this same code is not a performance issue in unity 5.3.5
     
  3. Alex-Lian

    Alex-Lian

    Guest

    We have some perf improvements for the SetParent function in flight. Not b20 for sure, but sometime after.
     
  4. JJJohan

    JJJohan

    Joined:
    Mar 18, 2016
    Posts:
    214
    Hi @Alex Lian, would you be so kind as to let us know if this has been scheduled for a particular beta release yet? I use a hierarchy-based node system and find the SetParent performance issues are making the software difficult to operate compared to a 5.3 version.
     
  5. Sebioff

    Sebioff

    Joined:
    Dec 22, 2013
    Posts:
    218
    The changelog says SetParent performance was improved in b21 and we should give feedback :)
    In our project, loading levels takes roughly twice as long in 5.4b21 than it did in 5.3.5 (30s -> 60s), and according to the Profiler all of that extra time is spent in SetParent. During normal gameplay we get lots of lag spikes with SetParent taking about 15ms per call. Only on some calls though:


    I don't have numbers to compare how much it improved since b20, but at least compared to 5.3 it's extremely slow.
     
    Last edited: Jun 10, 2016
  6. Alex-Lian

    Alex-Lian

    Guest

    @Sebioff , testing and reply extremely appreciated. It's one of our primary worries at this point and is getting further focused attention.

    Thanks again.
     
  7. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    @Sebioff: Can you upload the project folder or a stripped down project that shows a performance regression against 5.3.
     
  8. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Please note that beta 21 had some big speedups in regards to SetParent & Destroy in sub hierarchies.

    Generally 5.4 SetParent performance is now better than 5.3 SetParent performance in the most common cases. But there are ways to get worse performance. So lets detail how the code is different.

    Unity now allocates a big block of memory that is as big as the entire hierarchy, containing transform rotation / scale / position / parent indices etc.

    For best performance:
    * Append or destroy from the end of a hierarchy (depth first). It is always the fastest operation. When building large hierarchies, always append to the end. (The profiler shows you when you are not taking the fastest path.)
    * SetParent internally creates a big array of all transform nodes. We now automatically resize to 2x size when capacity runs out of space. You can set the hierarchyCapacity before if you know how many objects you are going to add into a hierarchy, this can usually give you a 20-30% speed up when building large hierarchies ( > 5000 game objects)

    In the tests we have run where you do correctly set hierarchyCapacity + append at the end of the hierarchy Unity 5.4 SetParent performance is better than 5.3 SetParent performance.

    What to avoid:
    * Dont destroy from beginning of the transform hierarchy. The fastest operation is always to destroy the whole hierarchy at the root game object. If thats not possible, always try to destroy from the end, not the beginning. Otherwise unity has to do a lot of copying to re-pack the data
    * Dont SetParent to transforms at the beginning of the hierarchy. Try to build hierarchies in a way where SetParent is applied to the end or relatively far at the end. (The amount of data copied is dependent on how many transforms from where you parent to to the end of the hierarchy)
     
    Last edited: Jun 11, 2016
    drew55, tinyant, Harinezumi and 2 others like this.
  9. Sebioff

    Sebioff

    Joined:
    Dec 22, 2013
    Posts:
    218
    @Joachim_Ante: I've uploaded the project as case #804765

    Also thanks for the explanation for how it works now. Note that we haven't done any optimizations yet to make the best use out of this new SetParent behaviour so there's certainly room for improvement on our end - the main problem seems to be that we parented everything (~55k objects) to a root object to keep the hierarchy tidy, which was fine in 5.3.
     
  10. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    I looked through your project folder. Some hierarchies are applied in a way that will lead to good performance:

    Code (CSharp):
    1.      
    2.         landChunksParent = new GameObject("LandChunks");
    3.         landChunksParent.transform.parent = transform;
    4.  
    5.         int chunkCountX = Mathf.CeilToInt((float)xSize / LandChunk.chunkSize);
    6.         int chunkCountZ = Mathf.CeilToInt((float)zSize / LandChunk.chunkSize);
    7.         landChunks = new LandChunk[chunkCountX, chunkCountZ];
    8.  
    9.         int chunkSizeX = xSize / chunkCountX;
    10.         int chunkSizeZ = zSize / chunkCountZ;
    11.         for (int x = 0; x < chunkCountX; x++) {
    12.             for (int z = 0; z < chunkCountZ; z++) {
    13.                 LandChunk landChunk = Instantiate<GameObject>(landChunkGO).GetComponent<LandChunk>();
    14.                  landChunk.transform.parent = landChunksParent.transform;
    15.             }
    16.  
    This results in good performance. transform here is a root game object, you are additional transforms to the end of the hierarchy, which is faster in 5.4 than in 5.3.


    In other places you place a game object named "unclassified" first, add some instances to it as children, then add a bunch more game objects to the root, then afterwards go back and add more to the "unclassified" game object. In the mean time you have added many more game objects at the end of the hierarchy. This results in bad performance because Unity now has to copy the transforms that were added to the end.

    You can solve this in two ways:
    1. make the unclassified game objects be root game objects
    2. only apply game objects at the end of the hierarchy. Basically create a game object, parent it, add children, and don't change it once you have parented in locations afterwards.


    In this case you have 50000 game objects and you are calling SetParent 8000 times, so things add up to your load time being roughly 2x slower in total. SetParent time with my changes went from 7000ms to 80ms. Changing your game code took me roughly 5 minutes.


    It was good to check out this project folder, and I will write a blog post with examples of the corner cases you can now run into when doing lots of parenting. But since this is a perfectly solvable problem and the new system gives huge speedups in other places, we see this as working as intended.
     
    Last edited: Jun 11, 2016
  11. Sebioff

    Sebioff

    Joined:
    Dec 22, 2013
    Posts:
    218
    Yep, with the explanations given in this thread it makes perfect sense and, as you said, is trivial to fix.
    Thanks for taking the time to make sure it is working as intended (on a Saturday!).
     
  12. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Do you mind if I use snippets from your project folder in an upcoming blog post about the new Transform component
     
  13. Sebioff

    Sebioff

    Joined:
    Dec 22, 2013
    Posts:
    218
    Nope, got no problem with that
     
  14. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    @Sebioff
    I am very curious if you have been able to adapt your code to work optimally with the new SetParent behaviour and if you were able to get performance to be as good or better than 5.3?
     
    Peter77 likes this.
  15. Sebioff

    Sebioff

    Joined:
    Dec 22, 2013
    Posts:
    218
    @Joachim_Ante
    We haven't done the full switch to 5.4 yet, but yes, at least the immediately apparent issues can be easily fixed by removing any unnecessary parenting and keeping hierarchies as shallow as possible, which seems to result in about equal performance to 5.3. Not sure how easily that can be achieved in practice for other games, but at least for us it shouldn't be a big problem.

    I have to say though that I never noticed a performance issue with SetParent in 5.3 in the first place, so I was curious and tried the following code to get a direct comparison:

    Code (CSharp):
    1. void OnGUI() {
    2.         if (GUILayout.Button("Benchmark")) {
    3.             Profiler.BeginSample("Ordered parenting");
    4.             GameObject root = new GameObject("Root");
    5.             for (int i = 0; i < 20000; i++) {
    6.                 new GameObject("Child").transform.parent = root.transform;
    7.             }
    8.             Profiler.EndSample();
    9.  
    10.             Profiler.BeginSample("Random order parenting");
    11.             for (int i = 0; i < 20000; i++) {
    12.                 new GameObject("Child").transform.parent = root.transform.GetChild(Random.Range(0, root.transform.childCount - 1));
    13.             }
    14.             Profiler.EndSample();
    15.  
    16.             #if UNITY_5_4
    17.             Profiler.BeginSample("Ordered parenting + capacity");
    18.             root = new GameObject("Root");
    19.             root.transform.hierarchyCapacity = 20000;
    20.             for (int i = 0; i < 20000; i++) {
    21.                 new GameObject("Child").transform.parent = root.transform;
    22.             }
    23.             Profiler.EndSample();
    24.             #endif
    25.         }
    26.     }
    On a standalone build running on a 2014 Mac Mini I get the following results:
    5.3.5p2:
    5.3.5p2.png

    5.4.0b21:
    5.4.0b21.png

    So unless I made a mistake in my test or there are some other benefits to the hierarchy change the 5.3 behaviour is better (no huge penalty for not appending to the hierarchy end + even slightly faster overall).

    (Slightly off-topic, but apart from that 5.4 is performing much better for our game :) Especially rendering time improved a lot, probably mostly due to instancing)
     
    Last edited: Jun 15, 2016
    landon912, Lyje and Peter77 like this.
  16. mdrotar

    mdrotar

    Joined:
    Aug 26, 2013
    Posts:
    377
    @Joachim_Ante Which is really hard to do for UI since UI visuals are dependent on hierarchy ordering and structure.
     
    laurentlavigne, Lyje and ortin like this.
  17. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    169
    I'd like to add my voice to this - I, too, have never noticed any performance issues with SetParent until 5.4, when I've suddenly got multi-millisecond spikes for operations which were previously insignificant (many of which are in UI, as @mdrotar mentions).

    I'd much rather have SetParent perform pretty well in all cases, rather than amazingly in one specific instance and poorly otherwise. I worry that this might be a lab-conditions optimisation that causes huge problems in real-life projects.
     
  18. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,589
    Would it be an option for you to submit your project, or a stripped down version, that illustrates the issue and post the case # here? This would allow Joachim to take a look at this use-case and hopefully come up with a fix.
     
  19. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    We have taken another pass at optimizing Transform.SetParent and now it is faster in 5.4 than in 5.3 in all SetParent conditions. Should be in b23.
     
  20. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    169
    Great, thanks Joachim! Looking forward to trying b23.
     
  21. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    In the interest of making sure that this time we really covered all corner cases before shipping the next build.

    Please try this non-offical temporary build and see if it makes all SetParent cases faster than in 5.3.
    (Has not gone through any QA and has all the latest SetParent optimizations)

    http://beta.unity3d.com/download/eb36fa61241b/download.html
     
    JJJohan and Paulo_Mattos like this.
  22. Sebioff

    Sebioff

    Joined:
    Dec 22, 2013
    Posts:
    218
    5.4.0b23:
    Bildschirmfoto+2016-06-21+um+13.04.20.png
    Better than b21 :) Looks like .hierarchyCapacity isn't needed anymore?
     
    Last edited: Jun 21, 2016
  23. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    169
    Certainly seems like a solid improvement. I don't have a proper test case like Sebioff, but from eyeballing the profiler it looks like my worst case has gone from 2-3ms in b22 down to <0.1ms in b23.
     
  24. DudoTheStampede

    DudoTheStampede

    Joined:
    Mar 16, 2015
    Posts:
    81
    Hi Guys!

    You're talking about SetParent and profiling so I hope I'm not in the wrong place (if I should open a new thread I'll do it and I already say sorry!).
    I've noticed the same problem with the parenting in Unity 5.4b21 and along with that a strange warning started appearing on the profiler!
    Schermata 2016-06-22 alle 15.34.04.png

    I'm using that for UI elements, my code is:
    Code (CSharp):
    1. buttonTransf.SetParent( parent, false);
    2. buttonTransf.SetAsFirstSibling();
    I'm using "SetAsFirstSibling" because those are buttons placed one on top of another and I need them to be clicked in order of appearing.

    I do that a lot of time (in different frames) and I don't know how much that warning can lead to performance issues (I'm targeting for mobile).
     
  25. mark_gr

    mark_gr

    Joined:
    Jan 16, 2015
    Posts:
    25
    Not sure if related but since the changes to SetParent, we have had a bug.
    We have a few objects that we move between trees with SetParent, some of these tress have different canvas's for different sorting purposes.

    When they are moved to trees with a different canvas everything that is under that canvas goes invisible(not just the objects that are moved), and there is no way to bring it back.
    All objects are enabled and active, there is no visible parameter changes.

    This all worked perfectly fine on 5.3.5p1 but from p3 and on is not working.
    Any kind of help would be appreciated.
     
  26. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    That doesn't sound related to Transform.SetParent changes, however please do file a bug report with a repro project for that so we can fix the issue.
     
  27. z000z

    z000z

    Joined:
    Dec 31, 2014
    Posts:
    96
    @mark_gr do you see this same behavior in b23? I saw something similar but mine turned out to be some limitation of scaling limits on world canvases, whenever the scale would go below about 1e-05 on x/y things would just disappear. I just checked this in b23 and it looks like they fixed whatever was going on there, tried all the way down to 1e-28 and things worked fine.
     
  28. smenyhart

    smenyhart

    Joined:
    May 6, 2016
    Posts:
    45
    I'm using Unity Version 5.4.0b22-HTP. I have built some Tree structure UI using Unity UI panels, images and buttons. Because it's a Tree structure viewer, the UI GameObject heirarchy can get deep, depending on the tree being visualized. If I try to build this UI for a deeply nested tree where it gets over 8 levels deep, calling Transform.SetParent(parent, false) can literally take multiple MINUTES, and eventually just crashes. Even around 6 or 7 deep it can take a noticeable amount of seconds for SetParent to return. I append child UI GameObjects to the end of the hierarchy as they are instantiated from a prefab. Is there any way to work around this problem? Is it a bug that will eventually be fixed? Or is it that nested hierarchy deeper than 7 or 8 just will never be supported and I should completely re-architect my UI?
     
  29. Sebioff

    Sebioff

    Joined:
    Dec 22, 2013
    Posts:
    218
    @smenyhart Try beta 23 that was released yesterday, it probably fixes that.
     
  30. smenyhart

    smenyhart

    Joined:
    May 6, 2016
    Posts:
    45
    I'll try out beta 23 as soon as they release an HTP version of it.
     
  31. mark_gr

    mark_gr

    Joined:
    Jan 16, 2015
    Posts:
    25
    We are on p5 and it is still not working. However we were able to build around it and getting rid of some canvas`s so it doesint occur.
    The canvas's themselves dont scale at all but the objects inside them did but the lowest they go is probably 0.3 or so.
     
  32. smenyhart

    smenyhart

    Joined:
    May 6, 2016
    Posts:
    45
    I just tried out 5.4.24-HTP and while the performance is better in the sense that the Tree UI now actually loads in about 2 to 3 minutes instead of never, that's still unacceptably slow. I'm also seeing massive frame lag in some instances where some nodes in the tree view are hidden (UI game object disabled).
     
  33. smenyhart

    smenyhart

    Joined:
    May 6, 2016
    Posts:
    45
    Ok so I've worked around both of my problems.

    Loading the Tree UI is much faster if I load just a single node per Update call (Instead of loading everything in one operation). Doing it this way loads the tree in a few seconds instead of minutes. I do not know why doing a lot of deep parenting in a single operation is so slow.

    The second problem of frame lag after the Tree UI is loaded I solved by loading the tree in its fully expanded configuration, where all nodes are visible (all UI game objects are enabled). For some reason having a hidden (disabled) node that has a deep hierarchy of child nodes causes massive frame lag until the entire hierarchy is shown. Once it's shown once, it can be hidden again without causing lag. I think it has something to do again with doing a lot of deep parenting calls on a disabled game object.

    I think both both of these problems should probably be investigated as bugs.
     
  34. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    10,645
    Can you report them?
     
  35. smenyhart

    smenyhart

    Joined:
    May 6, 2016
    Posts:
    45
    I've reported the issues along with a sample project demonstrating them. The bug report title is "Extremely slow performance of SetParent on deeply nested UI panels"
     
  36. laurentlavigne

    laurentlavigne

    Joined:
    Aug 16, 2012
    Posts:
    6,223
    "War is Peace, Freedom is Slavery, Ignorance is Strength"

    or, the unity version...

     
    Last edited: Jul 16, 2016
  37. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    Seems like this will cause some big issues with UI since UI rendering order is sensitive to hierarchy order, and so we can't just change the way we parent objects to one another without breaking the rendering order of our UI elements. I don't have a project to test with on hand but I imagine we are going to be seeing lots of profiler warnings in our UI scripts since objects get parented/unparented/reordered very frequently and often in random places (not just at the ends of the hierarchy) because that is literally how the Unity UI is supposed to work. And UI often has a *lot* of game objects with deep hierarchies. A list of buttons alone could be 4 deep. If I wanted to add a button to the list of buttons, I would have to 'inefficiently' instantiate and parent a new button to the UIVerticalLayout (Inefficient because I am not adding to the end of the hierarchy). Not Imagine a 'real' UI - my list of buttons would probably appear somewhere in the middle of the entire UI hierarchy, and adding new buttons could now cause performance issues?

    UIRoot
    -- UIVerticalLayout
    -- -- Button Sprite
    -- -- -- Button Label
    -- -- Button Sprite
    -- -- -- Button Label
    -- -- Button Sprite
    -- -- -- Button Label


    It might not be a big deal, I don't know. Just voicing concerns.
     
    Last edited: Jul 18, 2016
    ortin likes this.
  38. hoesterey

    hoesterey

    Joined:
    Mar 19, 2010
    Posts:
    659
    Will this change effect objects where you remove pieces from the middle of the hierarchy?

    Use Case:
    -Complex Vehicle with many sub objects.
    -the Vehicle is destroyed, a subset of pieces are un-parented from the middle of the hierarchy.
    -Empty Rigidbody objects are instantiated and the previously un-parented pieces are parented to these new rigidbodies.
    -FX and Forces are added. Boom.
     
  39. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
    @smenyhart I've been looking at your project. Could you tell me which versions this example case worked in? I've tried 5.3.4p1, 5.3.5f1, 5.4f1 and they all seem to have the same issue. (talking about case 814484)
     
  40. smenyhart

    smenyhart

    Joined:
    May 6, 2016
    Posts:
    45
    @phil-Unity I'm completely new to Unity. I started with it for HoloLens development a few months ago so I've never used any previous versions of Unity. It's why I never made the claim that this use case used to work in previous versions. Would this still not be considered a bug even if it never did work in any previous versions?
     
  41. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
    oh yea its totally a bug, its just that internally people started freaking out that this was a regression that was introduced by the changes to SetParent introduced in 5.4. I just wanted to make sure that i didnt miss a working revision such that i could track down any changes.
     
    laurentlavigne and AcidArrow like this.
  42. hoesterey

    hoesterey

    Joined:
    Mar 19, 2010
    Posts:
    659
    From what I've read, I'm not understanding why the Transform changes are beneficial, though I'm sure Unity has reasons, could you explain the benefit?

    I can think of a ton of simple and common cases in a game where I'll want to reorder a hierarchy

    Destruction of vehicles, A character landing on a specific car of a moving train, equipping armor/weapons to a character's hierarchy, parenting a character to the seat of a vehicle. A phone parented to a desk that is parented to a room, where you want to parent the receiver to a characters hand when they touch it.

    I'm a bit concerned that we will need to be rewriting a lot of systems if changing to a hierarchy at runtime are slow. Its something we do all the time to simplify what would otherwise be complicated and expensive physics. Re-ordering the hierarchy seams essential, especially with VR where picking complex objects up (a phone with buttons as children) is a very common practice.

    What are we gaining here?
     
    laurentlavigne likes this.
  43. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    To be clear: Since beta 23 Transform.SetParent has been optimized so much that it is faster in all cases we are aware of than 5.3.

    So reordering of hierarchies is definately still just as much possible as it was in 5.3. That said as a general rule, one thing we found during all of these changes, is that when you do instantiated object pooling, it's a bad idea to constantly re-arent. This is irregardless of 5.3/5.4 changes. There has always been a cost to calling SetParent and if it is unnecessary then don't do it.
     
  44. hoesterey

    hoesterey

    Joined:
    Mar 19, 2010
    Posts:
    659
    Thanks for the clarification. :)
     
  45. 00christian00

    00christian00

    Joined:
    Jul 22, 2012
    Posts:
    1,035
    Hi Joachim, could you please remove the note about this on the upgrade notes then?
    I was also shocked when I read this, not that I need to parent that many, but this sentence make me think I need to worry regardless and recheck all my instantiation code, what could be unacceptable for you on 1000 gameobject tested maybe on desktop, may be unacceptable for me with 50 testing on a low end mobile.
    If it is same or faster than before, this sentence shouldn't stay on the upgrade guide anymore.
     
    Last edited: Jul 23, 2016
    Flavelius, ortin and hoesterey like this.
  46. phil-Unity

    phil-Unity

    Unity UI Lead Developer

    Joined:
    Nov 23, 2012
    Posts:
    1,226
  47. ortin

    ortin

    Joined:
    Jan 13, 2013
    Posts:
    221
    I think it should be backported coz using "zero" rectTransforms as some kind of a container seems logical and I wouldn't want to check all UI to apply workaround.
     
  48. Alex-Lian

    Alex-Lian

    Guest

    We're of course considering it, but fixing what looks like an edge case can have repercussions and we'd like longer time to review, test, etc. Also the longer testing cycle of a full release helps catch any subsequent regressions that might be caused by fixing said bug.