Code benchmarks Unity3D

B

#30 Un i5 de 2.26 GHz y 8 GB de RAM

En un pc más actual rendirá mucho más. Los personajes se mueven aunque en este gif se ve una mierda de FPS :/

2 respuestas
B

#25 tu planteamiento es erróneo:

Primero: usar items.Count en el for desvirtúa el resultado.

Segundo: mi test está probado en Unity (este hilo va de pruebas en Unity).

Tercero: #24 #26 he encontrado documentación sobre el tema...

...y nada nuevo (calcado con mi test)

PD: #25 se agradece que pases de desvirtuar el tema a aportar (aunque sea con información errónea respecto a la salida que da Unity3D).

1 respuesta
Jastro

Joder...pues me parece fatal semejante bajon de rendimiento para un foreach es para flipar.

3 respuestas
B

#33 con array no sucede, es con list. Se debe tener en cuenta dada la magnitud de pérdida.

B

Acceder al gameobject del propio script directamente vs hacerlo con variable.

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

case 1:
	for (int i = 0; i < iteracciones; i++) {
		test = variable;
	}
	break;		
  • acceder al gameobject que contiene el script directamente es un 80% más lento que hacerlo desde una variable que contenga su referencia.
SnakyBeaky

#32 que equivocado estás amigo mio... a parte de que tu test es completamente inválido ya que realizas cosas diferentes en un bucle comparado con el otro (en el for estas haciendo una asignación, en el foreach tienes el bucle vacío).

Cabe destacar que al test no le importa que tipo uses mientras sea una clase, ya que la asignacion se hace por referencia y no estas copiando nada por lo que todos los tipos por referencia se comportaran igual, es decir que no importa que yo haya usado strings y tu GameObjects.

Por último, cuando iteras sobre una colección normalmente lo haces sobre toda ella, no sobre un número de elementos arbitrarios que tu te lo sacas de la chistera como es 1000 en tu ejemplo, es decir que si que lo haces sobre items.Count.

Veo que has hecho un copy paste del link que mencionas y el tiene el mismo error, por lo que deduzco que ni siquiera te has molestado en echarle un vistazo al código antes de postearlo aquí...

2 respuestas
B

#33 a menor dimensión varía el resultado...

B

#36 haz la prueba en Unity sin desvirtuar el for y sales de dudas. Repito, el hilo va de test prácticos en Unity.

1 respuesta
B

#36

Primero: en mi test, el for asigna, el foreach no asigna... en todo caso el perjudicado debería ser el for.

Segundo: asigno en for porque foreach lo hace internamente.

Tercero: he migrado tu código y probado en Unity...

spoiler

El resultado es este:


PD: he eliminado tu items.Count porque supone una influencia externa que desvirtúa el test aproximadamente en un 15% de rendimiento. He puesto un número pero se podría usar una variable (cacheando el items.Count) y el resultado es similar.

1 1 respuesta
-Crack-

Mola la idea del hilo, también deberías tener en cuenta que ciertas técnicas hacen allocations y otras no, el GC en unity es de las cosas que te pueden matar el performance.

1
SnakyBeaky

#38 de ser así deberías estar haciendo pruebas en cuanto a shaders, tipos de colliders, configuración de rigidbodies, etc... no comparar un tipo de bucle o otro, que es algo fundamental de C# y no específico de Unity.

Y de nuevo, te repito, "Premature optimization is the root of all evil."

Si quieres optimizar un juego hecho en Unity, te metes el profiler en Deep Profile y miras por qué tu juego va a pedales, juegas con los parametros de iluminación, optimizas los modelos para reducir la cantidad de tris, configuras la camara y los parametros de oclusion y distancia de vision, etc...

En cuanto a código, puedes seleccionar una estructura de datos mas apropiada para lo que vas a hacer, puedes añadir paralelismo, puedes tener en cuenta el GC y sus consecuencias, puedes usar algoritmos diferente, etc...

En fin, tienes miles de opciones a elegir para optimizar, cambiando un tipo de bucle a otro no vas a conseguir nada.

