Ember.js: Pérdida de rendimiento entre las versiones 2.X y 3.X

Creado en 14 may. 2020  ·  28Comentarios  ·  Fuente: emberjs/ember.js

Hay una pérdida de rendimiento del 60 por ciento entre las versiones 2.X y 3.X. Vea los registros de tiempo de renderizado en los violines a continuación en diferentes versiones. Ejemplos simplificados para demostrar un rendimiento de renderizado puro sin ningún estilo ni cálculos.

2.18 tiempo de renderizado del
3.18 tiempo de renderizado del

Bug Regression Rendering

Comentario más útil

Solo quería dar una actualización rápida sobre esto:

Hicimos una prueba de TracerBench similar a la que @runspired configuró con emberobserver.com , que es una de nuestras aplicaciones de prueba habituales, para ver si se había producido alguna ebullición de ranas (por ejemplo, pequeños cambios de rendimiento que eran insignificantes de una versión a otra). versión, pero resumido en un gran cambio). Estos son los resultados de esa prueba:

ember-observer-2.18-3.18.pdf

Podemos ver en estos resultados que hay dos saltos bastante definitivos:

  1. Ember 3.0 a Ember 3.1
  2. Ember 3.16 a Ember 3.17

La regresión en 3.17 se debe a la actualización de Glimmer VM, y actualmente nos estamos enfocando en reducir eso ya que es bastante reciente y probablemente comenzará a afectar las aplicaciones que se actualizan en el ciclo LTS pronto.

La regresión en 3.1 se conocía realmente en ese momento, tras una discusión con el equipo central. Fue causado, en parte, al habilitar captadores nativos y usar Object.defineProperty . Se consideró una regresión aceptable para permitir que el marco avanzara con nuevas funciones del navegador.

En general, el escenario {{each}} que se planteó al comienzo de este número parece haber retrocedido más y de diferentes maneras que emberobserver.com. Una vez que hayamos profundizado en la regresión 3.17, nos centraremos en optimizar {{each}} para ver qué se puede mejorar allí en general.

¡Gracias a todos por su paciencia!

Todos 28 comentarios

Después de algunas ejecuciones en Chrome 81 en mi máquina, obtuve:

2.18 mejor tiempo: 283ms
3.18 mejor tiempo: 471ms

Eso fue ejecutarlo con DevTools cerrado.

Luego convertí el twiddle 3.18 a Ember Octane mediante:

  • Usando clases nativas para componentes y controladores.
  • Usando @tracked y no usando @computed .
  • Convertir el componente t-r en un componente solo de plantilla porque no necesitaba una clase de respaldo.
  • Usar sintaxis de corchetes angulares al invocar componentes.
  • Usando argumentos con nombre y this. donde sea apropiado en las plantillas.

Después de eso, el mejor tiempo que obtuve de 3.18.1 fue 276ms, por lo que una mejora significativa en línea con el número 2.18.

Sin embargo, estas pruebas de rendimiento no fueron particularmente científicas y no he investigado qué cambio fue el más importante en términos de rendimiento.

Crear perfiles en un giro es bastante propenso a errores, ¿podemos migrar a un repositorio de aplicaciones ember-cli normal (usando una rama para cada una de las dos versiones) para generar perfiles?

@rwjblue Obtengo los mismos resultados en una aplicación normal de ember-cli. Puede probarse aquí

@ richard-viney Puede haber mejoras a considerar, pero el problema es que no se utiliza ningún código obsoleto en ambas versiones y la pérdida de rendimiento parece inaceptable.

  • El uso del componente de plantilla solo puede estar causando un aumento del rendimiento, pero definitivamente tr necesitará una clase de respaldo para calcular algunos estilos internos. El ejemplo se simplificó para demostrar el problema.
  • Con toda la refactorización, obtiene un aumento de rendimiento del 2 por ciento (283ms -> 276ms) frente a 2.18. Considere la posibilidad de actualizar una aplicación 2.18 a 3.X. Refactorizar todos los componentes solo para obtener ese aumento del 2 por ciento definitivamente no es factible.

