Jump to content
enelmenu

Rendimiento en Update

Recommended Posts

Hola, Alguien que sepa un pocom asin ternamente sobre el lenguaje de programacion y me diga hablando en terminos re rendimiento, como funcionan varios for en un update que se actualiza por frame, son una serie de for yo diria comunes, nada fuera del margen normal de sobrecarga. O porlomenos y ocreo que no es sobrecarga, y si no lo es  en que momento se podria decir que estamos sobrecargando mas datos de lo que puede procesar un script por frame?

Estos son algunos for en un update

public class Checker : MonoBehaviour
	{
		public List<Track> Tracks = new List<Track>();

		private void Update()
		{
			foreach (var Track in Tracks)
			{
				foreach (var Pipe in Track.Pipes)
				{
					for (int i = ; i < Pipe.Values.Length; i++)
					{
						if (Pipe.Values[i] == Pipe.Pipe.GetComponent<Pipe>().values[i])
						{
							Pipe.Joined = true;
						}
						else
						{
							Pipe.Joined = false;
							break;
						}
					}
				}

				for (int i = ; i < Track.Pipes.Count; i++)
				{
					if (Track.Pipes[i].Joined == false)
					{
						Track.TrackOn = false;
						return;
					}
				}

				Track.TrackOn = true;
			}
		}
	}

De promedio tengo minimmo 5 pipes(tubos) por Track(via), un GetComponent malo ahi que se repite, nose como guardar antes ese determinado componente de ese determinado objeto, mas omenos itero mas de unas 100 o 250veces por frame, esto me parece una locura ami, pero no conosco el potencial de la programacion todabia soy un poco novato.

Esto le duele mucho a los fps? Asi tal cual como ese codigo, y si no es mucha carga de info por frame, cuando se podria decir que uno se pasa de mambo conlos for en cada frame?

 

Edited by enelmenu

Share this post


Link to post
Share on other sites
9 hours ago, enelmenu said:

mas omenos itero mas de unas 100 o 250veces por frame, esto me parece una locura ami

Hola IntheMenu, mira no va en las veces que iteras una simple iteracion funcionando al minimo (sin tener en cuenta el cuerpo del for) nada mas suma la variable y la compara, o en cada foreach algo similar (vamos a suponer para simplificar). Por supuesto sin tomar la gran parte del proceso que va en el orden de los eventos-funciones (start, update, lateUpdate, Onrender ... ), en el resto de los monobehaviour, graficos, audio, otros hilos, etc. Es decir si tuvieras un archivo de C super pelado haciendo for's.

Suponete 1 ciclo de reloj por iteracion pelada (a modo de simplificacion) con un clock de 3.2 GHz un solo hilo bancandose todo.

FPS = fclock / (iteraciones * (ciclos_Iteraciones + ciclos_Cuerpo));

- 300 iteraciones por frame , Cuerpo con 1 ciclo (o un NOP, "ciclo delay") --> 5726623  FPS

- 300 iteraciones por frame , Cuerpo con 300 ciclos --> 38050.6 FPS

- 300 iteraciones por frame , Cuerpo con 3000 ciclos --> 3816.47 FPS

- 10 scripts con 300 iteraciones por frame , Cuerpo con 3000 ciclos ---> FPS = 381.6 FPS (parece que sobra, solo a modor de mostrar numeros).

Si tuvieras las mismas iteraciones pero anidadas es un poquito peor, en algunas de estas iteraciones cuando pasas del gran for al pequeño for estas haciendo dos ciclos de comparacion, luego que el mismo for de antes, nada determinante, sobretodo si el cuerpo cuesta mucho mas que estas compraciones.

Hay varios factores que pueden empeorar la cosa, desde el lado de proceso vs memoria del programa, pero no va al scripting de Unity ni a lo que uno va a usar, es mas de bajo nivel. Si te interesa recuerdo esta tecnica https://en.wikipedia.org/wiki/Loop_unrolling En donde el for se va desarrollando en el mismo programa , te evitas de hacer la iteracion (comparacion + suma + mas salto) a expensas de incrementar el tamaño del programa. Bue me fui por las ramas.

Por supuesto esto considera un lenguaje compilado, que tenes las instrucciones ya determinadas a ejecutar dependiendo de la plataforma, optimizado para esta, y no un interprete de por medio, por eso siempre que tengas calculo pesado se suele recomendar a modo general usar plugins (generalemtne en C/C++) que hagan este trabajo y no usar el lenguaje de scripting (logica, movimiento, estados, etc), estamos hablando de mucho calculo, no un for buscando un getcomponent por ejemplo.

------------------------------------------------------------------------------------------------------------------

En tu caso: primero Que es eso?--> Pipe.Pipe.GetComponent<Pipe>() , muchos Pipes jaja. No se que es lo que estabas tratando de hacer, asi que muchas mejoras no te puedo sugerir. Si lo basico:

