2009-04-15 13 views
8

Estoy trabajando en un proyecto que necesita mucho ajuste de rendimiento.¿Mejores prácticas de prueba de rendimiento al hacer TDD?

¿Cómo escribo una prueba que falla si mis optimizaciones no mejoran la velocidad del programa?

Para elaborar un poco:

El problema no es descubrir qué partes de optimizar. Puedo usar varias herramientas de evaluación y evaluación comparativa para eso.

El problema es utilizar pruebas automatizadas para documentar que una optimización específica sí tuvo el efecto deseado. También sería muy conveniente si pudiera usar el conjunto de pruebas para descubrir posibles regresiones de rendimiento más adelante.

Supongo que podría simplemente ejecutar mis herramientas de generación de perfiles para obtener algunos valores y luego afirmar que mi código optimizado produce mejores valores. El problema obvio con eso, sin embargo, es que los valores de referencia no son valores difíciles. Varían según el entorno local.

Entonces, ¿la respuesta es utilizar siempre la misma máquina para realizar este tipo de pruebas de integración? Si es así, aún tendría que permitir cierta confusión en los resultados, ya que incluso en los mismos resultados de evaluación comparativa de hardware puede variar. ¿Cómo luego tomar esto en cuenta?

¿O tal vez la respuesta es mantener versiones anteriores del programa y comparar resultados antes y después? Este sería mi método preferido, ya que es en su mayoría agnóstico del medio ambiente. ¿Alguien tiene experiencia con este enfoque? Me imagino que solo sería necesario mantener una versión anterior si se puede hacer pasar todas las pruebas si el rendimiento de la última versión es al menos tan bueno como la versión anterior.

Respuesta

3

Primero debe establecer algunos criterios para un rendimiento aceptable, luego debe idear una prueba que fallará ese criterio al usar el código existente, luego deberá ajustar su código para el rendimiento hasta que pase la prueba. Probablemente tenga más de un criterio para el rendimiento, y seguramente debería tener más de una prueba.

+0

¿Confirma usted esta afirmación al control de revisión? ¿Espera que se revise en más de un tipo de máquina? Si es así (como me imagino), ¿cómo puede usted proporcionar una expectativa razonable de que sus afirmaciones son apropiadas en una máquina más lenta/más rápida? – bukzor

2

Registre el tiempo de ejecución del código actual.

if (newCode.RunningTime >= oldCode.RunningTime) Fail 
+1

Incluso en el sistema de mejor comportamiento, esto producirá un falso positivo (falla cuando todo está realmente bien) 50% del tiempo; esta es una solución inutilizable. – bukzor

3

En muchas aplicaciones de servidor (puede que no sea su caso) problema de rendimiento se manifiestan sólo en el acceso concurrente y bajo carga. Por lo tanto, medir el tiempo absoluto que ejecuta una rutina y tratar de mejorarlo no es muy útil. Hay problemas con este método incluso en aplicaciones de subproceso único. La medición del tiempo de rutina absoluto se basa en el reloj que proporciona la plataforma, y ​​estos son not always very precise; es mejor confiar en el tiempo promedio que toma una rutina.

Mi consejo es:

  • uso de perfiles para identificar las rutinas que se ejecutan la mayoría de veces y toman más tiempo.
  • Utilice la herramienta como JMeter o Grinder para elaborar casos de prueba representativos, simular el acceso concurrente, poner su aplicación bajo tensión y medir (más importante) el rendimiento y el tiempo de respuesta promedio. Esto le dará una mejor idea de cómo se comporta su aplicación como se ve desde la perspectiva externa.

Mientras que usted podría utilizar las pruebas unitarias para establecer algunos aspectos no funcionales de su aplicación, creo que el enfoque dado anteriormente dará mejores resultados durante el proceso de optimización. Cuando coloque afirmaciones relacionadas con el tiempo en las pruebas de su unidad, tendrá que elegir algunos valores muy aproximativos: el tiempo puede variar según el entorno que esté utilizando para ejecutar las pruebas de su unidad. No desea que las pruebas fallen solo porque algunos de sus colegas usan hardware inferior.

