Ember.js: Perte de performances entre les versions 2.X et 3.X

Créé le 14 mai 2020  ·  28Commentaires  ·  Source: emberjs/ember.js

Il y a une perte de performances de 60% entre les versions 2.X et 3.X. Voir les journaux de temps de rendu ci-dessous des violons dans différentes versions. Exemples simplifiés pour démontrer les performances de rendu pures sans style ni calculs.

2.18 temps de rendu du
3.18 temps de rendu du

Bug Regression Rendering

Commentaire le plus utile

Je voulais juste faire une mise à jour rapide à ce sujet:

Nous avons exécuté un test TracerBench similaire à celui que @runspired a mis en place avec emberobserver.com , qui est l'une de nos applications de test habituelles, pour voir s'il y avait eu une ébullition de grenouille (par exemple, de petits changements de performance insignifiants d'une version à l'autre). version, mais résumée à un grand décalage). Voici les résultats de ce test:

ember-observer-2.18-3.18.pdf

Nous pouvons voir à partir de ces résultats qu'il y a deux sauts assez définitifs:

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

La régression dans la version 3.17 est due à la mise à niveau de Glimmer VM, et nous nous concentrons actuellement sur la réduction car elle est assez récente et commencera probablement à affecter les applications qui se mettent à jour sur le cycle LTS bientôt.

La régression en 3.1 était en fait connue à l'époque, après discussion avec l'équipe principale. Cela a été causé, en partie, par l'activation des getters natifs et l'utilisation de Object.defineProperty . Il a été considéré comme une régression acceptable pour permettre au cadre d'avancer avec les nouvelles fonctionnalités du navigateur.

En général, le scénario {{each}} qui a été soulevé au début de ce numéro semble avoir régressé davantage et de différentes manières que emberobserver.com. Une fois que nous aurons creusé la régression 3.17, nous nous concentrerons sur l'optimisation de {{each}} pour voir ce qui peut être amélioré en général.

Merci à tous pour votre patience!

Tous les 28 commentaires

Après quelques exécutions dans Chrome 81 sur ma machine, j'ai obtenu:

2.18 meilleur temps: 283ms
3.18 meilleur temps: 471ms

C'était l'exécuter avec les DevTools fermés.

Ensuite, j'ai converti le twiddle 3.18 en Ember Octane en:

  • Utilisation de classes natives pour les composants et les contrôleurs.
  • En utilisant @tracked sans utiliser @computed .
  • Conversion du composant t-r en un composant uniquement modèle car il n'avait pas besoin d'une classe de sauvegarde.
  • Utilisation de la syntaxe des crochets angulaires lors de l'appel de composants.
  • Utilisation d'arguments nommés et this. cas échéant dans les modèles.

Après cela, le meilleur temps que j'ai obtenu de 3.18.1 était de 276ms, donc une amélioration significative en ligne avec le nombre 2.18.

Ces tests de performances n'étaient cependant pas particulièrement scientifiques, et je n'ai pas recherché quel changement était le plus important en termes de performances.

Le profilage dans un twiddle est assez sujet aux erreurs, pouvons-nous effectuer un portage vers un référentiel d'applications ember-cli normal (en utilisant une branche pour chacune des deux versions) pour profiler?

@rwjblue J'obtiens les mêmes résultats sur une application ember-cli normale. Peut être testé ici

@ richard-viney Il peut y avoir des améliorations à considérer mais le problème est qu'aucun code obsolète utilisé dans les deux versions et subissant une perte de performances ne semble inacceptable.

  • L'utilisation d'un composant uniquement modèle peut entraîner une amélioration des performances, mais tr aura certainement besoin d'une classe de sauvegarde pour calculer certains styles internes. L'exemple a été simplifié pour illustrer le problème.
  • Avec tout le refactoring, vous obtenez un gain de performance de 2% (283 ms -> 276 ms) contre 2,18. Envisagez une mise à niveau d'application 2.18 existante vers 3.X. Refactoriser tous les composants juste pour obtenir cette augmentation de 2% n'est certainement pas possible.

@barisnisanci D'accord, je ne voulais pas suggérer que ce type de refactoring devrait être nécessaire afin d'éviter des régressions de performances significatives lors de la mise à niveau. C'était une expérience pour voir si l'utilisation des conventions modernes avait un impact, car cela pourrait aider à isoler le problème et / ou à le contourner si nécessaire.

