- Home /
Not a question - just some performance metrics for rendering from Unity scripts
I need to dynamically instantiate and alter GameObjects from scripts and wanted to share what I found about the performance of these scripts. I've included the C# source code at the bottom.
Testing protocol: I am running Unity 4.0.1f2. The script below was attached to the Main Camera object, and references a simple prefab Cube called myCube. For the tests below, I took the best of 3 times to try and minimize reflection of any temporary bottlenecks or CPU overload created by other programs running on my machine (Lenovo G560 running 64-bit Windows 7, 2.13GHz, 4.0GB RAM). Test result is the average seconds per render over 1000 renders.
1000 cubes, static: 0.01022 seconds per render
1000 cubes, floating away along the z-axis (1), using new Vector3: 0.01316 s/render
1000 cubes, floating away along the z-axis (1), using static Vector3.forward: 0.01362 s/render
At this point, I was surprised that multiplying a static vector by the time elapsed generated worse results than instantiating new vectors for each cube on each render, but the order of magnitude of the difference here was lower to a point that I just decided to continue using new Vector3 instantiation for each test below and assume results would be comparable with the static Vector3.
1000 cubes, stretching along one axis (2): 0.01691 s/render
Benchmarking the cost of generating Random values: 1000 cubes, on each render generating a Random.range value for each cube (but doing nothing with it): .01042 s/render
After this, I did not include any further metrics to assess cost of the Random float generator, since the order or magnitude of the difference is again much smaller, and probably comparable in order of magnitude to the variance caused by my admittedly rudimentary testing method.
1000 cubes, enabling/disabling each on each render according to a random value (3): .01928 s/render
1000 cubes, floating away along the z-axis (1) while also stretching along one axis (2): 0.01809 s/render
1000 cubes, floating away along the z-axis (1) while also enabling/disabling randomly (3): 0.02261 s/render
1000 cubes, stretching along one axis (2) while also enabling/disabling randomly (3): 0.03292 s/render
1000 cubes, floating away along the z-axis (1), stretching along one axis (2), and enabling/disabling randomly (3): 0.03404 s/render
Hope this helps!
Source code:
using UnityEngine;
using System.Collections;
public class makeCube : MonoBehaviour {
public static int num_shapes=1000;
public GameObject myCube;
float lastRenderTime;
Vector3[] v3array;
GameObject[] oarray;
int renders;
float totalRenderingTime;
void Start () {
renders=0;
totalRenderingTime=0.0F;
lastRenderTime = Time.time;
v3array = new Vector3[num_shapes];
oarray = new GameObject[v3array.Length];
for (int i=0; i<v3array.Length; i++)
{
v3array[i] = new Vector3(((float)i)/400.0F,((float)i)/250.0F,((float)i)/500.0F);
}
Quaternion q = Quaternion.identity;
for(int i=0; i<v3array.Length; i++)
{
oarray[i] = (GameObject)Instantiate(myCube, v3array[i], q);
}
}
void Update () {
renders++;
totalRenderingTime+=(Time.time-lastRenderTime);
if (renders%100==0)
print (renders + " renders in " + totalRenderingTime + " seconds");
float enableRandom=0;
for(int i=0; i<v3array.Length; i++)
{
// TRANSFORM 1: Floating away along the z-axis
//oarray[i].transform.position += Vector3.forward * (Time.time-lastRenderTime);
//oarray[i].transform.position += new Vector3(0.0F,0.0F,(Time.time-lastRenderTime));
//TRANSFORM 2: Stretching along one axis
//oarray[i].transform.localScale += new Vector3((Time.time-lastRenderTime),0.0F,0.0F);
//TRANSFORM 3: Enabling/disabling randomly
/*enableRandom = Random.Range(-1.0F, 1.0F);
if (enableRandom > 0)
{
oarray[i].SetActive(true);
}
else
{
oarray[i].SetActive(false);
}*/
}
lastRenderTime = Time.time;
}
}
This'd be good to post in the forums: questions here get pushed through the list pretty quickly, and I can see this being worth some conversation.
Questions that start with "Not a question" are quite obviously wrong here. This is a Q&A site. We have a forum and a wiki beside the Q&A site, so why did you post it as question? I don't get it...
Also this kind of benchmark usually doesn't "prove" anything. It should be done several times under same conditions and repeated on different hardware. Also it's not clear if all objects are visible all the time or if some got frustum culled. Also is is any kind of batching happening?
Next thing is print (or Debug.Log which is called by print) has a horrible performance in the editor. So calling it during a benchmark totally destroys the result, even when only called every 100 frames.
Vector3.forward is not a constant value. It's just a static property that is implemented like this:
// extracted from UnityEngine.dll
public static Vector3 forward
{
get { return new Vector3(0f, 0f, 1f); }
}
Time.time is not realtime. It is the time the current frame has started you calculate Time.deltaTime manually but it will result in the same value. For benchmark time measurement you should use a reliable realtime counter. If you don't need a very high precision you can use Time.realtimeSinceStartup, otherwise the .NET / $$anonymous$$ono framework has some classes that might help (Stopwatch, on windows there's also QueryPerformanceCounter)
re Itinerant: Thanks - was not aware Unity had forums, I will move this post there. It will be listed under the same title except with "Not a question" removed.
re Bunny: as mentioned above, I will be moving this to forums. Please feel free to comment there and I'll be happy to respond, but I wanted to make two observations before you do: first, the purpose here was to measure relative performance, so print() won't be messing up the benchmark as it happens on every iteration. It's like if we tried to measure whether you run slower with a 50-pound sack on your back: we wouldn't have to replace your legs with rocket skates before the experiment. second, when my company makes the results of our internal research available for free to the developer community, you can feel free to not use it if you don't find it useful. I've also made the source code available, for the exact reason that you may run a different test more suited to your own objectives if you'd like.