unity react performance optimization profiling

performance - react - Uno podría usar un generador de perfiles, pero ¿por qué no detener el programa?



react native performance (17)

Si algo hace que un programa de un solo hilo tome, digamos, 10 veces más de lo que debería, podría ejecutar un generador de perfiles en él. También podría detenerlo con un botón de "pausa", y verá exactamente lo que está haciendo.

Incluso si solo es un 10% más lento de lo que debería ser, si lo detienes más veces, en poco tiempo lo verás repetidamente haciendo lo innecesario. Por lo general, el problema es una llamada de función en algún lugar en el medio de la pila que realmente no se necesita. Esto no mide el problema, pero seguro lo encuentra.

Editar: Las objeciones suponen en su mayoría que solo tomas 1 muestra. Si habla en serio, tome 10. Cualquier línea de código que cause algún porcentaje de desperdicio, como 40%, aparecerá en la pila en esa fracción de muestras, en promedio. Los cuellos de botella (en código de subproceso único) no pueden ocultarse.

EDITAR: Para mostrar lo que quiero decir, muchas objeciones son de la forma "no hay muestras suficientes, por lo que lo que ves podría ser completamente falso" - ideas vagas sobre el azar. Pero si algo de cualquier descripción reconocible , no solo estar en una rutina o la rutina activa, está en vigencia durante el 30% del tiempo, entonces la probabilidad de verlo en cualquier muestra dada es del 30%.

Entonces supongamos que solo se toman 10 muestras. El número de veces que se verá el problema en 10 muestras sigue una distribución binomial , y la probabilidad de verlo 0 veces es .028. La probabilidad de verlo 1 vez es .121. Por 2 veces, la probabilidad es .233, y por 3 veces es .267, luego de lo cual se cae. Dado que la probabilidad de verlo menos de dos veces es .028 + .121 = .139, eso significa que la probabilidad de verlo dos o más veces es 1 - .139 = .861. La regla general es que si ve algo que podría corregir en dos o más muestras, vale la pena corregirlo.

En este caso, la probabilidad de verlo en 10 muestras es del 86%. Si estás en el 14% que no lo ve, simplemente toma más muestras hasta que lo hagas. (Si el número de muestras aumenta a 20, la posibilidad de verlo dos o más veces aumenta a más del 99%). Por lo tanto, no se ha medido con precisión, pero se ha encontrado con precisión, y es importante comprender que podría ser algo que un generador de perfiles no podría encontrar realmente, como algo relacionado con el estado de los datos, no el contador del programa.


¿Qué ocurre si el programa está en producción y se está utilizando al mismo tiempo pagando a clientes o colegas? Un perfilador le permite observar sin interferir (tanto, porque por supuesto tendrá un pequeño golpe también según el principio de Heisenberg ).

La creación de perfiles también puede proporcionarle informes mucho más completos y detallados. Esto será más rápido a largo plazo.


EDITAR 2008/11/25: OK, la respuesta de Vineet finalmente me hizo ver cuál es el problema aquí. Mejor tarde que nunca.

De alguna manera la idea se desató en la tierra que los problemas de rendimiento se encuentran midiendo el rendimiento. Eso es medios confusos con fines. De alguna manera, evité esto haciendo un solo paso de programas completos hace mucho tiempo. No me regañé a mí mismo por reducir la velocidad humana. Estaba tratando de ver si estaba haciendo cosas incorrectas o innecesarias. Así es como hacer que el software sea rápido: encuentre y elimine operaciones innecesarias.

Nadie tiene la paciencia para caminar solo en estos días, pero lo mejor es elegir un número de ciclos al azar y preguntar cuáles son sus motivos. (Eso es lo que la pila de llamadas a menudo puede decirte). Si un buen porcentaje de ellos no tiene buenas razones, puedes hacer algo al respecto.

Es más difícil en estos días, con el subprocesamiento y la asincronía, pero así es como ajusto el software, al encontrar ciclos innecesarios. No al ver qué tan rápido es, lo hago al final.

He aquí por qué el muestreo de la pila de llamadas no puede dar una respuesta incorrecta, y por qué no se necesitan muchas muestras.