#39 de nuevo, manipulas el test. El items.Count no supone ninguna influencia externa, eso te lo sacas tu de la manga. El items.Count se usa para enumerar sobre la colección en su totalidad, tu le estas metiendo un numero arbitrario por que tu ya conoces el tamaño de la colección de antemano. Eso es manipular un test.

1 respuesta
B

#41 items.Count manipula la comparación porque la implementación óptima del for es mediante el cacheo de items.Count a una variable vs implementación interna del foreach.

Aun así... ahí va con el items.Count...

spoiler

PD: Abres el Unity, pegas tu propio código (con el items.Count), le das a play y después lo cascas...

kesada7

#31 Que es exactamente lo que hacen los personajes? Tienen una animación? Físicas? Es que no entiendo el por que de ese bajo rendimiento que con solo pasar de 15 instancias baje de los 60fps... Yo en el último juego que puse en el foro creo cientos de instancias con su rigibody y aplicandole fuerzas y va en móviles. Que me estoy perdiendo? Lo mismo no me estoy enterando de una mierda en que consite el bunny test.

1 1 respuesta
B

#43 Un bunny test consiste en un stress test de elementos en una escena para controlar el rendimiento de esta. Es como si en un mmo, en la zona inicial metieras a cientos o miles de jugadores para comprobar todas las conexiones y peticiones de estos jugadores al server analizando los tiempos de respuesta. O en uno de naves espaciales, cuantos cohetes, bolas, naves y otras piezas puede contener la escena antes de que los FPS decaigan.

En el caso que me ocupa. Cada animadora está formado por unos 50-100 sprites, uno por cada parte del cuerpo o elemento movible. Animator, el SDK para hacerlos funcionar para que no se solapen los sprites. A ver, el SDK usado tiene demasiada carga y por ello solo se pueden mantener ese cierto número de elementos en pantalla. No está pensado para contener tal número de elementos.

Viene muy bien para móviles y novelas gráficas pero no para crear animaciones de movimiento con los que un personaje pueda moverse por la pantalla.

3
B

#41 optimización básica de un simple bucle for...

	var cuenta = lista.Count;

	switch (prueba) {

	case 0:
		for (int i = 0; i < iteracciones; i++) {
			for (int j = 0; j < lista.Count;) {
				j++;
			}
		}
		break;

	case 1:
		for (int i = 0; i < iteracciones; i++) {
				for (int j = 0; j < cuenta;) {
				j++;
			}
		}
		break;		
	}
  • usar el items.Count (dimensionado a 1000) de #41 (autoproclamado dios de la interpolación de strings) supone casi un 60% de esfuerzo extra respecto a usar su valor almacenado en una variable.

Repito: no son pruebas de rendimiento de c#... son pruebas prácticas de la salida que da Unity3D.

En el caso de las listas, varía también dependiendo de la versión de Unity empleada. Las más recientes son más eficientes, pero aún así #15 ronda el 50% en pro de for.

B

Puedes hacer un test con i++ e ++i?

1 1 respuesta
Potito

#46 xdddddd

1
r2d2rigo

#31 algo estas haciendo muy mal para que solo te corran 15 sprites estables.

#33 foreach es syntactic sugar para recorrer el enumerator, dependiendo de sobre que lo uses generara allocs adicionales (o no). Con un for indexas directamente en el array/list asi que no hay diferencia de rendimiendo.

1 respuesta
B

#48 De dónde sacáis que son 15 sprites? Son 15 modelos, cada cual contiene 100 mallas con su correspondiente textura

Aquí la textura.

Cada una de sus partes es movible desde el editor o desde el animador.

Alguno que use Spine o Anima2D pueda mostrar un bunnytest de cuantos elementos en pantalla pueda tenerse en pantalla.

1 respuesta
pirri1721

Yo soy un absolut newbe en esto de forear en desarrollo, y visto que algunos traen ya el revolver fuera, no parece este el saloon más adecuado en el que meterse a comentar, pero me mola lo que leo, llevo dos años intentando abrir los ojos con que a lo mejor el game-dev no es mi sitio por el nivel, y entre 3
notas (seguramente ingenieros) que veo que habeís posteado en menos de dos días por aquí, ya me estais echando xD
Ánimo con esos test, aunque bien me apunto esa cita de la prematura optimización

