Code benchmarks Unity3D

B

Buenas, voy a ir añadiendo un listado de resultados comparativos.

Inicialmente emplearé esta plantilla que podéis descargar Main.cs.

  • Crear una escena vacía en Unity.
  • Crear un GameObject vacío al que le agregáis el Main.cs y darle a play.

Lo que hace este primer test, es ejecutar 200k repeticiones de dos bucles. Uno donde se modifica la posición del gameobject accediendo al transform vía GetComponent vs otro que lo hace desde una variable cacheando el transform.

Cada 20 ciclos completos de los dos bucles de 200k repeticiones (lo que son 4 millones de ajustes de posición al gameobject) calcula el promedio de tiempo de proceso y lo muestra en pantalla mediante barras de porcentaje.

La plantilla en este primer ejemplo solo hace dos test, GetComponent vs Variable, pero está diseñada para ser reutilizable y mostrar tantas barras y porcentajes como se carguen en la variable pruebas del script.

El resultado desde la build compilada puede variar respecto al resultado mostrado en ejecución desde del editor.

También depende de la plataforma de salida.

El resultado desde el editor es este:

	case 0:
		for (int i = 0; i < iteracciones; i++) {
			GetComponent <Transform> ().position = Vector3.zero;
		}
		break;

	case 1:
		for (int i = 0; i < iteracciones; i++) {
			variable.position = Vector3.zero;
		}
		break;
  • Usar GetComponent para acceder al component es aproximadamente un 30% más lento que acceder al component usando una variable que contenga su referencia.

  • Esto en funciones tipo Update y bucles puede tener un efecto significativo.

Iré agregando más mini test comparativos.

5
Jastro

Grande!

Gracias por compartir la info, todo este tipo de datos son MUY interesantes!!! mil gracias

1
X-Crim

Muy bueno

1
SnakyBeaky

Menudo spaghetti. La intención es buena, pero ya que vas a postear código a modo de ejemplo, curratelo un poco más.

B

new Vector3 (0f, 0f, 0f) vs Vector3.zero

	case 0:
		for (int i = 0; i < iteracciones; i++) {
			test = new Vector3 (0f, 0f, 0f);
		}
		break;

	case 1:
		for (int i = 0; i < iteracciones; i++) {
			test = Vector3.zero;
		}
		break;		
  • usar new Vector3 (0f, 0f, 0f) en vez de Vector3.zero es aproximadamente un 5% más lento.
kesada7

Usar GetComponent para acceder al component es aproximadamente un 30% más lento que acceder al component usando una variable que contenga su referencia.

Nunca he entendido muy bien como funciona eso en C#, es decir en C++ sería un puntero que apunta a lo que devuelve GetComponet, pero C# no tiene punteros e igualar una variable a algo lo que hace es una "copia" del contenido no? Pero no, a efectos prácticos funciona también como los punteros, haciendo referencias, es decir si haces:

 GameComponent componente1 = GameObject.GetComponent();

Puedes usar la variable componente1 dentro de los Update() para acceder en vez de usar todo el rato GameObject.GetComponent() que sería más lento, a eso te refieres no?

2 respuestas
r2d2rigo

#6 el problema es que tu no sabes como implementa Unity el GetComponent internamente, lo mismo guarda las referencias en un diccionario que tienes coste 1 o lo mismo lo hace en una lista que tiene coste n. De ahi la diferencia de rendimiento.

B

#6 cada vez que usas GetComponent se realiza una búsqueda en los componentes del gameobject. Almacenar el componente (su referencia) en una variable y usarla evita las búsquedas posteriores.

1 respuesta
B

Usar GetComponent en Update o bucles supone repetir constantemente la búsqueda del componente dentro del gameobject.

1 respuesta
VicoViper

#8 +1

Personalmente (OJO! PERSONALMENTE!!) el GetComponent, o lo uso en una función tipo "Setup" o no lo uso. En la mayoría de casos, prefiero tenerlo todo metido en variables publicas y hace drag and drop en el inspector (aunque luego me cague en todo cuando toca hacer cambios más o menos gordos) que meter un getcomponent.

1
B

Yo uso el getcomponent para los setup de elementos a la hora de montar la escena y luego interactuar con estas variables.

El tema es que algo que necesite ser modificado, pero se encuentre en otro script y/o los crees en runtime. Prefiero usar Delegates en vez de asignarlo al script o al controlador. De esta manera solo me tengo que preocupar de activarlos y desactivarlos. Además de crear la función o funciones a realizar.

Esto incluye que la ejecución de los métodos se vea encargada el componente en vez del controlador. O estar enviando información de un componente a otro.

SnakyBeaky

#9 si si, mejor quita el trozo de spaghetti ese que es lamentable compadre. Llevo mas de 5 años trabajando en Unity, se nota que aún estas aprendiendo. Sobretodo aprendiendo C#, por que mas allá de lo poco que conoces el entorno de Unity, se nota que de C# manejas más bien poco.