Durante el intervalo de interés, cuando el programa está tardando más tiempo del que le gustaría, la pila de llamadas existe de manera continua, incluso cuando no está haciendo un muestreo.

  • Si una instrucción I está en la pila de llamadas para la fracción P (I) de ese momento, eliminarla del programa, si pudiera, ahorraría exactamente tanto. Si esto no es obvio, piense un poco.

Si la instrucción aparece en M = 2 o más muestras, de N, su P (I) es aproximadamente M / N, y es definitivamente significativa.

La única forma en que puede dejar de ver las instrucciones es cronometrar mágicamente todas sus muestras para cuando las instrucciones no estén en la pila de llamadas. El simple hecho de que está presente por una fracción del tiempo es lo que lo expone a sus sondas.

Por lo tanto, el proceso de ajuste del rendimiento es una simple cuestión de elegir las instrucciones (principalmente instrucciones de llamada de función) que levantan la cabeza al activar múltiples muestras de la pila de llamadas. Esos son los árboles altos en el bosque.

Tenga en cuenta que no tenemos que preocuparnos por el gráfico de llamadas, ni por la duración de las funciones, ni por la cantidad de veces que se llaman, ni por la recursión.

Estoy en contra de la ofuscación, no en contra de los perfiladores. They give you lots of statistics, but most don''t give P(I), and most users don''t realize that that''s what matters.

You can talk about forests and trees, but for any performance problem that you can fix by modifying code, you need to modify instructions, specifically instructions with high P(I). So you need to know where those are, preferably without playing Sherlock Holmes. Stack sampling tells you exactly where they are.

This technique is harder to employ in multi-thread, event-driven, or systems in production. That''s where profilers, if they would report P(I), could really help.


El muestreo de Call Stack es una técnica muy útil para crear perfiles, especialmente cuando se trata de una base de código grande y complicada que podría estar pasando su tiempo en cualquier cantidad de lugares. Tiene la ventaja de medir el uso de la CPU por el reloj de pared, que es lo que importa para la interactividad, y la obtención de callstacks con cada muestra le permite ver por qué se está llamando a una función. Lo uso mucho, pero utilizo herramientas automatizadas para él, como Luke Stackwalker y OProfile y varias cosas suministradas por el proveedor de hardware.

La razón por la que prefiero las herramientas automáticas al muestreo manual para el trabajo que hago es el poder estadístico . Tomar diez muestras a mano está bien cuando tienes una función ocupando el 40% del tiempo de ejecución, porque en promedio obtendrás cuatro muestras, y siempre al menos una. Pero necesita más muestras cuando tiene un perfil plano, con cientos de funciones de hoja, ninguna ocupa más del 1.5% del tiempo de ejecución.

Digamos que tienes un lago con muchos tipos diferentes de peces. Si el 40% de los peces en el lago son salmón (y el 60% "todo lo demás"), entonces solo necesita capturar diez peces para saber que hay muchos salmones en el lago. Pero si tienes cientos de especies diferentes de peces, y cada especie es individualmente no más del 1%, necesitarás pescar más de diez peces para poder decir "este lago es un 0,8% de salmón y un 0,6% de trucha". "

De manera similar, en los juegos en los que trabajo hay varios sistemas principales, cada uno de los cuales llama a docenas de funciones en cientos de entidades diferentes, y todo esto sucede 60 veces por segundo. Algunas de esas funciones se canalizan hacia operaciones comunes (como malloc ), pero la mayoría no, y en cualquier caso no hay una sola hoja que ocupe más de 1000 μs por fotograma.

Puedo ver las funciones del maletero y ver, "estamos gastando el 10% de nuestro tiempo en una colisión", pero eso no es muy útil: necesito saber exactamente en qué momento de la colisión, así que sé qué funciones apretar. Solo "hacer menos colisión" solo te lleva tan lejos, especialmente cuando significa tirar las características. Prefiero saber que "estamos gastando un promedio de 600 μs / frame en falta de memoria caché en la fase estrecha del octree porque el misil mágico se mueve tan rápido y toca muchas células", porque entonces puedo rastrear la solución exacta: ya sea un árbol mejor o misiles más lentos.