_ Fijate que en el gran cuerpo estas haciendo un foreach en Track.Pipes, luego sigue un for en Track.Pipes (de vuelta), es decir que los podes juntar tranquilamente o por lo menos intentar hacerlo y obtener igual resultado, estas ahorrando la mitad de iteraciones (aprox)

_ siempre que tengas si esto es verdadero haceme esto verd/falso y si esto es falso haceme esto falso/verd te conviente o queda mejor a la vista usar directamente un operador logico

varBool = condicion1 != condicion2;

//equivalente a 
if(condicion1 != condicion2)
	varBool = true;
else
	varBool = false;

- Otra es el GetComponent, antes de entrar a un for, si tenes que trabajar sobre variables o contenedores de un componente (en este caso Pipe.value) en "modo lectura" siempre te conviene tener tu propia def del contenedor con sus valores, es lo unico que te interesa, fijate que a values[] no le estas escribiendo nada, solo comparas sus valores, entonces podrias antes definir un arreglo y copiar el array (nunca copie un array no se si con la funcion Copy(...) lo podes hacer, igualando arrays, o simplemente un for previo llenando los valores, por las dudas Pongo un "COPY ARRAY" a modo de prueba ). La idea es NO usar el Getcomponent en cada iteracion. Otra cosa a tener en cuenta es el garbageCollector, cuando salis del "foreach Pipe in TrackPipes" el array ese muere, el GC tendra que recolectarlo, si fuera muy grande el array supongo que tardaria su tiempo, es todo un costo/beneficio habra casos que sean mejor y peor, probando se llega al punto justo.

foreach (var Pipe in Track.Pipes)
{
	"Tipo"[] valueArray <--- COPY_ARRAY(Pipe.Pipe.GetComponent<Pipe>().values[]);
      
	for (int i = ; i < Pipe.Values.Length; i++){
		Pipe.Joined = Pipe.Values[i] == valueArray[i];
		if(!Pipe.Joined){
			Track.TrackOn = false;
			return;
		}
	}

	//si salio del for ninguno estaba en joined = false 
	Track.TrackOn = true;
}
				
  
			

 

No digo que este bien, pero asi se podria reducir un poco. SI tenes dudas medi los FPS vos mismo en una escena bien pelada cosa de que afecten los for's solamente. Usa el profiler y revisa el GC, el Update , etc.

Salu2

 

Share this post


Link to post
Share on other sites
hace 3 horas, lightbug said:

Si te interesa recuerdo esta tecnica https://en.wikipedia.org/wiki/Loop_unrolling En donde el for se va desarrollando en el mismo programa

Wow, me sorprende mucho esto, la programacion tiene mucha mas ramas de las que yo imaginaba, de echo debe tener las mismas ramas que un cerebro con algun sindrome que necesita que le digan que hacer jajajaja y cuando supere ese sindrome agarrate catalina

