Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Industrial Internet of Things >> Embarqué

Comment garantir les meilleures performances de la machine d'état Qt

Si vous utilisez Qt pour le développement d'applications et si vous utilisez des machines à états, il est probable que vous utilisiez le framework de machines à états Qt. Vous allez donc définir la machine d'état en utilisant C++ ou SCXML. Une approche alternative consiste à générer du code C++ à partir de diagrammes de machines à états. Cet article compare ces approches, en tenant compte des fonctionnalités, de l'applicabilité et des performances.

Je parie qu'en tant que développeur de logiciels, vous avez déjà implémenté des tonnes d'instructions switch-case plus ou moins compliquées. C'est du moins vrai pour moi, et une grande partie de ce codage de boîtier de commutation n'était essentiellement rien d'autre que la mise en œuvre de diverses machines à états. C'est le moyen le plus simple de commencer à programmer des machines à états si vous n'avez rien d'autre sous la main que le langage de programmation de votre choix. Alors que le démarrage est facile, un tel code devient de moins en moins maintenable à mesure que la complexité de la machine d'état augmente. À la fin, vous serez convaincu que vous ne voulez pas continuer à implémenter les machines d'état manuellement de cette façon. (Au fait, je suppose que vous savez ce que sont les machines à états.)

Implémentation de machines à états

Il existe différentes alternatives pour implémenter des machines à états. L'un des meilleurs moyens, en particulier lorsque vous utilisez un langage de programmation orienté objet comme C++, consiste à appliquer le modèle d'état. Cette approche utilise des classes d'état et souvent aussi des classes de transition. Une machine à états est ensuite définie en créant des instances de classes d'états et en les connectant à l'aide d'instances de classes de transition. Dans ce cas, un framework aide beaucoup à réduire la taille du code et l'effort de mise en œuvre.

Le framework de machine à états Qt est un bon exemple. Cette API vous permet de « configurer » une machine d'état à l'aide d'un code compact. Vous n'avez pas à vous soucier des détails de la sémantique d'exécution de la machine à états, car ceux-ci sont déjà implémentés par le framework. Vous devez toujours écrire du code, et comme votre machine d'état devient plus complexe et contient des dizaines voire des centaines d'états, il deviendra vraiment difficile d'avoir une vue d'ensemble. Une image vaut mille mots, et le concept bien connu de diagramme d'états permet de s'affranchir de cette contrainte. Qt lui-même prend en charge le State Chart XML (SCXML), qui est une norme W3C. Comme écrire du XML à la main n'est pas amusant,Qt Creator comprend également un simple éditeur de diagramme d'états transitions.

Quelle que soit l'approche d'implémentation concrète, l'utilisation d'une syntaxe graphique est le meilleur choix pour éditer et comprendre les machines à états. De tels modèles graphiques peuvent non seulement être représentés textuellement par des langages tels que SCXML, mais peuvent également être utilisés pour générer tout type de code source de langage de programmation, comme une machine d'état basée sur le cas de commutation en C++ simple - ou du code C++ qui configure des instances de QStateMachine. En utilisant un outil qui effectue une telle transformation pour vous, vous pouvez éviter d'avoir à écrire manuellement le code de la machine d'état. Il élève les trois approches de mise en œuvre au même niveau de convivialité. Néanmoins, les implémentations sont encore fondamentalement différentes. Cet article a pour but de comparer leur comportement à l'exécution et surtout leurs performances.


UnsplashPhoto par Austris Augusts sur Unsplash

Les concurrents

Et les performances alors ? En quoi les approches disponibles diffèrent-elles en ce qui concerne les cycles CPU requis ? Pour obtenir des chiffres concrets, j'ai mis en place une suite de tests de performances. La première partie compare les différentes stratégies de mise en œuvre. Voici les concurrents :

  1. Interpréteur SCXML - la machine d'état de test est définie à l'aide de SCXML et exécutée par la QSCXMLStateMachine de Qt classe.
  2. Modèle d'état - la machine d'état de test est implémentée à l'aide de QStateMachine cours.
  3. Code C++ simple :la machine d'état de test est implémentée par une classe C++ qui applique une approche de base basée sur les cas de commutation.

Remarque :Le code de ces exemples peut être trouvé ici.

Les deux premières variantes impliquent l'utilisation de concepts Qt comme les signaux et les slots ainsi que l'utilisation d'une file d'attente d'événements Qt, tandis qu'une implémentation C++ simple ne nécessite pas cette infrastructure. Afin de rendre les approches plus comparables, la suite de tests comprend deux scénarios de test supplémentaires :

Cela permet de comparer l'impact de l'utilisation des signaux et slots d'une part et l'utilisation des QEvents d'autre part par rapport à l'implémentation C++ simple, puisque le code d'exécution de la machine à états est identique dans tous les cas, mais juste enveloppé différemment.

La machine à états de test

Pour tester les cinq concurrents, j'ai défini la machine d'état illustrée à la fig. 1 pour le scénario de test de base.