El muestreo manual estaría bien si hubiera un gran 20% de protuberancia en, por ejemplo, stricmp , pero con nuestros perfiles no es el caso. En cambio, tengo cientos de funciones que necesito obtener, digamos, del 0,6% del fotograma al 0,4% del fotograma. Necesito afeitar 10 μs de cada función de 50 μs que se llama 300 veces por segundo. Para obtener ese tipo de precisión, necesito más muestras.

Pero en el fondo lo que Luke Stackwalker hace es lo que describes: cada milisegundo más o menos, detiene el programa y registra la pila de llamadas (incluidas las instrucciones precisas y el número de línea de la IP ). Algunos programas solo necesitan decenas de miles de muestras para ser perfiladas de manera útil.

(Hemos hablado de esto antes, por supuesto, pero pensé que era un buen lugar para resumir el debate).


En los servidores Java, siempre ha sido un buen truco hacer 2-3 rápidas Ctrl - Breaks s en una fila y obtener 2-3 threaddumps de todos los subprocesos en ejecución. Simplemente mirando dónde están todos los hilos "pueden" determinar muy rápidamente dónde están sus problemas de rendimiento.

Esta técnica puede revelar más problemas de rendimiento en 2 minutos que cualquier otra técnica que conozca.


Estos deben ser algunos ejemplos triviales con los que está trabajando para obtener resultados útiles con su método. No puedo pensar en un proyecto donde la creación de perfiles fuera útil (con cualquier método) que hubiera obtenido resultados decentes con su método "rápido y efectivo". El tiempo que lleva iniciar y detener algunas aplicaciones ya pone en cuestión su afirmación de "rápido".

De nuevo, con programas no triviales, el método que defiende es inútil.

EDITAR: con respecto a "¿por qué no se lo conoce mejor?"

En mi experiencia, las revisiones de código evitan códigos y algoritmos de baja calidad, y los perfiles también los encontrarían. Si desea continuar con su método, es grandioso, pero creo que para la mayoría de la comunidad profesional esto está tan abajo en la lista de cosas para probar que nunca obtendrá un refuerzo positivo como un buen uso del tiempo.

Parece ser bastante inexacto con pequeños conjuntos de muestras y para obtener grandes conjuntos de muestras tomaría mucho tiempo que habría sido mejor utilizado con otras actividades útiles.


Estoy sorprendido por el tono religioso en ambos lados.

El perfilado es excelente, y ciertamente es más refinado y preciso cuando puedes hacerlo. A veces no puedes, y es bueno tener una copia de seguridad confiable. La técnica de pausa es como el destornillador manual que utiliza cuando su herramienta eléctrica está demasiado lejos o las baterías se han agotado.

Aquí hay una breve historia real. Una aplicación (una especie de tarea de procesamiento por lotes) había estado funcionando bien en producción durante seis meses, de repente los operadores llaman a los desarrolladores porque está yendo "demasiado lento". ¡No nos van a permitir conectar un generador de perfiles de muestreo en producción! Tienes que trabajar con las herramientas ya instaladas. Sin detener el proceso de producción, simplemente usando Process Explorer , (que los operadores ya habían instalado en la máquina) pudimos ver una instantánea de la pila de un hilo. Puede echar un vistazo a la parte superior de la pila, descartarlo con la tecla Intro y obtener otra instantánea con otro clic del mouse. Puede obtener una muestra fácilmente cada segundo más o menos.

No tarda mucho en ver si la parte superior de la pila está más a menudo en la biblioteca de la base de datos DLL (esperando en la base de datos) o en otra DLL del sistema (esperando una operación del sistema) o en algún método de la aplicación en sí. En este caso, si mal no recuerdo, rápidamente nos dimos cuenta de que 8 de cada 10 veces la aplicación estaba en una llamada de archivo DLL del sistema leyendo o escribiendo un archivo de red. Efectivamente, las "actualizaciones" recientes habían cambiado las características de rendimiento de un recurso compartido de archivos. Sin un enfoque rápido y sucio y (sancionado por el administrador del sistema) para ver lo que la aplicación estaba haciendo en producción , hubiésemos pasado mucho más tiempo tratando de medir el problema, que corrigiendo el problema.