La afinación se trata de encontrar las cosas correctas para sintonizar. Ya tiene un código que funciona, por lo que si coloca afirmaciones relacionadas con el rendimiento a posteriori y sin establecer secciones críticas de código, puede perder mucho tiempo en optimizar piezas no esenciales de su aplicación.

+0

"el tiempo puede variar según el entorno que esté utilizando para ejecutar las pruebas de su unidad. No desea que las pruebas fallen solo porque algunos de sus colegas están utilizando un hardware inferior". Eso es exactamente correcto, y en parte lo que está causando mi dolor de cabeza. – KaptajnKold

+0

Después de que hayas ajustado el sistema, ¿cómo evitarás que retroceda? En todos los demás escenarios de regresión de software, la solución es agregar una aserción al conjunto de pruebas. – bukzor

1

Ejecute las pruebas + perfiles en el servidor de CI. También puede ejecutar pruebas de carga periódicamente.

Le preocupan las diferencias (como ha mencionado), por lo que no se trata de definir un valor absoluto. Tenga un paso adicional que compare las medidas de rendimiento de esta ejecución con la de la última compilación e informe las diferencias como%. Puede levantar una bandera roja para variaciones importantes de tiempo.

Si le preocupa el rendimiento, debe tener objetivos claros que quiera cumplir y hacerlos valer. Debe medir aquellos con pruebas en el sistema completo. Incluso si la lógica de su aplicación es rápida, es posible que tenga problemas con la vista que le hagan perder el objetivo. También puede combinarlo con el enfoque de diferencias, pero para estos tendría menos tolerancia a las variaciones de tiempo.

Tenga en cuenta que puede ejecutar el mismo proceso en su computadora dev, solo usando las ejecuciones previas en esa computadora y no una compartida entre desarrolladores.

5

Sospecho que la aplicación de TDD para controlar el rendimiento es un error. Por supuesto, utilícelo para obtener un buen código de diseño y funcionamiento, y use las pruebas escritas en el curso de TDD para garantizar la corrección continua, pero una vez que tiene un código bien elaborado y un conjunto sólido de pruebas, está en buena forma. para sintonizar y se aplican diferentes técnicas y herramientas (de TDD).

TDD le ofrece un buen diseño, un código confiable y una red de seguridad de cobertura de prueba. Eso te coloca en un buen lugar para afinar, pero creo que debido a los problemas que tú y otros han citado, simplemente no te llevará mucho más lejos en el camino de sintonía. Lo digo como un gran admirador y defensor de TDD y un practicante.

+1

+1 de acuerdo. TDD garantiza que cuando sintonice el sistema, no rompa la funcionalidad –

+0

Esta respuesta sería mucho más útil si menciona * cualquiera * de las técnicas más adecuadas. – bukzor

+0

@bukzor El OP parece tener un buen manejo de los perfiles de conceptos y herramientas; la pregunta era cómo aplicar TDD a esto. Mi respuesta es que eso es probablemente imprudente; hay muchas otras preguntas y respuestas sobre cómo ajustar el rendimiento de su código. –

0

Para la sintonización en sí, puede comparar el código antiguo y el nuevo código directamente. Pero no guardes ambas copias. Esto suena como una pesadilla para manejar. Además, solo comparas una versión con otra versión. Es posible que un cambio en la funcionalidad disminuya la velocidad de su función, y eso es aceptable para los usuarios.

Personalmente, nunca he visto los criterios de rendimiento del tipo 'debe ser más rápido que la última versión', porque es muy difícil de medir.

Usted dice 'en serio necesidad de ajuste del rendimiento'. ¿Dónde? ¿Qué consultas? ¿Qué funciones? ¿Quién dice, el negocio, los usuarios? ¿Cuál es el rendimiento aceptable? ¿3 segundos? ¿2 segundos? 50 milisegundos?

El punto de partida para cualquier análisis de rendimiento es definir los criterios de aprobado/rechazado. Una vez que tenga esto, PUEDE automatizar las pruebas de rendimiento.

