Search Unity

SetActiveRecursively vs Instantiate / Destroy performance

Discussion in 'Scripting' started by raithza, Nov 19, 2012.

  1. raithza

    raithza

    Joined:
    Dec 14, 2011
    Posts:
    21
    I've been tasked with implementing asset pooling in our project, and after my first implementation have found some strange results which I've replicated in a test project.

    I wrote a test script (at the end of this message) which takes a test object as parameter and then either creates/destroys copies of it every frame, or activates/deactivates the copies (using SetActiveRecursively).

    Using a standard cube as my test object, 2000 copies, the profiler shows the following:



    Instantiating/Destroying the objects on the left, activating and deactivating on the right. Creating/destroying the objects take about 115ms on the CPU, Activating/Deactivating take about 315ms.

    Why does activating and deactivating take more time than creating and destroying the same amount of objects? Using a blank object as test case does not impact the results of the test.

    It would be great if someone else could take my script and try to reproduce my findings. If needed I can upload a test project, but it is simple enough using my script below: Create a blank project, add 2 gameobjects to the scene, add the script to one and assign the other object to TestObject, then run and press F7 to create/destroy or F8 to activate/deactivate the copies.

    Bonus question: The purple spikes in GPU usage are all due to RenderTexture.SetActive. What could be causing that in an absolutely blank project?

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class ActiveTest : MonoBehaviour {
    7.  
    8.     bool toggleActive = false;
    9.     bool createDestroy = false;
    10.     public GameObject TestObject;
    11.     public int amount = 2000;
    12.     private List<GameObject>  TestObjects;
    13.    
    14.     void Start()
    15.     {
    16.         TestObjects = new List<GameObject>();
    17.    
    18.         for (int i = 0; i < amount; i++)
    19.             TestObjects.Add (Instantiate(TestObject,TestObject.transform.position + (Vector3.right) * i,Quaternion.identity) as GameObject);
    20.     }
    21.    
    22.     void Update ()
    23.     {
    24.         if (Input.GetKeyDown(KeyCode.F8))
    25.         {
    26.             toggleActive = !toggleActive;
    27.             if (toggleActive)
    28.                 createDestroy = false;
    29.                
    30.                
    31.             if (!createDestroy  TestObjects.Count == 0)
    32.             {
    33.                 for (int i = 0; i < amount; i++)
    34.                     TestObjects.Add (Instantiate(TestObject,TestObject.transform.position + (Vector3.right) * i,Quaternion.identity) as GameObject);
    35.             }
    36.         }
    37.        
    38.        
    39.         if (Input.GetKeyDown(KeyCode.F7))
    40.         {
    41.             createDestroy = !createDestroy;
    42.             if (createDestroy)
    43.                 toggleActive = false;
    44.             else
    45.             {
    46.                 if (TestObjects.Count == 0)
    47.                 {
    48.                     for (int i = 0; i < amount; i++)
    49.                         TestObjects.Add (Instantiate(TestObject,TestObject.transform.position + (Vector3.right) * i,Quaternion.identity) as GameObject);
    50.                 }
    51.             }
    52.         }
    53.         if (toggleActive)
    54.         {
    55.            
    56.             TestObject.SetActiveRecursively(!TestObject.active);
    57.             foreach (var TO in TestObjects)
    58.                 TO.SetActiveRecursively(TestObject.active);
    59.         }
    60.         else if (createDestroy)
    61.         {
    62.             if (TestObjects.Count == 0)
    63.             {
    64.                 for (int i = 0; i < amount; i++)
    65.                     TestObjects.Add (Instantiate(TestObject,TestObject.transform.position + (Vector3.right) * i,Quaternion.identity) as GameObject);
    66.             }
    67.             else
    68.             {
    69.                 foreach (var to in TestObjects.ToArray())
    70.                 {
    71.                     TestObjects.Remove(to);
    72.                     Destroy(to.gameObject);
    73.                 }
    74.             }
    75.         }
    76.     }
    77. }
    78.  
    79.  
     
  2. BrUnO-XaVIeR

    BrUnO-XaVIeR

    Joined:
    Dec 6, 2010
    Posts:
    1,687
    The point of new SetActive system is to call it once for all the 2000 objects, it now affects hierarchy thus its slower than before.
    But you can't call it 2000 times at once and expect it to be fast.
     
  3. raithza

    raithza

    Joined:
    Dec 14, 2011
    Posts:
    21
    I probably should have mentioned that I am on Unity 3.5.6f4



    Using object.active = true/false instead of SetActiveRecursively makes no difference to the performance (which makes sense considering that my test object has no child objects to begin with).

    I'm not expecting it to be fast with 2000 objects, I am just expecting it to be faster than actually instantiating and destroying the objects! Using fewer objects in an active game scene still has an impact on framerate.
     
    Last edited: Nov 19, 2012
  4. Nition

    Nition

    Joined:
    Jul 4, 2012
    Posts:
    781
    In Unity 4, SetActive (which is equivalent to SetActiveRecursively in 3.x) seems to be a bit faster than Instantiate, but it's still pretty slow. I tried to do the same thing (implemenmt an object pool) and came across the same issue. Obviously you could leave all your items active and just hide them away somewhere, but then you'd have 2000 objects (or however many) processing the whole time. I'd like to hear a good solution to this, but suspect there isn't one.
     
  5. raithza

    raithza

    Joined:
    Dec 14, 2011
    Posts:
    21
    I haven't really come across a better solution, but I have found that performance in the editor when it comes to creating/activating is not indicative at all of how performance will be in a build. Also, we were doing a lot of effects manually, that we've now reworked into using standard particle effects which has had a great impact on performance. In any case though, pooling and activating/deactivating is still more efficient than create/destroying.
     
  6. Nition

    Nition

    Joined:
    Jul 4, 2012
    Posts:
    781
    Good to know about performance in build vs editor, thanks. I'd only been testing this in the editor, and I really need to do more testing on the built version.