Il serait intéressant de savoir quelle (s) version (s) d'Ember a introduit la régression des performances en testant également les versions LTS intermédiaires, à savoir 3.4, 3.8, 3.12 et 3.16.

@barisnisanci Ember Twiddle et ember serve s'exécutent en mode développement par défaut. Pendant le développement, de nombreux outils supplémentaires sont activés, ce qui peut sérieusement régresser les performances. Nous ne considérons généralement pas cela comme une régression ou un problème, à moins que ce ne soit suffisamment grave pour affecter l'ergonomie du développeur. Alors tout d'abord, je vérifierais que vous exécutez les deux versions en mode production.

J'ai téléchargé votre exemple et servi les versions 2.8 et 3.18 côte à côte en mode production. Ce que j'ai trouvé, c'est qu'il semble que vous ayez peut-être raison, en moyenne le temps entre les deux opérations d'assistance (ce qui est mesuré ici) semble plus grand en 3.18 qu'il ne l'était en 2.8. Cela est basé sur le fait que j'ai pris quelques échantillons sur mon ordinateur portable de travail sans beaucoup de contrôles, donc c'est difficile à dire avec certitude, mais en regardant cela, cela pourrait être un léger changement.

Cependant, en regardant d'autres mesures plus significatives, je ne vois pas de changement. En ce qui concerne spécifiquement le temps global de rendu du contenu, ils se ressemblent en général. Le temps de la première peinture est à peu près le même, par exemple.

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

Il est important de garder à l'esprit que nous avons beaucoup de travail réparti dans de nombreux endroits, et lorsque nous apportons des modifications, parfois ce travail se déplace mais n'affecte pas les métriques _dans l'ensemble_. C'est pourquoi nous utilisons TracerBench pour vérifier les changements de performances, car il est conçu pour prendre en compte les phases globales du rendu et pour tenir compte de tous les changements au niveau _macro_, plutôt qu'au niveau _micro_, comme le timing entre les helpers en cours d'exécution.

Nous devrions probablement essayer de faire un test TracerBench bientôt sur une période plus longue, juste pour vérifier ces résultats et pour nous assurer que nous n'avons pas glissé en général (nous l'utilisons généralement pour des changements plus petits où nous nous attendons à des régressions potentielles). Nous devrions également simplement essayer de le faire fonctionner à intervalles réguliers, afin que nous puissions voir la ligne de tendance.

@pzuraq Je le dépôt avec rowsCount:300 et la différence columnsCount:20 devrait être plus visible maintenant. Les deux fonctionnent avec --environment production

  • 3.18 Première peinture: 3489 ms
    3 18
  • 2.18 Première peinture: 2814 ms
    2 18

A également remarqué que JS Heap n'est jamais sorti en 3.18 mais peut-être un peu de malchance sur GC.

Je peux ajouter des liaisons de style, des injections de service, des calculs plus lourds sur les composants au lieu d'augmenter le nombre, mais ils peuvent masquer le problème sous-jacent.

Tout comme vous l'avez mentionné, les mesures globales sont bien plus importantes que les changements mineurs. Cependant, des différences mineures s'ajoutent à une baisse de performance majeure dans notre cas. Le temps de rendu initial de notre application commerciale est passé de 15 secondes à 20 secondes après la mise à niveau vers la version 3.18. J'espère que vous envisagerez la régression en termes de pourcentage plutôt que de légers changements en millisecondes.

Notre entreprise souffre de ce problème. Nous avons mis à jour la version de braise de 2.18 à 3.16. alors nos temps de rendu sont devenus plus longs que «50» pour cent. Lorsque nous utilisons des structures compliquées, la différence entre les temps de rendu est devenue plus évidente plutôt que de légers changements en millisecondes. Des mises à jour sur ce problème? Nous avons des benchmarks montrant une augmentation de 50% du temps de rendu. Décidé de conserver 2.18 pour le moment. Nous pouvons envisager de changer de framework si cela nécessite un refactor majeur.

@ Caglayan06 Pouvez-vous confirmer que vous utilisez le drapeau de production? Je veux juste vous assurer que les chiffres sont des pommes aux pommes!