Para mayor confiabilidad, puede usar un enfoque estadístico (simple). Por ejemplo, ejecute la misma consulta en las mismas condiciones 100 veces.Si el 95% de ellos regresan en menos de n segundos, eso es un pase.

Personalmente, haría esto en el momento de la integración, ya sea desde una máquina estándar o desde el servidor de integración. Registre los valores para cada prueba en alguna parte (el control de crucero tiene algunas características agradables para este tipo de cosas). Si hace esto, puede ver cómo progresa el rendimiento a lo largo del tiempo y con cada compilación. Incluso puedes hacer un gráfico. A los gerentes les gustan los gráficos.

Tener un entorno estable siempre es difícil de hacer cuando se realizan pruebas de rendimiento, independientemente de que se realicen o no pruebas automáticas. Tendrás ese problema particular sin importar cómo te desarrolles (TDD, Waterfall, etc.).

+1

"Nunca he visto los criterios de rendimiento del tipo 'deben ser más rápidos que la última versión'" La gente de WebKit tiene una política de tolerancia cero para las regresiones de rendimiento. – KaptajnKold

+0

@KatajnKold Eso es genial. Eso significa que lo he visto una vez :-) –

0

No he enfrentado esta situación todavía;) sin embargo, si lo hiciera, aquí es cómo lo haría. (Creo que tomé esto del libro de Dave Astel)

Paso n. ° 1: Propóngase una especificación de "rendimiento aceptable", por ejemplo, esto podría significar "El usuario debe poder hacer Y en N secs" (o milisegundos) '
Paso n. ° 2: Ahora escribe una prueba fallida. Usa tu clase amistosa de temporizador (p. ej. .NET tiene la clase cronómetro) y Assert.Less(actualTime, MySpec)
Paso n. ° 3: si la prueba ya pasó, ya terminaste . Si es rojo, debes optimizarlo y hacerlo verde. Tan pronto como la prueba se vuelva verde, el rendimiento ahora es 'aceptable'.

0

kent beck y su equipo automatizaron todas las pruebas en TDD.

aquí para pruebas de rendimiento también podemos automatizar las pruebas en TDD.

los criterios aquí en las pruebas de rendimiento es que debemos probar los sí o no casos

si conocemos las Specfications bien n bien que podemos automatizar ellos también en TDD

0

Mientras que en líneas generales de acuerdo con la respuesta de Carl Manaster Con las herramientas modernas es posible obtener algunas de las ventajas que TDD ofrece para las pruebas funcionales en las pruebas de rendimiento.

Con la mayoría de los marcos de pruebas de rendimiento modernas (la mayor parte de mi experiencia es con Gatling, pero creo que el mismo es cierto para las nuevas versiones de la mayoría de los marcos de pruebas de rendimiento), es posible integrar las pruebas de rendimiento automatizados en la acumulación de integración continua, y configurar para que la compilación de CI falle si no se cumplen los requisitos de rendimiento.

Así siempre y cuando sea posible acordar de antemano cuáles son sus requisitos de rendimiento son (que para algunas aplicaciones puede ser impulsado por los SLA acordados con los usuarios o clientes), esto le puede dar una retroalimentación rápida si un cambio ha creado un problema de rendimiento, e identificar áreas que necesitan mejoras de rendimiento.

Los buenos requisitos de rendimiento están en la línea de "cuando hay 5000 pedidos por hora, el 95% de los viajes del usuario deben incluir no más de 10 segundos de espera y ninguna transición de pantalla tarda más de 1 segundo".

Esto también se basa en la implementación en un entorno de prueba similar a la producción en su canalización CI.

Sin embargo, probablemente aún no sea una buena idea utilizar los requisitos de rendimiento para impulsar su desarrollo de la misma manera que con los requisitos funcionales. Con requisitos funcionales, generalmente tiene alguna idea de si su aplicación pasará la prueba antes de ejecutarla, y es sensato tratar de escribir el código que cree que será aprobado. Con rendimiento, trying to optimize code whose performance hasn't been measured is a dubious practice.Puede utilizar el rendimiento resultados para impulsar el desarrollo de su aplicación hasta cierto punto, simplemente no el rendimiento requisitos.