Por otro lado, cuando los requisitos de rendimiento van más allá de "lo suficientemente bueno" como para empujar realmente la envolvente, un perfilador se vuelve esencial para que pueda tratar de afeitar los ciclos de todos sus diez o veinte puntos principales estrechamente vinculados. Incluso si solo está tratando de cumplir con un requisito de rendimiento moderado durante un proyecto, cuando puede obtener las herramientas correctas alineadas para ayudarlo a medir y probar, e incluso integrarlas en su proceso de prueba automatizado, puede ser muy útil.

Pero cuando se corta la energía (por así decirlo) y las baterías están agotadas, es bueno saber cómo usar ese destornillador manual.

Entonces, la respuesta directa: sepa lo que puede aprender al detener el programa, pero tampoco tema a las herramientas de precisión. Lo más importante es saber qué trabajos requieren las herramientas.


Hacer esto manualmente no se puede llamar realmente "rápido" o "efectivo", pero hay varias herramientas de creación de perfiles que lo hacen automáticamente; también conocido como perfil estadístico .


Hay una diferencia entre las cosas que los programadores realmente hacen, y las cosas que recomiendan que otros hagan.

Sé de muchos programadores (incluido yo mismo) que realmente usan este método. Solo ayuda a encontrar los problemas de rendimiento más obvios, pero es rápido y sucio y funciona.

Pero realmente no le diría a otros programadores que lo hagan, porque me llevaría demasiado tiempo explicar todas las advertencias. Es demasiado fácil hacer una conclusión imprecisa basada en este método, y hay muchas áreas en las que simplemente no funciona. (por ejemplo, ese método no revela ningún código que se active por la entrada del usuario).

Así que al igual que el uso de detectores de mentiras en la corte, o la declaración "goto", simplemente no recomendamos que lo haga, aunque todos tengan su uso.


Las instantáneas de trazado de pila solo le permiten ver radiografías estroboscópicas de su aplicación. Es posible que requiera más conocimiento acumulado que un perfilador puede darle.

El truco es conocer bien tus herramientas y elegir lo mejor para el trabajo que tienes entre manos.


Los perfiladores de muestreo solo son útiles cuando

  1. Está monitoreando un tiempo de ejecución con un pequeño número de subprocesos. Preferiblemente uno.
  2. La profundidad de la pila de llamadas de cada hilo es relativamente pequeña (para reducir la increíble sobrecarga al recolectar una muestra).
  3. Solo le preocupa el tiempo del reloj de pared y no otros contadores o cuellos de botella de recursos.
  4. No ha instrumentado el código para fines de gestión y supervisión (de ahí las solicitudes de volcado de pila)
  5. Cree erróneamente que eliminar un marco de pila es una estrategia eficaz de mejora del rendimiento, independientemente de que los costes inherentes (excluidos los callebles) sean prácticamente nulos o no
  6. No se puede molestar en aprender a aplicar la ingeniería del rendimiento del software día a día en su trabajo
  7. ....

Porque a veces funciona, y a veces te da respuestas completamente incorrectas. Un perfilador tiene un registro mucho mejor de encontrar la respuesta correcta, y generalmente llega más rápido.


Pulsar el botón de pausa durante la ejecución de un programa en modo "depuración" podría no proporcionar los datos correctos para realizar optimizaciones de rendimiento. Para decirlo sin rodeos, es una forma cruda de perfilar.

Si debe evitar el uso de un generador de perfiles, una mejor opción es usar un registrador, y luego aplicar un factor de desaceleración para "estimar" dónde está el verdadero problema. Sin embargo, los profilers son mejores herramientas para estimar.