@barisnisanci De acuerdo, no tenía la intención de sugerir que este tipo de refactorización debería ser necesaria para evitar regresiones de rendimiento significativas al actualizar. Fue un experimento para ver si había algún impacto por el uso de las convenciones modernas, ya que eso podría ayudar a aislar el problema y / o permitir que se solucione si es necesario.

Sería interesante saber qué versiones de Ember introdujeron la regresión de rendimiento probando también las versiones LTS intermedias, es decir, 3.4, 3.8, 3.12 y 3.16.

@barisnisanci Ember Twiddle y ember serve ejecutan en modo de desarrollo de forma predeterminada. Durante el desarrollo, se habilitan muchas herramientas adicionales que pueden afectar seriamente el rendimiento. Por lo general, no consideramos que esto sea una regresión o un problema, a menos que sea lo suficientemente malo como para afectar la ergonomía del desarrollador. Entonces, en primer lugar, verificaría que esté ejecutando ambas versiones en modo de producción.

Descargué su ejemplo y serví tanto 2.8 como 3.18 uno al lado del otro en modo de producción. Lo que encontré fue que parece que puede estar en lo cierto, en promedio, el tiempo entre las dos operaciones de ayuda (que es lo que se está midiendo aquí) parece mayor en 3.18 que en 2.8. Eso se basa en que tomé algunas muestras en mi computadora portátil de trabajo sin muchos controles, por lo que es difícil decirlo con certeza, pero a simple vista, podría ser un pequeño cambio.

Sin embargo, al observar otras métricas más significativas, no veo ningún cambio. Mirando específicamente el tiempo total para renderizar contenido, se ven más o menos iguales en general. Time to First Paint es aproximadamente el mismo, por ejemplo.

Screen Shot 2020-05-18 at 11 10 15 AM

Es importante tener en cuenta que tenemos mucho trabajo distribuido en muchos lugares, y cuando hacemos cambios, a veces ese trabajo se mueve pero no afecta las métricas _overall_. Es por eso que usamos TracerBench para verificar los cambios de rendimiento, porque está diseñado para considerar las fases generales de renderizado y para tener en cuenta todos los cambios en un nivel _macro_, en lugar de un nivel _micro_, como el tiempo entre los asistentes que se ejecutan.

Probablemente deberíamos intentar hacer una prueba de TracerBench pronto durante un período de tiempo más largo, solo para verificar estos hallazgos y asegurarnos de que no nos hemos deslizado en general (generalmente lo usamos para cambios más pequeños donde esperamos regresiones potenciales). También deberíamos intentar que se ejecute a intervalos regulares, para que podamos ver la línea de tendencia.

@pzuraq Acabo de actualizar el repositorio con rowsCount:300 y la diferencia columnsCount:20 debería ser más notoria ahora. Ambos se ejecutan con --environment production

  • 3.18 Primera pintura: 3489 ms
    3 18
  • 2.18 Primera pintura: 2814 ms
    2 18

También noté que JS Heap nunca se lanzó en 3.18, pero tal vez tuvo mala suerte en GC.

Puedo agregar enlaces de estilo, inyecciones de servicio, cálculos más pesados ​​en componentes en lugar de aumentar los recuentos, sin embargo, pueden ocultar el problema subyacente.

Como mencionaste, las métricas generales son muy importantes que los cambios menores. Sin embargo, las pequeñas diferencias se suman a una importante caída del rendimiento en nuestro caso. El tiempo de renderizado inicial de nuestra aplicación comercial aumentó de 15 a 20 segundos después de actualizar a 3.18. Con suerte, considerará la regresión en términos de porcentaje en lugar de cambios leves de milisegundos.

Nuestra empresa está sufriendo este problema. Actualizamos la versión de ember de 2.18 a 3.16. luego, nuestros tiempos de renderización se hicieron más largos en más del '50' por ciento. Cuando usamos estructuras complicadas, la diferencia entre los tiempos de renderización se volvió más obvia en lugar de ligeros cambios de milisegundos. ¿Alguna actualización sobre este tema? Tenemos puntos de referencia que muestran un aumento del 50% en el tiempo de procesamiento. Decidió aferrarse a 2.18 por el momento. Podemos considerar cambiar los marcos si requiere una refactorización importante.