#49 jajajajajaja acabas de callarle la boca y los pensamientos a muchos, creo

B

Sobre #15 y #25 ...

Para alguno de los presentes...

  • que abra Unity
  • cree Main.cs y le pegue el código adjunto
  • agregue el Main.cs a algún gameobject
  • le de al play

El código...

spoiler

La salida/respuesta que da Unity3D, eso es de lo que va el hilo...

¿Qué dice la consola de Unity al seguir los paso de arriba?

¿Hay o no diferencia de rendimiento?

¿A favor de for o foreach?

Gracias...

PD: fe de autoría... el código original es de #25

B

El siguiente test resulta algo inesperado... podéis hacer la prueba por vuestra cuenta.

20k gameobjects en escena, cada uno el siguiente script (funciones vacías, creado por defecto).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class a2 : MonoBehaviour {

	// Use this for initialization
	void Start () {
	
	}

	// Update is called once per frame
	void Update () {
	
	}
}


Da una salida aproximada de 50fps

Si eliminamos la función Update (que está vacía).

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class a1 : MonoBehaviour {

	// Use this for initialization
	void Start () {
	
	}
}

La salida es la siguiente...


Da una salida aproximada de 150fps

  • eliminar los Updates que no se usen (incluso si están vacíos) en los scripts.
1 2 respuestas
Srednuht

#52 Bueno, inesperado tampoco

1 respuesta
B

#53 pues yo no me lo esperaba, me esperaba un preprocesado + clean.

1
kesada7

#52 Whaaaat? Yo pensaba que eso el compilador te lo elimina, vamos estaba al 99% seguro. Pero si cuando ya creas un script te viene por defecto, yo nunca los borraba, los dejaba ahí aunque no los usara.

Srednuht

#53 Pues si, siempre se recomienda eliminar todos los métodos del ciclo de Unity que no estén en uso porque se intentan evaluar, vamos es algo que recuerdo aprender casi desde el principio. No lo digo por darme aires de nada, si no porque debe de estar remarcado por ahí en la documentación o similar.

De hecho es peligroso para ciertas prácticas donde la gente usa componentes a modo de etiquetas ( por ejemplo, hacer la clase Libro.cs, vacía con el Start y Update por defecto simplemente para recoger luego con un Getcomponent todos los "Libros")

Borradlos siempre!

De todas formas, siempre está bien ilustrar el impacto que tiene, 20K GO tampoco es un número normal, pero aunque con 100 GO la diferencia no sea tanta, siempre es bueno recortar

También deberías notar mejoras si eliminas el Start, solo que al ser de llamada única y al principio el impacto puede parecer / ser menor

Update()
Update(), LateUpdate() and other event functions look like simple functions, but they have a hidden overhead. These functions require communication between engine code and managed code every time they are called. In addition to this, Unity carries out a number of safety checks before calling these functions. The safety checks ensure that the GameObject is in a valid state, hasn't been destroyed, and so on. This overhead is not particularly large for any single call, but it can add up in a game that has thousands of MonoBehaviours.

For this reason, empty Update() calls can be particularly wasteful. We may assume that because the function is empty and our code contains no direct calls to it, the empty function will not run. This is not the case: behind the scenes, these safety checks and native calls still happen even when the body of the Update() function is blank. To avoid wasted CPU time, we should ensure that our game does not contain empty Update() calls.
1
B

Veo que mi manía de borrar los métodos vacíos no era sólo mía :D.

B

Para el runtime del editor podría ser justificable (que tampoco)... Pero bueno, teniendo en cuenta la interminable lista de BUGs pendientes que tienen, seguramente el no pre procesar les alivie de problemáticas posteriores.

r2d2rigo

Unity no tiene por que hacer ningun stripping de metodos vacios porque puede acabar tocando donde no debe. Y si a mi me da la gana tener un metodo virtual vacio pero que las clases derivadas usan?

1 respuesta
B

#59 no aplica, estamos hablando de un método específico que además es inherente al engine, el Update.

Tema cerrado

Usuarios habituales