Donde he trabajado, siempre usamos múltiples niveles de creación de perfiles; Si ve un problema, simplemente baje un poco más en la lista hasta que descubra lo que está sucediendo:
- El "perfilador humano", también conocido como solo jugar el juego ; ¿Se siente lento o "enganche" ocasionalmente? ¿Te das cuenta de animaciones desiguales? (Como desarrollador, tenga en cuenta que será más sensible a algunos tipos de problemas de rendimiento y ajeno a otros. Planifique las pruebas adicionales en consecuencia).
- Encienda la pantalla FPS , que es un FPS promedio de 5 segundos con ventana deslizante. Muy poca sobrecarga para calcular y mostrar.
- Active las barras de perfil , que son solo una serie de quads (colores ROYGBIV) que representan diferentes partes del marco (por ejemplo, vblank, preframe, update, collision, render, postframe) usando un temporizador simple "cronómetro" alrededor de cada sección de código . Para enfatizar lo que queremos, configuramos un ancho de pantalla equivalente a un marco objetivo de 60Hz, por lo que es realmente fácil ver si está, por ejemplo, un 50% por debajo del presupuesto (solo media barra) o un 50% por encima ( la barra se enrolla y se convierte en una barra y media). También es bastante fácil saber qué es lo que generalmente consume la mayor parte del marco: rojo = renderizado, amarillo = actualización, etc.
- Cree una compilación instrumentada especial que inserte "cronómetro" como código alrededor de todas y cada una de las funciones. (Tenga en cuenta que puede obtener un rendimiento masivo, dcache e icache al hacer esto, por lo que definitivamente es intrusivo. Pero si carece de un perfil de muestreo adecuado o un soporte decente en la CPU, esta es una opción aceptable. También puede ser inteligente sobre el registro de un mínimo de datos sobre la función enter / exit y la reconstrucción de calltraces más tarde). Cuando creamos el nuestro, imitamos gran parte del formato de salida de gprof .
- Lo mejor de todo, ejecute un generador de perfiles de muestreo ; VTune y CodeAnalyst están disponibles para x86 y x64, tiene varios entornos de simulación o emulación que pueden proporcionarle datos aquí.
(Hay una historia divertida del GDC del año pasado de un programador de gráficos que tomó cuatro fotos de sí mismo: feliz, indiferente, molesto y enojado, y mostró una imagen apropiada en la esquina de las construcciones internas en función de la velocidad de fotogramas. los creadores de contenido aprendieron rápidamente a no activar sombreadores complicados para todos sus objetos y entornos: harían enojar al programador. Contemplen el poder de la retroalimentación).
Tenga en cuenta que también puede hacer cosas divertidas como graficar las "barras de perfil" continuamente, para que pueda ver patrones de espiga ("estamos perdiendo un cuadro cada 7 cuadros") o similares.
Para responder a su pregunta directamente, sin embargo: en mi experiencia, mientras que es tentador (y, a menudo recompensar - Por lo general aprendo algo) para volver a escribir funciones / módulos individuales al número Optimizar de instrucciones o Icaché o dcache rendimiento, y lo hacemos realmente necesita hacer esto a veces cuando tenemos un problema de rendimiento particularmente desagradable, la gran mayoría de los problemas de rendimiento que tratamos regularmente se reducen al diseño . Por ejemplo:
- ¿Deberíamos almacenar en caché en RAM o recargar desde el disco los cuadros de animación de estado de "ataque" para el jugador? ¿Qué tal para cada enemigo? No tenemos RAM para hacerlos todos, ¡pero las cargas de disco son caras! ¡Puedes ver el enganche si aparecen 5 o 6 enemigos diferentes a la vez! (Bien, ¿qué tal escalonar el desove?)
- ¿Estamos haciendo un solo tipo de operación en todas las partículas, o todas las operaciones en una sola partícula? (Esta es una compensación icache / dcache, y la respuesta no siempre es clara). ¿Qué tal si separamos todas las partículas y almacenamos las posiciones juntas (la famosa "estructura de matrices") versus mantener todos los datos de partículas en un solo lugar (" matriz de estructuras ").
Lo escuchas hasta que se vuelve desagradable en cualquier curso de informática de nivel universitario, pero: realmente se trata de estructuras de datos y algoritmos. Dedicar algo de tiempo al algoritmo y al diseño del flujo de datos le dará más beneficios en general. (Asegúrese de haber leído las excelentes diapositivas de las diapositivas de la programación orientada a objetos de un compañero de Sony Developer Services para obtener una idea aquí). Esto no "se siente" como una optimización; es principalmente el tiempo que se pasa con una pizarra o herramienta UML o creando muchos prototipos, en lugar de hacer que el código actual se ejecute más rápido. Pero generalmente vale mucho más la pena.
Y otra heurística útil: si está cerca del "núcleo" de su motor, puede valer la pena un esfuerzo extra y experimentación para optimizar (por ejemplo, ¡vectorice esas multiplicaciones matriciales!). Cuanto más lejos del núcleo, menos debería preocuparse por eso a menos que una de sus herramientas de creación de perfiles le indique lo contrario.
Sin embargo, recuerde también "pesimismo prematuro". Si bien no es necesario volverse duro en cada línea de código, hay justificación para darse cuenta de que realmente está trabajando en un juego, lo que tiene implicaciones de rendimiento en tiempo real.
Si bien todos le dicen que mida y optimice los puntos calientes, esa técnica no le mostrará el rendimiento que se pierde en lugares ocultos. Por ejemplo, si cada operación '+' en su código demoraría el doble de lo que debería, no aparecerá como un punto caliente y, por lo tanto, nunca lo optimizará ni siquiera se dará cuenta, ya que se está utilizando para colocarlo puede costarle mucho rendimiento. Te sorprendería cuántos de esos ciclos se filtran sin ser detectados. Así que sé consciente de lo que haces.
Aparte de eso, tiendo a perfilar regularmente para tener una idea de lo que hay allí y cuánto tiempo queda por fotograma. Para mí, el tiempo por fotograma es el más lógico, ya que me dice directamente dónde estoy con los objetivos de velocidad de fotogramas. También trate de averiguar dónde están los picos y qué los causa: prefiero una velocidad de fotogramas estable sobre una velocidad de fotogramas alta con picos.
fuente
Una vez que un juego está listo para ser lanzado (ya sea final o beta), o es notablemente lento, ese es probablemente el mejor momento para perfilar su aplicación. Por supuesto, siempre puede ejecutar el generador de perfiles en cualquier momento; pero sí, la optimización prematura es la raíz de todo mal. Optimización infundada, también; necesita datos reales para mostrar que algunos códigos son lentos, antes de intentar "optimizarlos". Un perfilador lo hace por ti.
Si no sabes sobre un perfilador, ¡aprende! Aquí hay una buena publicación de blog que demuestra la utilidad de un generador de perfiles.
De lo contrario, si su pequeño juego se ejecuta a 200 FPS a pesar de que tiene un algoritmo ineficiente, ¿realmente tiene una razón para optimizar? Debes tener una buena idea de las especificaciones de tu máquina objetivo y asegurarte de que el juego se ejecute bien en esa máquina, pero cualquier cosa más allá de eso es (posiblemente) tiempo perdido que podría gastarse mejor codificando o puliendo el juego.
fuente
Me resulta útil construir perfiles. Incluso si no está optimizando activamente, es bueno tener una idea de lo que está limitando su rendimiento en un momento dado. Muchos juegos tienen algún tipo de HUD superpuesto que muestra una tabla gráfica simple (generalmente solo una barra de color) que muestra cuánto tiempo duran varias partes del bucle del juego en cada fotograma.
Sería una mala idea dejar el análisis y la optimización del rendimiento en una etapa demasiado tardía. Si ya has creado el juego y estás un 200% por encima del presupuesto de tu CPU y no puedes encontrarlo mediante la optimización, estás jodido.
Necesitas saber cuáles son los presupuestos para gráficos, física, etc., mientras escribes. No puede hacer eso si no tiene idea de cuál será su rendimiento, y no puede adivinar eso sin saber cuál es su rendimiento y qué tanta holgura podría haber.
Así que incorpore algunas estadísticas de rendimiento desde el primer día.
En cuanto a cuándo abordar cosas, nuevamente, probablemente sea mejor no dejarlo demasiado tarde, para no tener que refactorizar la mitad de su motor. Por otro lado, no te involucres demasiado en la optimización de las cosas para exprimir cada ciclo si crees que podrías cambiar el algoritmo por completo mañana, o si no has puesto datos reales del juego a través de él.
Retire la fruta que cuelga a medida que avanza, aborde las cosas grandes periódicamente, y debería estar bien.
fuente
Si mira la cita de Knuth en su contexto, continúa explicando que debemos optimizar pero con herramientas, como un generador de perfiles.
Debe perfilar constantemente su perfil de memoria y su aplicación después de que se establezca la arquitectura muy básica.
La creación de perfiles no solo lo ayudará a aumentar la velocidad, sino que también lo ayudará a encontrar errores. Si su programa de repente cambia drásticamente la velocidad, esto generalmente se debe a un error. Si no está perfilando, puede pasar desapercibido.
El truco para optimizar es hacerlo por diseño. No esperes hasta el último minuto. Asegúrese de que el diseño de su programa le brinde el rendimiento que necesita sin realmente trucos desagradables del bucle interno.
fuente
Para mi proyecto, generalmente aplico algunas optimizaciones MUY necesarias en mi motor base. Por ejemplo, siempre me gusta implementar una buena implementación SIMD sólida usando SSE2 y 3DNow. Esto asegura que mi matemática de coma flotante esté en el lugar donde quiero que esté. Otra buena práctica es aprovechar las optimizaciones a medida que codifica en lugar de retroceder. La mayoría de las veces, estas pequeñas prácticas son tan lentas como lo que estaba codificando de todos modos. Antes de codificar una función, asegúrese de investigar la forma más eficiente de hacerlo.
En pocas palabras, en mi opinión, es MÁS DIFÍCIL hacer que su código sea más eficiente después de que ya es una mierda.
fuente
Diría que la forma más fácil sería usar su sentido común: si algo parece que se está ejecutando lentamente, échele un vistazo. Vea si es un cuello de botella.
Use un generador de perfiles para ver las funciones de velocidad que toman y con qué frecuencia se les llama.
No tiene ningún sentido optimizar o perder tiempo tratando de optimizar algo que no lo necesita.
fuente
Si su código se ejecuta lentamente, ejecute un generador de perfiles y vea qué es exactamente lo que hace que se ejecute más lento. O puede ser proactivo y tener un generador de perfiles ejecutándose antes de comenzar a notar problemas de rendimiento.
Querrás optimizar cuando tu velocidad de cuadros baje a un punto que el juego comience a sufrir. Su culpable más probable será que su CPU se use demasiado (100%).
fuente
Debería optimizar su código ... tan a menudo como sea necesario.
Lo que he hecho en el pasado es ejecutar continuamente el juego con el perfil activado (al menos un contador de velocidad de cuadros en la pantalla en todo momento). Si el juego se está volviendo lento (por debajo de su velocidad de fotogramas objetivo en su máquina de especificaciones mínimas, por ejemplo), encienda el generador de perfiles y vea si aparecen puntos calientes.
A veces no es el código. Muchos de los problemas con los que me he encontrado en el pasado han estado orientados a gpu (concedido, esto estaba en el iPhone). Problemas de velocidad de llenado, demasiadas llamadas de sorteo, falta de geometría suficiente, sombreadores ineficientes ...
Además de algoritmos ineficientes para problemas difíciles (es decir, búsqueda de caminos, física), rara vez me he encontrado con problemas en los que el código en sí era el culpable. Y esos problemas difíciles deberían ser cosas en las que invierte mucho esfuerzo para obtener el algoritmo correcto y no preocuparse por cosas más pequeñas.
fuente
Para mí es el mejor seguir un modelo de datos bien preparado. Y optimización-antes del principal paso adelante. Quiero decir, antes de comenzar a implementar algo grande y nuevo. Otra razón para la optimización es cuando estoy perdiendo el control de los recursos, la aplicación necesita mucha carga de CPU / GPU o memoria y no sé por qué :) o es demasiado.
fuente