Bueno haber:
Te comento un poco mi situacion, para no aburrirte y que entiendas tooodo lo que estoy haciendo te hago un alto resumen con un gif y coloreando todo asi no te entro en ambiente(? (esto sigue siendo Kuboi ahora le estoy agregando algo mas avanzado) jajaja

hace 3 horas, lightbug said:

primero Que es eso?--> Pipe.Pipe.GetComponent<Pipe>()

Depaso te muestro esta mecanica/idea que hice ya que por ahi en un futuro te sirve para algo, para aplicar en algo que hagas o te de alguna idea nose(espero que si u.u decime dsp si te srive o no xD)

Tengo un array en cada pipe insertado con el script Pipe. Aca hay 4 valores de un pipe(tuberia) Estos 4 valores representan un Vector4, por asi decirlo, en donde cada numero representa una coordenada de un eje XY, vamos a dibujar(espero que no se deforme):

Los 1 tomados como Salidas.
Los 0 tomados como null.

1_Pipe_03_100x100.png  Esto es representado como esto: Example_01_100x100.png

2_Pipe_01_100x100.png Esto es representado como esto: Example_02_100x100.png

Importante, Tomamos como referencia los Ejes como en sentido del reloj, arriba derecha abajo izquierda
Tomando el ejemplo UNO, esto en el Array values queda asi:
values[0] = 0
values[1] = 0
values[2] = 1
values[3] = 0

En el script de Pipe, tambien tengo un algoritmo que Gira los valores en sentido del reloj, entonces, puedo girar por ejemplo el Pipe01 donde el values[2] ahora es 0
values[3] ahora es 1

Entonces suponiendo que queres CREAR un TRACK(una VIA, CAMINO), tenes que saber CUANDO CADA PIPE de el TRACK esta correcto y puede ser JOINED(UNIDO) SI TODOS SON JOINED EL TRACKON (EJ: el TrackOn del TRACK01) ES TRUE. 


Tambien:

Hay una Lista con un array, un gameobject y un booleano en el Manager de todo esto...(DONDE EL ARRAY De determinado pipe, es el CORRECTO el JOINED. EJemplo: El JOINED de Pipe01 es el array 0,0,1,0 y eso tengo anotado en el array del manager del TRACK01 del PIPE01)
el Pipe.Values es el array tiene los Values(4 valores ACTUALIZADOS CADA VEZ QUE GIRAN), el Pipe.Pipe es el gameobject al que compara mi array CORRECTO(El que explique recien), y darle true o false para su estado....

Es sierto que podria igualar Pipe.Pipe.GetComponent<Pipe>().values, agregando un array en la lista, tipo que (Pipe.Values == Pipe.AuxValues) valores auxiliares, e igualar eso en un Awake por ejemplo.
PERO Si haria eso obtendria COMO logro saber cuando mi array que se ACTUALIZA por frame, esta bien posicionado??
 

Por todo eso uso el  Pipe.Pipe.GetComponent<Pipe>(), Se te ocurre alguna variante donde no use el GetComponet por frame?, podria guardar en la Lista del Pipe, el script Pipe determinado del GameObject, tambien se me acaba de ocurrir.
 

En fin, no quiero que esto se transforme en un vuelco de demostrar lo que hice, sino que es en modo educativo(? jajajaj LITERAL, si te sirve que espero que asi sea decime!!, yo a todo esto lo estoy mostrando, primero por que quiero un juego bien echo, y que mejor que especialistas en el lenguaje me ayuden, y segundo que depaso les dejo estas ideitas minimas que por ahi te hacen ocurrior otras ideas mejores eso quiero alfin de al cabo tambien.

 

Saludos.:134_spy:

Edited by enelmenu

Share this post


Link to post
Share on other sites
7 hours ago, enelmenu said:

Es sierto que podria igualar Pipe.Pipe.GetComponent<Pipe>().values, agregando un array en la lista, tipo que (Pipe.Values == Pipe.AuxValues) valores auxiliares, e igualar eso en un Awake por ejemplo.

PERO Si haria eso obtendria COMO logro saber cuando mi array que se ACTUALIZA por frame, esta bien posicionado??

No, yo no digo en un awake, yo digo antes de for o foreach, cuadro a cuadro. Aparte eso es para un track, osea que si o si necesitas que el array se vaya actualizando, no podes definir uno en awake. (Sí podrias definir n arrays para los n tracks en awake, pero no se modificarian nunca)

7 hours ago, enelmenu said:

En fin, no quiero que esto se transforme en un vuelco de demostrar lo que hice, sino que es en modo educativo(? jajajaj LITERAL, si te sirve que espero que asi sea decime!!, yo a todo esto lo estoy mostrando, primero por que quiero un juego bien echo, y que mejor que especialistas en el lenguaje me ayuden, y segundo que depaso les dejo estas ideitas minimas que por ahi te hacen ocurrior otras ideas mejores eso quiero alfin de al cabo tambien.

Bueno entonces volviendo y "tratando evitando hablar sobre lo que hiciste", un for es un for, no  hay mas vuelta,  si dentro del for te mandas un moco glorioso no es culpa del for, osea mas alla de eso no se que mas se pueda llegar a decir. No creo que tengamos que traer a los "especialistas del lenguaje" para que te ayuden, y si te ayudasen en que seria en concreto? es imposible no hablar de tu proyecto personal, porque el for es independiente de todo, es un iterador (espero haberte desmostrado esto con el ejemplo de arriba con los tiempos/fps), en cambio la papa está en el interior + cantidad de fors por frame, depende de como haces vos las cosas, por ende en un cierto porcentaje de tu proyecto/metodologia, entendes? mira por ej:

--> fijate que si tus value[] fueran o no dinamicos cambia donde copias el array (awake vs interior/update), es decir cambia como usas el for.

-->Tambien fijate que si tuvieras un array con 1 millon de elementos (por ser exagerados) y estos encima de un tipo grande, no te conviene copiarlo y recorrerlo, mas vale leelo directamente! otra vez depende de tu proyecto.

por eso las 250 iteraciones que mencionas no tiene un argumento valido (por si solo) para determinar si unity o tu juego se lo va a bancar, es mas si me decias que tenias 1 iteracion vs 10 millones de iteraciones tampoco me dice nada (con 10 millones me da como > 350 fps para un NOP superaproximado), lo que importa es 'cuerpo + iteraciones + cantidad de scripts que hacen eso en 1 frame'.

No se a que te referis con "margen de sobrecarga". Un script puede tardar 5 segundos en terminar su Update, tardara >5 segundos en hacer un frame de Render, pero el juego va a "andar lo mas bien", >> quizas << no sea aceptable si queres 60 frames por segundo, tal vez el motor detecte que tal hilo tardo >5 segundos, que es mucho tiempo y se crasheé todo, un tipico "No responde", puede ser.

 

Share this post


Link to post
Share on other sites

UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...