Search Unity

gooey gumdrops pyramid performance

Discussion in 'Scripting' started by Jessy, Dec 24, 2007.

  1. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    So, I was watching Joachim's Unite optimization video last night, and today, I decided to procedurally create a pyramid of gumdrops to hone my skills. He said that dynamic typing was not a great thing to do, so I would like to know if all the type defining I am doing here is a good thing. Also, I can't figure out a way to create this shape without division, and although he said division is also not optimal, it doesn't seem to me that division by 2 of even integers should be that taxing. However, I don't really have a clue about such things, so please inform me!

    Also, I am sure that people have come up with better ways to create this shape, but I couldn't find anything with a quick googling, so I used the code from the bottom of the following page and ran with it. Thanks for your suggestions!

    http://unity3d.com/support/documentation/Manual/Instantiating Prefabs.html

    Code (csharp):
    1. var element : GameObject;
    2. var gridHeight : int;
    3. var spacing : float;
    4.  
    5. function Start () {
    6.     var greatestDim : int = (2 * gridHeight - 1);
    7.     for (var levelDim : int = 1; levelDim <= greatestDim; levelDim += 2) {
    8.         for (var xNum : int = 0; xNum < levelDim; xNum++) {
    9.             for (var zNum : int = 0; zNum < levelDim; zNum++) {
    10.                 var x : float = (xNum - (levelDim - 1)/2 ) * spacing;
    11.                 var z : float = (zNum - (levelDim - 1)/2 ) * spacing;
    12.                 var y : float = -(levelDim - 1)/2 * spacing;
    13.                 var placement : Vector3 = Vector3(x, y, z);
    14.                 //create the element and place it relative to the parent
    15.                 var thisElement : GameObject = Instantiate(element);
    16.                 thisElement.transform.parent = transform;
    17.                 thisElement.transform.localPosition = placement;
    18.             }
    19.         }
    20.     }
    21. }
     

    Attached Files:

  2. Morgan

    Morgan

    Joined:
    May 21, 2006
    Posts:
    1,223
    Cool--the interaction between the Jolly Ranchers and the gumdrops is quite true to life.
     
  3. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It never hurts to define types, but it's not usually even necessary, since Unity's Javascript will do it for you. That's called type inference, which is not the same thing as dynamic typing. Put this on the top of your scripts:

    Code (csharp):
    1. #pragma strict
    Then you will never have to worry about dynamic typing. A variable is only dynamically typed if Unity can't figure it out at compile time, but usually it can. Of course, sometimes you want to specifically define types rather than letting Unity do it, like if you want to force a variable to be an integer, even if you're doing math that would normally result in a float.

    I guess that depends on how the compiler works...division by two can be accomplished merely by right-shifting the bits of a number (even for odd numbers, as long as you don't mind the remainder getting dropped), which would be about as fast an operation as you can do. So dividing integers by two might be really fast, depending on what optimizations are done. Or it might not. Only the Unity guys know for sure....

    --Eric
     
  4. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    I always try to replace divisions with multiplications since they're much faster, and only use bit shifting where the speed is really needed.
     
  5. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Right, I meant to mention that...instead of doing "blah/2", you could do "blah*.5". In case anyone's wondering about how to do bitshifting, it's simple:

    Code (csharp):
    1. var foo = 64;
    2. foo >>= 1; // Same as "foo = foo >> 1;"
    3. print (foo); // Prints "32"
    4. foo >>= 2;
    5. print (foo); // Prints "8"
    6. foo <<= 3;
    7. print (foo); // Prints "64"
    Unity doesn't seem to support >>> though.

    Edit: I should mention, doing "*.5" instead of "/2" is only faster (by about 20%) if you're doing that to a float. If you have an int, "/2" is MUCH faster (nearly 3X faster) than "*.5", which makes sense as there must be some int->float conversion going on there. Faster yet (as expected, by 15%) is ">>1", though of course you can't do that to floats, only ints. That's tested on a G5; not sure about Core Duos etc.

    So to answer your question, Jessy, it looks like the best thing to do in this case is to leave the "/2" as is. The results are getting put into floats, but the actual division is being done on integers. I did another test using your code, and ">>1" was actually a teensy bit slower here (consistently), for some reason. You can also leave out all the type definitions if you wanted to (not that it would affect the speed in any way), except for the "var thisElement : GameObject = Instantiate(element);" line, where it's needed to avoid dynamic typing.

    --Eric
     
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    The optimizations related to optimizing floating point math or math operations, is in this case completely point less though.

    Code (csharp):
    1.  
    2.                var thisElement : GameObject = Instantiate(element);
    3.                thisElement.transform.parent = transform;
    4.                thisElement.transform.localPosition = placement;
    5.  
    These three lines of code will completely thwart any math operations you will do above. Optimizing code on a low level is really the last step, which you only do in inner loops once you know that you are really running this code a lot and it's what makes the game slow down.
     
  7. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,325
    I still need to look at what each of you said (thanks for replying), but I just uploaded a new version. It's utter chaos, but I love it!

    Later: Ok, I got a chance to look it all over. Is there any better way to do what I am doing with those last three lines?
     
  8. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Yep...the main issue, I believe, is the use of three GetComponent calls, which slows things down. I'd rewrite it like this:

    Code (csharp):
    1. var element : Transform;  // Not GameObject
    2. var gridHeight : int;
    3. var spacing : float;
    4.  
    5. function Start () {
    6.    var myTransform = transform; // Cache GetComponent(Transform) call
    7.    var greatestDim : int = (2 * gridHeight - 1);
    8.    for (var levelDim : int = 1; levelDim <= greatestDim; levelDim += 2) {
    9.        for (var xNum : int = 0; xNum < levelDim; xNum++) {
    10.           for (var zNum : int = 0; zNum < levelDim; zNum++) {
    11.              var x : float = (xNum - (levelDim - 1)/2 ) * spacing;
    12.              var z : float = (zNum - (levelDim - 1)/2 ) * spacing;
    13.              var y : float = -(levelDim - 1)/2 * spacing;
    14.                var placement : Vector3 = Vector3(x, y, z);
    15.                //create the element and place it relative to the parent
    16.                var thisElement : Transform = Instantiate(element);
    17.                thisElement.parent = myTransform;
    18.                thisElement.localPosition = placement;
    19.           }
    20.        }
    21.    }
    22. }
     
  9. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    rather than /2 you could just * 0.5
     
  10. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Not in this case. As mentioned above, that only applies to floats...with ints, it's much faster to use /2 compared to *0.5.

    --Eric
     
  11. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    Hmm... isnt this floats?

    var x : float = (xNum - (levelDim - 1)/2 ) * spacing;

    wouldn't

    var x : float = (xNum - (levelDim - 1)*0.5 ) * spacing;

    be quicker here?
     
  12. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Nope, because the salient point is "(levelDim - 1)/2", which is ints. I ran some tests, and using *0.5 here slowed it down a lot (relatively speaking).

    --Eric
     
  13. bronxbomber92

    bronxbomber92

    Joined:
    Nov 11, 2006
    Posts:
    888
    Nope, since xNum and levelDim are integers, you're doing integer math, and once the equal opcode is executed the resultant of the integer math is converted to a floating point number. If you were to multiply by 0.5 then the conversion would happen before the equal opcode is executed.

    You might be thinking, why does it matter then, since in both cases the conversion to float is occurring. Well, it's because floating point arithmetic is slower than integer. So, do as much math with integers as possible :)

    Of course, I highly doubt doing one or the other would affect performance in this case.

    Edit - Damn, Eric beat me to it... ;)
     
  14. seon

    seon

    Joined:
    Jan 10, 2007
    Posts:
    1,441
    wow, ok, cool... love learning stuff from you guys!
     
  15. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Pretty much...you need to loop a rather massive number of times before the difference becomes easily measurable. In real-world situations, it's unlikely to be an issue. Interesting from an academic standpoint though....

    --Eric