La razón por la que pulsar el botón de pausa en el modo de depuración puede no dar una imagen real del comportamiento de la aplicación es porque los depuradores introducen código ejecutable adicional que puede ralentizar ciertas partes de la aplicación. Uno puede referirse a la publicación de blog de Mike Stall sobre las posibles razones de la desaceleración de la aplicación en un entorno de depuración. La publicación arroja luz sobre ciertos motivos, como demasiados puntos de interrupción, creación de objetos de excepción, código no optimizado, etc. La parte sobre el código no optimizado es importante: el modo de "depuración" dará lugar a muchas optimizaciones (por lo general, código en el forro y pedidos) que se expulsan de la ventana, para habilitar el host de depuración (el proceso que ejecuta su código) y el IDE para sincronizar la ejecución del código. Por lo tanto, presionar Pausa repetidamente en el modo "depurar" podría ser una mala idea.


Si tomamos la pregunta "¿Por qué no se la conoce mejor?" entonces la respuesta será subjetiva. Es de suponer que la razón por la que no se conoce mejor es porque los perfiles proporcionan una solución a largo plazo en lugar de una solución de problema actual. No es efectivo para aplicaciones de subprocesos múltiples y no es efectivo para aplicaciones como juegos que pasan una gran parte de su tiempo de renderizado.

Además, en aplicaciones de subproceso único si tiene un método que espera consumir el mayor tiempo de ejecución, y desea reducir el tiempo de ejecución de todos los demás métodos, será más difícil determinar qué métodos secundarios enfocar sus esfuerzos sobre el primero.

Su proceso de creación de perfiles es un método aceptable que puede funcionar y funciona, pero la creación de perfiles le proporciona más información y tiene el beneficio de mostrarle mejoras y regresiones de rendimiento más detalladas.

Si tiene un código bien instrumentado, entonces puede examinar más que solo el tiempo de un método en particular; puedes ver todos los métodos.

Con el perfil:

  • Luego puede volver a ejecutar su escenario después de cada cambio para determinar el grado de mejora / regresión del rendimiento.

  • Puede perfilar el código en diferentes configuraciones de hardware para determinar si su hardware de producción será suficiente.

  • Puede perfilar el código bajo escenarios de carga y estrés para determinar cómo el volumen de información afecta el rendimiento

  • Puede hacer que a los desarrolladores más jóvenes les resulte más fácil visualizar los impactos de sus cambios en su código, ya que pueden volver a perfilar el código dentro de seis meses mientras están en la playa o en el pub, o en ambos. Beach-pub, ftw.

A los perfiles se les da más peso porque el código de la empresa siempre debe tener cierto grado de perfil debido a los beneficios que brinda a la organización durante un período prolongado. Cuanto más importante sea el código, más perfiles y pruebas hará.

Su enfoque es válido y es otro elemento es la caja de herramientas del desarrollador. Simplemente se ve superado por el perfil.


I used this method for Commodore 64 BASIC many years ago. It is surprising how well it works.


I''ve typically used it on real-time programs that were overrunning their timeslice. You can''t manually stop and restart code that has to run 60 times every second.

I''ve also used it to track down the bottleneck in a compiler I had written. You wouldn''t want to try to break such a program manually, because you really have no way of knowing if you are breaking at the spot where the bottlenck is, or just at the spot after the bottleneck when the OS is allowed back in to stop it. Also, what if the major bottleneck is something you can''t do anything about, but you''d like to get rid of all the other largeish bottlenecks in the system? How to you prioritize which bottlenecks to attack first, when you don''t have good data on where they all are, and what their relative impact each is?


Stepping through code is great for seeing the nitty-gritty details and troubleshooting algorithms. It''s like looking at a tree really up close and following each vein of bark and branch individually.

Profiling lets you see the big picture, and quickly identify trouble points -- like taking a step backwards and looking at the whole forest and noticing the tallest trees. By sorting your function calls by length of execution time, you can quickly identify the areas that are the trouble points.


The larger your program gets, the more useful a profiler will be. If you need to optimize a program which contains thousands of conditional branches, a profiler can be indispensible. Feed in your largest sample of test data, and when it''s done import the profiling data into Excel. Then you check your assumptions about likely hot spots against the actual data. There are always surprises.