Figure 1 :La machine d'état de test, telle que créée avec YAKINDU Statechart Tools. (Source :auteur)

La machine à états de test est une simple machine à états plats. Il définit six états A à F et parcourt les états. Deux événements d'entrée e1 et e2 sont définis, qui déclenchent alternativement des transitions d'état. Lorsqu'une transition d'état a lieu, une action simple est également exécutée. Chaque action de transition ajoute simplement 10 à une variable de diagramme d'états transitions nommée x . Le passage de l'état F à A augmente (ou émet) en plus le out événement o .


Figure 2 :La machine à états de test en tant que modèle SCXML dans Qt Creator. (Source :auteur)

Cette machine d'état a été définie à l'aide de YAKINDU Statechart Tools, qui prend en charge la génération de SCXML. Ce SCXML peut être ajouté au projet Qt et peut être modifié dans Qt Creator. Comme vous pouvez le voir sur la fig. 2, la machine d'état a la même structure que celle de la fig. 1, mais certains détails, comme les actions de transition, ne sont pas visibles dans Qt Creator. YAKINDU Statechart Tools offre d'autres avantages, mais je n'en parlerai pas ici.

Plus important ici est le fait que YAKINDU Statechart Tools peut également générer des classes de machines à états C++ basées sur des commutateurs simples. Il fournit également une option pour générer des classes compatibles Qt avec des signaux et des slots, donc cela est pratique. En utilisant cet outil, je n'ai eu qu'à implémenter la machine à états basée sur un modèle d'état à l'aide de QStateMachine par la main. Il n'y avait pas de générateur de code disponible pour cette variante. Néanmoins, j'ai pu économiser beaucoup d'efforts d'implémentation, tout en obtenant des machines à états sémantiquement équivalentes pour les tests de performances en utilisant simplement une seule définition de diagramme d'états.

Tous les cas de test suivent le même schéma. Comme je voulais mesurer le temps moyen nécessaire pour traiter des événements individuels, chaque test a capturé un million d'itérations d'une seule boucle d'état. Chaque boucle d'état exécute tous les événements nécessaires pour visiter tous les états et traiter toutes les transitions et actions de transition. Ainsi, une boucle d'état commence et se termine par l'état A être actif. Cela signifie que pour chaque cas de test 6 millions in événements et actions de transition et 1 million de out les événements avec leurs actions de transition associées sont traités. Les tests ont été exécutés en tant qu'application en ligne de commande et ont enregistré le temps des itérations en un seul lot. La consommation de temps par événement peut alors être simplement déterminée en divisant le temps mesuré par la somme du nombre de in événements et sorties événements. Les tests ont été effectués plusieurs fois et les résultats de mesure avec les valeurs les plus faibles ont été choisis.

Les tests ont été effectués à l'aide d'un code optimisé sans informations de débogage sur mon ancien MacBook Pro (mi-2014), avec un processeur Core i7 Quad Core 2,4 GHz. Bien sûr, les chiffres concrets différeront selon les machines et les systèmes d'exploitation. Cependant, cela n'est pas pertinent, car je voulais comparer les différentes approches de mise en œuvre les unes par rapport aux autres. Ces différences relatives seront comparables sur différentes plates-formes matérielles et OS.

Regardons les chiffres de performance

Oui - je pense que presque tout le monde se serait attendu à ce qu'une implémentation C++ simple soit plus rapide que les autres alternatives, mais l'ampleur des différences est vraiment étonnante.


Figure 3 : temps de traitement d'un événement unique comparé. (Source :auteur)

Le traitement d'événements uniques à l'aide de C++ simple a pris en moyenne 7 nanosecondes. L'utilisation de SCXML a nécessité 33 850 nanosecondes – c'est un facteur d'environ 4 800 et une énorme différence ! À titre de comparaison, la lumière parcourt plus de 10 kilomètres alors que la machine à états SCXML ne traite qu'une seule transition, tandis que la même transition dans la machine à états C++ simple ne laisse que peu de temps à la lumière pour parcourir un peu plus de 2 mètres. Cela implique des ordres de grandeurs très différents pour les cycles CPU et la consommation d'énergie.

Bien entendu, les chiffres concrets dépendent de la machine et de la procédure de test utilisée. J'aborderai ce sujet plus tard. Mais parlons d'abord des autres chiffres. Les trois premiers scénarios de test incluent tous une logique de transition d'état identique, qui a été générée par YAKINDU Statechart Tools, mais chacun enveloppé de différentes manières.

L'utilisation de signaux et de slots pour gérer les événements prenait en moyenne 72 ns lors de l'utilisation de connexions directes. Ce mécanisme impose donc une surcharge minimale d'environ 90 %, par rapport à la logique réelle de la machine à états. À ce stade, je ne veux pas prétendre que l'utilisation de signaux et de slots ralentit les applications. Au lieu de cela, je préférerais affirmer que les implémentations en code simple des machines à états sont extrêmement rapides .