@ Caglayan06 ¿Podrías confirmar que estás corriendo con la bandera de producción? ¡Solo quiero asegurarse de que los números sean manzanas con manzanas!

@ Caglayan06 - Es poco probable que esto sea una sola cosa. La reproducción que @barisnisanci proporcionó puede no coincidir con lo que muestra su perfil de aplicaciones. ¿Puede proporcionar una reproducción del problema general en su aplicación (o confirmar que el repositorio de ejemplo de

¿Tiene algún comentario sobre la última publicación de @barisnisanci en este hilo?
Tuvimos problemas de rendimiento similares después de actualizar 2.18 a 3.16. Tuvimos una pérdida de rendimiento del 40%. Bajamos la calificación a 3.12, pero solo logramos ahorrar el 20% de esa pérdida, aún no tan buena como 2.18. Refactorizar como mencionaste antes lleva casi tanto tiempo como cambiar de marco. ¿Esperamos alguna acción sobre este tema?

Recientemente actualizamos a Ember 3.16.8, no tenemos un caso de prueba de rendimiento y no encontramos un problema de rendimiento obvio en este momento.
pero me gustaría estar ansioso por resolver y cerrar los problemas de rendimiento lo antes posible.
>

PD: más memoria y cpu utilizada en ie11. a veces provoca el bloqueo de ie11.

@ Caglayan06 - Es poco probable que esto sea una sola cosa. La reproducción que @barisnisanci proporcionó puede no coincidir con lo que muestra su perfil de aplicaciones. ¿Puede proporcionar una reproducción del problema general en su aplicación (o confirmar que el repositorio de ejemplo de

El ejemplo de @rwjblue @barisnisanci funciona igual para mí como dice @barisnisanci .

@ Caglayan06 ¿Podrías confirmar que estás corriendo con la bandera de producción? ¡Solo quiero asegurarse de que los números sean manzanas con manzanas!

@scottmessinger sí, estamos corriendo con la bandera de producción. Nuestros resultados son similares a los resultados de @barisnisanci .

Mejoramos nuestra estructura de código. Aumentó el rendimiento Pero aún no es tan rápido como la versión Ember 2.18. Si hacemos esos cambios en 2.18 obtenemos mejores resultados.

No podemos revisar nuestro sistema de código para cambiar la sintaxis del código 3.16 y las nuevas funciones. Esto es demasiado costoso para nosotros, porque nuestro proyecto es enorme. Probablemente, refactorizar todo el proyecto sea más costoso que cambiar el marco. ¿Se tomará alguna medida sobre este problema?

¿Se tomará alguna medida sobre este problema?

¡Sí, por supuesto! Solo necesitamos encontrar tiempo para perfilar y descubrir qué está pasando. Pero eso realmente no necesita esperar a nadie más que a ti mismo

El ejemplo de @rwjblue @barisnisanci funciona igual para mí como dice @barisnisanci .

@ Caglayan06 - Hmm, eso no es realmente lo que pregunté. Sé que el ejemplo de @barisnisanci funciona, le pido que lo revise / lo perfile / compare las características de rendimiento con su aplicación y vea si la _forma_ en la que funciona el ejemplo (y es más lento) coincide con su aplicación.

@ Caglayan06 - Hmm, eso no es realmente lo que pregunté. Sé que el ejemplo de @barisnisanci funciona, le pido que lo revise / lo perfile / compare las características de rendimiento con su aplicación y vea si la _forma_ en la que funciona el ejemplo (y es más lento) coincide con su aplicación.

@rwjblue integro el repositorio de a nuestra aplicación, dio resultados similares. Cuando cambiamos la versión de 3.16 a 3.12, nuestro rendimiento se incrementó.
Pero aún no tan rápido como la versión 2.18.

En nuestra aplicación para algunos ejemplos:
2977

Como resultado:
Incluso mejoramos la estructura del código, los tiempos de renderización promedio totales;
2.18 tiempo de renderizado: 1x seg
3.16 tiempo de renderizado: 1.6x seg.
3.12 tiempo de renderizado: 1.4x seg.

3.20 tiene una actualización de VM, así que me pregunto si eso ayudaría aquí

@NullVoxPopuli no tuvo suerte con 3.20.0-beta.2 FP: 3.4 segundos (lo mismo con 3.18)

Dado que 3.12 muestra mejores resultados, creo que el problema puede presentarse con el seguimiento automático. Además, # 18225 podría estar relacionado considerando la caída del rendimiento de toda la aplicación en los puntos de referencia 3.12 -> 3.16 de @ Caglayan06 .

Hm. Me pregunto cuánta sobrecarga es la compatibilidad con versiones anteriores

Algunas preguntas generales:

  • ¿Cuál es el valor de la marca de función opcional del observador asíncrono?
  • ¿La aplicación en cuestión utiliza QP?
  • ¿La velocidad negativa afecta todas las rutas o solo algunas?

Algunas preguntas generales:

  • ¿Cuál es el valor de la marca de función opcional del observador asíncrono?
  • ¿La aplicación en cuestión utiliza QP?
  • ¿La velocidad negativa afecta todas las rutas o solo algunas?

@rwjblue

  1. Al no usar la bandera de observadores asíncronos, creo que el valor predeterminado es falso en 3.12. En 3.16 Probado con ambos no hace mucha diferencia.
  2. QPs ampliamente utilizados en rutas principales. Sin embargo, se observó una caída del rendimiento incluso sin ninguno.
  3. Todas las rutas se ven afectadas

Además, el repositorio de ejemplo no usa ninguno de los anteriores, pero aún es más lento en 3.X. Los tiempos de renderizado pueden haber aumentado gradualmente en cada versión secundaria, por lo que no podemos identificar el problema exacto.

Tracerbench informa que muestra que 2.18 a 3.18 retrocede ~ 17% para este escenario, pero también mejora en lugar de retroceder ~ 18% si se realiza una conversión al componente de luz tenue.

2.18 a 3.18 Sin otros cambios
Componentes 2.18 a 3.18 + Octano + Glimmer

Tengo mi propia bifurcación de esto donde agregué un corredor automático para esto, y estoy trabajando para mejorar el corredor para que podamos reducir rápidamente por versión / confirmación para encontrar dónde ocurrió la regresión. https://github.com/runspired/version-performance/runs/801596557

¡ Muchas gracias a

Para el contexto, @krisselden desarrolló TracerBench como una herramienta específicamente para probar el rendimiento de manera integral, y lo hemos estado usando para refactores importantes internamente, como la implementación de decoradores y seguimiento automático / seguimiento de revisiones . En LinkedIn lo usamos para probar nuestras aplicaciones antes de cada actualización de Ember, y no hemos visto este nivel de regresión.

Sin embargo, definitivamente podría ser algo que extrañamos. Al final, estamos probando aplicaciones específicas, que tienen comportamientos y casos de uso específicos. Este podría ser un problema que no detectamos porque nuestras aplicaciones de casos de prueba no usaron la funcionalidad que retrocedió, como la reproducción de @barisnisanci . También es posible que incluso si solucionamos los problemas en esa reproducción, es posible que no solucionemos otros, por lo que si está experimentando regresiones, definitivamente apreciaríamos las reproducciones para su caso de uso. Trabajaremos para hacer que la configuración de TracerBench sea más fácil de usar para que pueda probarlo localmente y enviar una reproducción como la de @runspired .

Vamos a profundizar para descubrir cuál es el problema exacto y encontrar una solución. Más importante aún, este nivel de regresión no es aceptable para _cualquier_ API, incluso si estamos viendo una aceleración con Octane. Si los usuarios no pueden actualizar y cambiar gradualmente, entonces no estamos todos escalando la montaña juntos.

Estén atentos para más actualizaciones, ¡les haremos saber mientras resolvemos las cosas!

Muchas gracias a @runspired por su genial https://github.com/TracerBench/tracerbench-compare-action

Solo quería dar una actualización rápida sobre esto:

Hicimos una prueba de TracerBench similar a la que @runspired configuró con emberobserver.com , que es una de nuestras aplicaciones de prueba habituales, para ver si se había producido alguna ebullición de ranas (por ejemplo, pequeños cambios de rendimiento que eran insignificantes de una versión a otra). versión, pero resumido en un gran cambio). Estos son los resultados de esa prueba:

ember-observer-2.18-3.18.pdf

Podemos ver en estos resultados que hay dos saltos bastante definitivos:

  1. Ember 3.0 a Ember 3.1
  2. Ember 3.16 a Ember 3.17

La regresión en 3.17 se debe a la actualización de Glimmer VM, y actualmente nos estamos enfocando en reducir eso ya que es bastante reciente y probablemente comenzará a afectar las aplicaciones que se actualizan en el ciclo LTS pronto.

La regresión en 3.1 se conocía realmente en ese momento, tras una discusión con el equipo central. Fue causado, en parte, al habilitar captadores nativos y usar Object.defineProperty . Se consideró una regresión aceptable para permitir que el marco avanzara con nuevas funciones del navegador.

En general, el escenario {{each}} que se planteó al comienzo de este número parece haber retrocedido más y de diferentes maneras que emberobserver.com. Una vez que hayamos profundizado en la regresión 3.17, nos centraremos en optimizar {{each}} para ver qué se puede mejorar allí en general.

¡Gracias a todos por su paciencia!

¿Podemos obtener una actualización sobre este tema? Han pasado unos dos meses.

¡Si! Han sido dos largos meses, hemos estado trabajando duro en este problema y en la continuación de nuestros refactores en el Glimmer VM, que encajó muy bien con esto.

Como mencioné antes, nos estábamos enfocando en dos conjuntos separados de correcciones:

  1. Los refactores de bajo riesgo aterrizarán en la versión 3.20 LTS, para las personas que intentan actualizar a la próxima LTS
  2. Refactores a mayor escala para aterrizar en el maestro, para mejorar el rendimiento a largo plazo

Para el primer conjunto de correcciones, refactorizamos una cantidad decente de código clásico de Ember, ya que fue el código que se vio más afectado. De esta manera, pudimos reducir la pérdida de rendimiento general de 3.16-3.20 a cantidades estadísticamente insignificantes, según las pruebas en nuestras aplicaciones internas en LinkedIn. Desafortunadamente, no he tenido la oportunidad de ejecutar las pruebas contra Ember Observer, pero creo que sería un resultado similar, ya que generalmente se rastrean muy de cerca.

Para el segundo conjunto de correcciones, las hemos obtenido hace relativamente poco tiempo, ya que muchas de ellas eran muy grandes, entre ellas:

  • Actualizar la máquina virtual para que se base completamente en el seguimiento automático internamente, eliminando el exceso de etiquetas
  • Refactorizar la máquina virtual para usar una sola clase de referencia monomórfica, en lugar de muchas implementaciones con mucha complejidad
  • Eliminación del modo de compilación AoT no utilizado

¡Los resultados son bastante buenos!

resultados.pdf

Esto está comparando el maestro actual de Ember con Ember 2.18, con la reproducción anterior de @barisnisanci. Ahora, como se mencionó anteriormente, este es un punto de referencia para un caso de uso muy específico, que también es demasiado simple. _No_ vimos una mejora tan espectacular en ninguno de nuestros puntos de referencia de aplicaciones del mundo real, fue mucho más modesto en general. ¡Esperamos que esto ayude a @barisnisanci y a otras aplicaciones y definitivamente estamos interesados ​​en saber de ellos!

Repo probado

También probado en nuestra producción con diferentes versiones de brasas. La rama maestra parece% 25 a% 40 más lenta que 3.12 en nuestra aplicación. Con los resultados a continuación, no podemos actualizar ember sin una refactorización importante.

perf

@barisnisanci ¡ Lo siento, ese parece ser el caso! Como mencioné antes en este hilo, vamos a necesitar reproducir estos resultados de una manera estadísticamente sólida para poder A. confirmar el problema y B. iterar hacia mejoras y una mejor solución en general. Recomiendo agregar TracerBench a su aplicación para que pueda ejecutar estos puntos de referencia usted mismo, o hacer otra reproducción que demuestre el problema ahora en master .

¿Fue útil esta página
0 / 5 - 0 calificaciones