· No sigues ningún tipo de convención en cuanto a nombrado de variables, metodos, clases, etc...
· Creas tipos innecesarios nestados para guardar algo que podrias guardar en una tupla
· No especificas modificadores de acceso
· Comentas cosas obvias, usas 16 barras consecutivas para introducir el comentario, comentas todo en mayúsculas como si estuvieras gritando
· Usas casteos innecesarios
· No estas al tanto de las novedades de C# y .NET por eso usas construcciones obsoletas
· Nombras variables sin ninguna relacion a lo que realmente representan (has nombrado "variable" al Transform del GameObject)
· No comprendes la diferencia fundamental entre los eventos Awake y Start
· Dudo que sepas que es LINQ, así que me limitaré a decir que ignoras completamente una gran tecnologia de C#, ya que no he visto ni rastro en tu spaghetti sin embargo podrias haberlo aplicado en varios casos
· Desconoces completamente la interpolación de strings
· Complicas innecesariamente la lógica con el uso de operadores aritmeticos dentro de condicionales

En fín, podría seguir listando malas prácticas en tu código un buen rato...

Te dejo una cita muy interesante, si no la entiendes pasala por el traductor :

Premature optimization is the root of all evil.

Un saludo.

1 2 respuestas
B

Lo dicho, UI en runtime...

1 respuesta
Jastro

Haya paz. Si consideras que puedes mejorar el código, aparte de meterle mierda, ponle cosas a mejorar.

Que indiques cosas a mejorar OK, que le digas que quite ese trozo de codigo espaguetii lamentable sobra. Aquí actualmente no hay ningun profesional del videojuego como para venirnos arriba y ni aunque lo fueramos, no hace falta pasarse tampoco.

Si quieres aportar, aporta, pero desde el respeto.

4 1 respuesta
B

Acceso a lista (1000) List<GameObject> lista; ... for vs foreach

	case 0:
		for (int i = 0; i < iteracciones; i++) {
			for (int j = 0; j < 1000; j++) {
				dato = lista [j];
			}
		}
		break;

	case 1:
		for (int i = 0; i < iteracciones; i++) {
			foreach (GameObject dato in lista) {
			}
		}
		break;
  • For es algo más del 60% más rápido que foreach en accesos a listas (gameobject, dimensionado a 1000).
3 respuestas
kesada7

#12 Con menos prepotencia y educación te irá mejor en la vida "compadre" aunque dudo que en la vida real vayas hablando así a la gente (o eso espero) . Si tienes tanta experiencia como dices en Unity pues podrías aprovechar para enseñarnos cosas útiles a los que estamos aprendiendo, aunque en realidad uno en este campo siempre es un aprendiz aunque lleves años dedicados. Y si no te apetece compartir tus conocimientos con la plebe pues al menos sé un poco educado.

1
3 comentarios moderados
B

El impacto de usar Screen en vez de almacenarlo en una variable.

	case 0:
		for (int i = 0; i < iteracciones; i++) {
			test = Screen.height;
		}
		break;

	case 1:
		for (int i = 0; i < iteracciones; i++) {
			test = variable;
		}
		break;		
  • Usar Screen para acceder a las dimensiones de la ventana en vez de almacenar el dato en una variable supone un impacto superior al 75%.
1 comentario moderado
Jastro

Rencillas personales por privados. Venimos a comentar los test, las faltas de respeto, ya no se tolerarán, por lo tanto empiezo a repartir chocopuntos.

Jastro

#15 Mirando este en cuestión me ha dejado roto, 60% mas lento, es una burrada.

VicoViper

#15 ¿Seguro que este test lo has hecho bien? Tenía entendido que había impacto, pero se me hace raro que sea TAN bestia...

1 respuesta
SnakyBeaky

#15 test completamente erróneo y resultados inventados...

        private static void Main(string[] args)
        {
            int iterations = 50000;
            List<string> items = Enumerable.Range(0, 1000).Select(i => i.ToString()).ToList();

        Stopwatch forWatch = Stopwatch.StartNew();

        for (int i = 0; i < iterations; i++)
        {
            for (int j = 0; j < items.Count; j++)
            {
                string x = items[j];
            }
        }

        forWatch.Stop();
        
        Stopwatch forEachWatch = Stopwatch.StartNew();

        for (int i = 0; i < iterations; i++)
        {
            foreach (string j in items)
            {
                string x = j;
            }
        }

        forEachWatch.Stop();

        Console.WriteLine($"{forWatch.Elapsed:g} for | {forEachWatch.Elapsed:g} foreach");
        Console.ReadLine();
    }

0:00:00,2864927 for
0:00:00,2953922 foreach

3 respuestas
Jastro

A mi este hilo me parece interesante. Esta claro que lo de #25 tiene mas sentido. Es una buena idea el intentar generar test para poner a prueba los motores.

¿Alguno tiene algun bunnymark de Unity? Porque la verdad hay unos datos que me gustaria comparar. Si alguien no esta al tanto del Bunnymark que me avise y explico de que va xD

1 respuesta
B

Algo así? :D

Que conste que las chibis animadoras, se mueven dando pequeños saltitos.

1 1 respuesta
Jastro

#27 Coooorrecto!!!

¿Cuantas consigues mostrar antes de perder los 60fps?

1 respuesta
B

#28 Con 15 se mantiene estable.

Aunque en pantalla del juego solo habrá 5 personajes haciendo animaciones así que en pc y móviles aguanta bastante bien.

1 respuesta
Jastro

#29 WUT

15 es muy poco xD. ¿PC?

1 respuesta
Tema cerrado