La comparaison avec le troisième scénario donne une bonne impression de la surcharge de performances causée par l'utilisation de la file d'attente d'événements. Dans ce scénario, tous les événements de diagramme d'états transitions sont acheminés via la file d'attente d'événements. Avec 731 ns par événement, il faut un facteur d'environ 10 par rapport aux signaux et aux slots et d'environ 100 par rapport au C++ ordinaire.

Nous pouvons supposer qu'un surcoût comparable s'applique également aux deux autres scénarios "plain QStateMachine " et " SCXML state machine " - ils nécessitent tous deux une file d'attente d'événements active. Ainsi, lorsque la surcharge supposée de la file d'attente d'événements est soustraite des 5200 ns par événement, nous obtenons une consommation approximative de la QStateMachine cadre de 4500ns par événement. Par rapport à l'approche du code simple, les implémentations de machines à états basées sur QStateMachine sont lentes. Il s'agit d'un facteur d'environ 635, par rapport à l'implémentation du code C++ simple.

Enfin, jetons un coup d'œil à l'interpréteur SCXML. Cela implique l'interprétation du code JavaScript et ajoute un autre facteur de ~7. Par rapport à l'approche du code simple, les implémentations de machines à états basées sur SCXML sont très lentes.

Qu'en est-il des machines à états hiérarchiques et orthogonales ?

Jusqu'à présent, je viens de profiler une simple machine à états plats. Mais les diagrammes d'états transitions offrent beaucoup plus de fonctionnalités, et les deux caractéristiques structurelles les plus importantes sont la hiérarchie et l'orthogonalité. Alors, quel impact l'utilisation de ces fonctionnalités a-t-elle sur le temps d'exécution de la machine à états ?

Dans un premier temps, pour mesurer l'impact des hiérarchies, j'ai défini une variante hiérarchique de la machine d'état à profiler, représentée sur la fig. 4.


Figure 4 :Diagramme d'états fonctionnels de test hiérarchique. (Source :auteur)

Il fournit exactement le même comportement que la machine à états plats, mais ajoute quelques états composites. Garder la fonctionnalité identique, mais juste changer la structure, permet de savoir combien de temps système la variante structurelle implique, le cas échéant.

Deuxièmement, afin de mesurer l'impact de l'orthogonalité, j'ai répliqué la machine à états plats sous la forme de quatre régions orthogonales. Ils ont tous exactement la même fonctionnalité. Ainsi, la machine d'état résultante (voir fig. 5) fera quatre fois plus de travail que la machine d'état simple.


Figure 5 :Diagramme d'états de test orthogonal. (Source :auteur)

Pour le profilage, j'ai choisi les implémentations C++ et SCXML, car il s'agissait des variantes les plus rapides et les plus lentes. Le schéma de la fig. 6 montre les résultats. Il est très encourageant de constater que l'utilisation de hiérarchies dans les diagrammes d'états transitions n'a pas d'impact mesurable sur les performances dans les deux variantes d'implémentation.


Figure 6 :Impact sur les performances des hiérarchies et de l'orthogonalité. (Source :auteur)

Un autre résultat positif est que l'utilisation de l'orthogonalité n'a pas non plus d'impact négatif. Au contraire, alors que l'on aurait pu s'attendre à au moins quatre fois le temps de traitement pour accomplir quatre fois le travail, les augmentations effectives du temps d'exécution avec des facteurs ~2,4 et ~3,1 sont nettement inférieures à 4.

pourquoi est-ce le cas? La raison en est qu'il existe une partie générale du traitement de la machine d'état qui est indépendante du traitement des états et des événements individuels. Cette partie prend 52 % (ou 3,5 ns par événement) pour la machine à états C++ simple, contre 28 % (ou 9 300 ns par événement) pour SCXML. Enfin, les états orthogonaux ont moins d'impact lors de l'utilisation de code C++ généré par rapport à SCXML.

Conclusion

Plain C++ est de loin plus efficace que toutes les alternatives. L'utilisation de signaux et de slots ou de la file d'attente d'événements Qt sont des mécanismes de framework facilitant la mise en œuvre et la maintenance d'applications de machine à états complexes. Le framework de machine à états Qt requiert ces deux mécanismes. En utilisant du code C++ généré, vous avez le choix.

Dans de nombreux scénarios, en particulier ceux interactifs, même les machines d'état SCXML sont assez rapides, et elles peuvent offrir plus de flexibilité en rendant le comportement configurable en changeant les définitions de diagramme d'état au moment de l'exécution.


Embarqué

  1. Comment choisir le meilleur logiciel de CAO de conception de bijoux
  2. Les meilleures marques de CNC
  3. Comment choisir la bonne machine CNC
  4. Comment garantir la préparation aux urgences dans l'entrepôt
  5. Comment suivre la performance du personnel technique ?
  6. Comment choisir le meilleur frein pour éolienne
  7. Comment choisir la bonne machine d'encartonnage
  8. Comment choisir la bonne machine de découpe au jet d'eau
  9. Comment choisir la meilleure plieuse de tôle