@ Caglayan06 - Il est peu probable que ce soit une seule chose. La reproduction fournie par @barisnisanci peut ne pas correspondre à ce que montre le profil de votre application. Pouvez-vous fournir une reproduction du problème général dans votre application (ou confirmer que l'exemple de dépôt de

Avez-vous des commentaires sur le dernier message de @barisnisanci dans ce fil?
Nous avons eu des problèmes de performances similaires après la mise à niveau de 2.18 à 3.16. Nous avons eu une perte de performance de 40%. Nous avons rétrogradé à 3,12 mais n'avons réussi à économiser que 20% de cette perte, encore loin d'être aussi bonne que 2,18. La refactorisation de la manière dont vous l'avez mentionné précédemment prend presque autant de temps que le changement de framework. Doit-on s'attendre à des actions sur cette question?

Récemment, nous avons mis à niveau vers la version 3.16.8 de ember, nous n'avons pas de cas de test de perf et ne trouvons pas de problème de performance évident pour le moment.
mais j'aimerais avoir hâte de résoudre et de clôturer les problèmes de performances dès que possible.
>

PS : plus de mémoire et de processeur utilisés dans ie11. parfois, cela provoque le crash de ie11.

@ Caglayan06 - Il est peu probable que ce soit une seule chose. La reproduction fournie par @barisnisanci peut ne pas correspondre à ce que montre le profil de votre application. Pouvez-vous fournir une reproduction du problème général dans votre application (ou confirmer que l'exemple de dépôt de

L' exemple de @rwjblue @barisnisanci fonctionne de la même manière pour moi que dit @barisnisanci .

@ Caglayan06 Pouvez-vous confirmer que vous utilisez le drapeau de production? Je veux juste vous assurer que les chiffres sont des pommes aux pommes!

@scottmessinger oui, nous fonctionnons avec l'indicateur de production. Nos résultats sont similaires aux résultats de @barisnisanci .

Nous avons amélioré notre structure de code. Cela a augmenté les performances Mais ce n'est toujours pas rapide avec la version 2.18 de décembre. Si nous apportons ces modifications dans la version 2.18, nous avons obtenu les meilleurs résultats.

Nous ne pouvons pas refondre notre système de code pour changer la syntaxe du code 3.16 et les nouvelles fonctionnalités. C'est trop coûteux pour nous, car notre projet est énorme. Refactoriser tous les projets est probablement plus coûteux que de changer de cadre. Des mesures seront-elles prises pour résoudre ce problème?

Des mesures seront-elles prises pour résoudre ce problème?

Oui bien sûr! Nous avons juste besoin de trouver le temps de profiler et de comprendre ce qui se passe. Mais cela n'a pas vraiment besoin d'attendre personne, mais vous creusez 😸

L' exemple de @rwjblue @barisnisanci fonctionne de la même manière pour moi que dit @barisnisanci .

@ Caglayan06 - Hmm, ce n'est pas vraiment ce que j'ai demandé. Je sais que l'exemple de @ barisnisanci fonctionne, je vous demande de le revoir / de le profiler / de comparer les caractéristiques de performance à votre application et de voir si le _way_ que l'exemple fonctionne (et est plus lent) correspond à votre application.

@ Caglayan06 - Hmm, ce n'est pas vraiment ce que j'ai demandé. Je sais que l'exemple de @ barisnisanci fonctionne, je vous demande de le revoir / de le profiler / de comparer les caractéristiques de performance à votre application et de voir si le _way_ que l'exemple fonctionne (et est plus lent) correspond à votre application.

@rwjblue J'ai intégré le repo de @barisnisanci à notre application, cela a donné des résultats similaires. Lorsque nous changeons de version de 3.16 à 3.12, nos performances ont été améliorées.
Mais toujours pas rapide en version 2.18.

Dans notre application pour quelques exemples:
2977

Par conséquent:
Même nous avons amélioré la structure du code, les temps de rendu moyens totaux;
2.18 temps de rendu: 1x sec
3.16 temps de rendu: 1,6x sec.
3.12 temps de rendu: 1,4x sec.

3.20 a une mise à jour de VM, donc je me demande si cela aiderait ici

@NullVoxPopuli n'a pas eu de chance avec 3.20.0-beta.2 FP: 3.4 secondes (idem avec 3.18)

Depuis 3.12 montre de meilleurs résultats, je pense que le problème peut être introduit avec le suivi automatique. Le # 18225 pourrait également être lié compte tenu de la baisse des performances de l'application dans les benchmarks 3.12 -> 3.16 de

Hm. Je me demande combien il y a de frais généraux pour les trucs de compatibilité arrière

Quelques questions générales:

  • Quelle est la valeur de l'indicateur de fonctionnalité optionnelle Async Observer?
  • L'application en question utilise-t-elle des QP?
  • La vitesse négative affecte-t-elle toutes les routes ou seulement certaines?

Quelques questions générales:

  • Quelle est la valeur de l'indicateur de fonctionnalité optionnelle Async Observer?
  • L'application en question utilise-t-elle des QP?
  • La vitesse négative affecte-t-elle toutes les routes ou seulement certaines?

@rwjblue

  1. Ne pas utiliser le drapeau des observateurs asynchrones Je pense que la valeur par défaut est fausse sur 3.12. Sur 3.16 Testé avec les deux ne fait pas beaucoup de différence.
  2. QP largement utilisé sur les routes principales. Cependant baisse de performance observée même sans aucun.
  3. Tous les itinéraires sont affectés

De plus, le référentiel d'exemple n'utilise aucun des éléments ci-dessus, mais reste plus lent dans 3.X. Les temps de rendu peuvent avoir augmenté progressivement dans chaque version mineure, nous ne pouvons donc pas identifier le problème exact.

Tracerbench rapporte que 2,18 à 3,18 régresse d'environ 17% pour ce scénario, mais s'améliore également au lieu de régresser d'environ 18% si une conversion en composant Glimmer est effectuée.

2.18 à 3.18 Aucun autre changement
2.18 à 3.18 + Octane + Composants Glimmer

J'ai mon propre fork où j'ai ajouté un runner automatisé pour cela, et je travaille pour améliorer le runner afin que nous puissions rapidement affiner par version / commit pour trouver où la ou les régression (s) s'est produite. https://github.com/runspired/version-performance/runs/801596557

Un grand merci à @runspired pour avoir mis en place ces tests! Maintenant que nous avons une configuration solide pour mesurer de manière fiable la régression, nous pouvons itérer pour résoudre ces problèmes.

Pour le contexte, @krisselden a développé TracerBench en tant qu'outil spécifiquement pour tester les performances de manière holistique, et nous l'avons utilisé pour des refactors majeurs en interne tels que la mise en œuvre de décorateurs et le suivi automatique / suivi des révisions . Chez LinkedIn, nous l'utilisons pour tester nos applications avant chaque mise à niveau d'Ember, et nous n'avons pas vu ce niveau de régression.

Cependant, cela pourrait certainement être quelque chose que nous avons manqué. En fin de compte, nous testons des applications spécifiques, qui ont des cas d'utilisation et des comportements spécifiques. Cela pourrait être un problème que nous n'avons pas détecté car nos applications de cas de test n'utilisaient pas les fonctionnalités qui ont régressé, comme la reproduction de @barisnisanci . Il est également possible que même si nous résolvions les problèmes de cette reproduction, nous ne puissions pas résoudre les autres, donc si vous rencontrez des régressions, nous apprécierions certainement les reproductions pour votre cas d'utilisation. Nous travaillerons à rendre la configuration de TracerBench plus facile à utiliser afin que vous puissiez la tester localement et soumettre une repro comme celle de @runspired .

Nous allons creuser pour déterminer quel est le problème exact et trouver une solution. Plus important encore, ce niveau de régression n'est pas acceptable pour _any_ API, même si nous constatons une accélération avec Octane. Si les utilisateurs ne peuvent pas mettre à niveau et changer progressivement, nous ne grimperons pas tous ensemble.

Restez à l'écoute pour plus de mises à jour, nous vous tiendrons au courant au fur et à mesure que nous découvrirons les choses!

Un grand merci à @runspired pour son super cool https://github.com/TracerBench/tracerbench-compare-action

Je voulais juste faire une mise à jour rapide à ce sujet:

Nous avons exécuté un test TracerBench similaire à celui que @runspired a mis en place avec emberobserver.com , qui est l'une de nos applications de test habituelles, pour voir s'il y avait eu une ébullition de grenouille (par exemple, de petits changements de performance insignifiants d'une version à l'autre). version, mais résumée à un grand décalage). Voici les résultats de ce test:

ember-observer-2.18-3.18.pdf

Nous pouvons voir à partir de ces résultats qu'il y a deux sauts assez définitifs:

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

La régression dans la version 3.17 est due à la mise à niveau de Glimmer VM, et nous nous concentrons actuellement sur la réduction car elle est assez récente et commencera probablement à affecter les applications qui se mettent à jour sur le cycle LTS bientôt.

La régression en 3.1 était en fait connue à l'époque, après discussion avec l'équipe principale. Cela a été causé, en partie, par l'activation des getters natifs et l'utilisation de Object.defineProperty . Il a été considéré comme une régression acceptable pour permettre au cadre d'avancer avec les nouvelles fonctionnalités du navigateur.

En général, le scénario {{each}} qui a été soulevé au début de ce numéro semble avoir régressé davantage et de différentes manières que emberobserver.com. Une fois que nous aurons creusé la régression 3.17, nous nous concentrerons sur l'optimisation de {{each}} pour voir ce qui peut être amélioré en général.

Merci à tous pour votre patience!

Pouvons-nous avoir une mise à jour sur ce problème? Cela fait environ deux mois.

Oui! Cela fait deux mois, nous avons travaillé dur sur ce problème et dans la poursuite de nos refactors dans la machine virtuelle Glimmer, ce qui a bien suivi.

Comme je l'ai mentionné précédemment, nous nous sommes concentrés sur deux ensembles distincts de correctifs:

  1. Les refacteurs à faible risque débarqueront dans la version 3.20 LTS, pour les personnes essayant de passer à la prochaine LTS
  2. Réfracteurs à plus grande échelle pour atterrir sur le maître, pour améliorer les performances à plus long terme

Pour le premier ensemble de correctifs, nous avons remanié une quantité décente de code Ember classique, car c'était le code qui était le plus affecté. Nous avons pu réduire la perte de performance globale de 3,16-3,20 à des montants statistiquement insignifiants de cette façon, sur la base de tests dans nos applications internes chez LinkedIn. Je n'ai malheureusement pas eu l'occasion d'exécuter les tests contre Ember Observer, mais je pense que ce serait un résultat similaire car ils suivent généralement assez étroitement ensemble.

Pour le deuxième ensemble de correctifs, nous les avons récemment trouvés car beaucoup d'entre eux étaient très volumineux, notamment:

  • Mettre à jour la machine virtuelle pour qu'elle soit entièrement basée sur le suivi automatique en interne, en éliminant les balises en excès
  • Refactoriser la machine virtuelle pour utiliser une seule classe de référence monomorphe, plutôt que de nombreuses implémentations avec beaucoup de complexité
  • Suppression du mode de compilation AoT inutilisé

Les résultats sont plutôt bons!

results.pdf

Ceci compare le maître actuel d'Ember à Ember 2.18, avec la reproduction ci-dessus de @barisnisanci. Maintenant, comme mentionné précédemment, il s'agit d'une référence pour un cas d'utilisation très spécifique, qui est également trop simple. Nous n'avons _pas_ vu une amélioration aussi spectaculaire dans aucun de nos benchmarks d'applications du monde réel, c'était beaucoup plus modeste dans l'ensemble. J'espère que cela aidera @barisnisanci et les autres applications et nous sommes vraiment intéressés à en entendre parler!

Testé repo ci-dessus avec la branche principale de braise. Still First Paint: (3035,7 ms) semble supérieur à 2,18 (2752,3 ms)

Également testé sur notre production avec différentes versions de braise. La branche principale semble% 25 à% 40 plus lente que 3.12 sur notre application. Avec les résultats ci-dessous, nous ne pouvons pas mettre à jour braise sans refactoring majeur.

perf

@barisnisanci Désolé, cela semble être le cas! Comme je l'ai mentionné précédemment dans ce fil, nous allons devoir reproduire ces résultats de manière statistiquement valable afin de pouvoir A. confirmer le problème et B. itérer vers des améliorations et une meilleure solution globale. Je recommande soit d'ajouter TracerBench à votre application afin que vous puissiez exécuter ces tests vous-même, soit de faire une autre reproduction qui démontre le problème maintenant sur master .

Cette page vous a été utile?
0 / 5 - 0 notes