Suggestions de conception d’applications de base de haut niveau
Pour créer une application de base de haut niveau (HL) sur des bases solides, vous devez utiliser les meilleures pratiques fondamentales. Les éléments suivants sont les plus pertinents :
Les applications principales de haut niveau (HL) s’exécutent en conteneur sur le système d’exploitation Azure Sphere. Au cours des révisions de code et de conception des solutions des clients, nous avons détecté plusieurs problèmes typiques avec les applications HL-core. Cette rubrique présente des suggestions d’amélioration de la conception pour résoudre ces problèmes.
Principes de base généraux
Pour créer une application HL-Core sur des bases solides, vous devez utiliser les meilleures pratiques fondamentales. Les éléments suivants sont les plus pertinents :
- Initialisation et arrêt : Veillez toujours à gérer le signal SIGTERM du système d’exploitation Azure Sphere, puis à initialiser et à détruire correctement tous les gestionnaires (tels que ceux des périphériques) à la sortie, en cas de plantage ou d’erreur. Pour plus d’informations, consultez Initialisation et terminaison et la documentation GNU sur les signaux d’arrêt.
- Utilisez toujours les codes de sortie : S’assurer que l’application HL-core fournit toujours un code de retour significatif en cas de sortie ou de plantage (par exemple, à l’aide du gestionnaire SIGTERM) est essentiel pour diagnostiquer correctement le comportement de l’appareil, en particulier à partir des données de télémétrie de vidage sur incident de l’appareil. Pour plus d’informations, consultez Codes de sortie et Collecter et interpréter les données d’erreur.
-
Assurez-vous que les cas d’échec entraînent toujours une sortie ou un plantage de l’application plutôt que dans un état d’interblocage : Une logique de récupération d’échec élaborée peut être contre-productive, car elle peut introduire des bogues ou des comportements entraînant un interblocage ou un état difficile à diagnostiquer. Une application Azure Sphere bien conçue doit toujours préférer le blocage ou la sortie (avec un code de sortie différent de zéro) à une situation d’interblocage potentiel, car cela entraîne les deux :
- Télémétrie d’erreur, activation diagnostics pour ce problème
- Une chance de récupération immédiate à un état opérationnel, car le système d’exploitation Azure Sphere redémarre l’application
- Gestion et journalisation des erreurs : La gestion et la journalisation précises des erreurs sont au cœur du développement d’applications de qualité. Les implémentations de fonctionnalités rapides peuvent rester enfouies dans des couches de code, puis intégrées à mesure que l’application se développe jusqu’à la pleine échelle. Pour plus d’informations sur les meilleures pratiques, consultez Gestion et journalisation des erreurs.
- Utilisez un minuteur système en tant qu’agent de surveillance : L’une des meilleures pratiques les plus cruciales consiste à implémenter un rappel du « minuteur de surveillance » (tout comme les rappels matériels disponibles dans les unités mcu nues) qui effectue le suivi des états d’application critiques, en détectant les interblocages et en agissant en conséquence (par exemple, la sortie et l’envoi de données de télémétrie). Pour plus d’informations, consultez Utiliser un minuteur système en tant qu’agent de surveillance.
- Ne déployez jamais d’applications de production qui ont été créées en ciblant un ensemble d’outils de mise en production bêta : L’utilisation d’ensembles d’outils de version bêta n’est pas recommandée, car il n’est pas garanti que le sous-ensemble bêta ne change pas dans les versions suivantes du système d’exploitation. Les ensembles d’outils bêta sont publiés uniquement pour tester de nouvelles fonctionnalités avant une version officielle du SDK.
Gestion de l’accès concurrentiel
- Utilisez EventLoop dans la mesure du possible : Les threads et les objets de synchronisation (c’est-à-dire, mutex, sémaphores, etc.) sont utilisés pour accomplir des tâches presque simultanées, mais dans les systèmes incorporés, celles-ci sont coûteuses en termes d’utilisation des ressources système. Par conséquent, pour améliorer les performances, envisagez d’utiliser des epolls au lieu de threads, pour les tâches qui ne sont pas strictement critiques de temps et ne sont pas sensibles au blocage mutuel. Pour plus d’informations sur la façon de surveiller et de distribuer des événements avec EventLoop, consultez La page Eventloop eventloop.h, y compris les exemples associés.
- Recherchez l’efficacité des tâches simultanées : Il est important de s’assurer que les opérations de blocage et les délais d’expiration sont maintenus au minimum dans les rappels epoll, sinon tous les autres rappels epoll seront affectés.
- Quand utiliser des threads (pthread) : Pour des scénarios spécifiques, comme lorsque le blocage des appels est inévitable, l’utilisation de threads peut être bénéfique, bien que ces scénarios aient généralement une durée de vie limitée et doivent être limités à des tâches spécifiques. Par exemple, étant donné que le système d’exploitation Azure Sphere (exécutant Linux) n’expose pas de faq aux applications HL-core (disponible uniquement pour les applications RT-core), l’utilisation d’une combinaison de tâches epoll et pthread peut être optimale pour gérer, par exemple, une communication en série en aval lors du téléchargement de données à partir d’Internet.
Important
Le système d’exploitation Azure Sphere peut interrompre les opérations en temps opportun, en particulier lorsqu’il effectue l’attestation de l’appareil, la recherche de mises à jour ou le chargement de données de télémétrie. Pour les tâches de contrôle critiques, envisagez de les déplacer vers les cœurs M4 et de les coordonner avec un protocole approprié via la boîte aux lettres intercœurs. Pour plus d’informations, consultez l’exemple de communication intercœurs.
En plus de ces suggestions, consultez la documentation Azure Sphere sur les événements asynchrones et l’accès concurrentiel.
Surveillance de la connectivité
Une application de base de haut niveau (HL) bien conçue doit implémenter une tâche de vérification de l’intégrité de la connectivité appropriée, qui doit être basée sur un ordinateur d’état robuste qui vérifie régulièrement les status de la connexion Internet (pour instance, à l’aide d’un minuteur époll) en tirant parti de l’API Networking_IsNetworkingReady. Dans certains cas, vous pouvez utiliser la fonction Networking_GetInterfaceConnectionStatus, car elle fournit une status plus détaillée de l’état de connectivité lié à une interface réseau spécifique que l’application HL-core peut utiliser pour mieux traiter son état, même si cela a un coût, car il n’est pas recommandé de l’appeler plus fréquemment que toutes les 90 secondes.
Le rappel de la machine à états doit généralement avoir les attributs suivants :
- Exécutez aussi rapidement que possible.
- Son intervalle d’interrogation doit être soigneusement conçu, en fonction du scénario d’application spécifique et des exigences globales de la solution (telles que le temps constant, le délai incrémentiel, etc.).
- Une fois qu’une déconnexion est détectée, il peut être utile d’appeler Networking_GetInterfaceConnectionStatus une fois pour journaliser l’état de l’interface réseau spécifique, ce qui peut être utilisé pour diagnostiquer le problème et avertir l’utilisateur via une interface utilisateur (par exemple, LED, affichage, terminal). Vous trouverez un exemple de cette approche dans le code main de l’exemple DHCP Azure Sphere.
- Activez un mécanisme (par exemple, via une variable globale) qui arrête toutes les autres tâches de l’application HL-core qui effectuent (ou sont liées à) des communications réseau pour optimiser la consommation des ressources jusqu’à ce qu’une connexion soit rétablie.
- cURL a récemment mis à jour le comportement de rappel et les meilleures pratiques. Bien qu’Azure Sphere ait pris des mesures pour s’assurer que les versions antérieures du comportement de cURL continuent de fonctionner comme prévu, il est recommandé de suivre les dernières instructions en matière de sécurité et de fiabilité lors de l’utilisation de curl_multi, car l’utilisation de rappels récursifs peut entraîner des blocages inattendus, des pannes de connectivité et des failles de sécurité potentielles. Si un TimerCallback se déclenche avec un délai d’expiration de 0 ms, traitez-le comme un délai d’expiration de 1 ms pour éviter les rappels récursifs. Veillez également à appeler explicitement curl_multi_socket_action au moins une fois après les appels à curl_multi_add_handle.
Outre les suggestions précédentes, vous devez envisager les scénarios suivants pour la gestion de l’alimentation :
- Mettez la puce Azure Sphere hors tension après l’envoi de données. Pour plus d’informations, consultez Gérer l’état de mise hors tension pour les appareils Azure Sphere.
- Étant donné que plusieurs problèmes peuvent résulter de délais d’arrêt exponentiels longs, il est essentiel de suivre la durée de fonctionnement totale et de définir un minuteur d’arrêt sur une limite raisonnable afin de ne pas vider la batterie dans des conditions où la connectivité n’est plus possible en raison de pannes externes ou d’autres facteurs indépendants du contrôle de l’application.
- Dans le contrôle de la surveillance de la connectivité pendant les pannes, l’émetteur-récepteur Wi-Fi peut s’arrêter en désactivant l’interface
wlan0
réseau (consultez Networking_SetInterfaceState et en attendant que la prochaine case activée pour la connectivité, ce qui permet d’économiser environ 100mW.
Gestion et utilisation de la mémoire
Sur les plateformes à mémoire limitée, les applications qui effectuent des allocations et des désaffectations de mémoire fréquentes peuvent entraîner des difficultés de gestion de la mémoire du système d’exploitation avec efficacité, ce qui entraîne une fragmentation excessive et une saturation de la mémoire. En particulier sur le MT3620 Azure Sphere, cela peut entraîner des conditions de mémoire insuffisante qui pourraient déclencher l’initialisation du tueur OOM du groupe du système d’exploitation Azure Sphere.
Naturellement, les applications sont souvent développées à partir d’une preuve de concept initiale, qui devient plus complète avec les fonctionnalités requises pour les versions progressives, en négligeant finalement les fonctionnalités mineures qui ont été initialement incluses. Voici des suggestions et des optimisations qui se sont avérées efficaces pour de nombreux scénarios analysés sur le terrain :
- En particulier dans les applications HL-Core qui utilisent intensivement la mémoire, il est essentiel de suivre l’utilisation de la mémoire des applications via l’API Azure Sphere, décrite dans Déterminer l’utilisation de la RAM des applications au moment de l’exécution. En règle générale, cette opération est implémentée dans un service de surveillance du minuteur et l’application réagit en conséquence à l’utilisation inattendue de la mémoire afin de redémarrer de manière raisonnable ; par exemple, la sortie avec le code de sortie approprié.
Plusieurs clients et partenaires ont trouvé utile d’utiliser l’utilitaire de suivi de la mémoire Heap Tracker , qui est publié dans la galerie Azure Sphere. Cette bibliothèque établit un lien transparent avec une application HL-Core existante et effectue le suivi des allocations de mémoire et de leurs pointeurs associés, ce qui permet une détection simplifiée de la plupart des cas de fuites de mémoire et d’utilisation incorrecte des pointeurs.
Important
Cette pratique peut réduire l’absence de réponse ou les défaillances de l’appareil apparemment inexpliquées souvent signalées à partir du champ. Ces défaillances sont généralement provoquées par des fuites ou des dépassements de mémoire qui ne sont pas correctement gérés par l’application HL-Core et conduisent le tueur OOM à arrêter le processus de l’application. Cela, ainsi qu’une connectivité médiocre qui empêche le système d’exploitation Azure Sphere d’envoyer des données de télémétrie, peut entraîner des incidents potentiels sur le terrain, car le diagnostic ne peut être détecté qu’en extrayant les journaux de diagnostic du système d’exploitation Azure Sphere.
- Sur les plateformes à mémoire limitée, il est généralement préférable d’éviter l’allocation dynamique de mémoire autant que possible, en particulier dans les fonctions fréquemment appelées. Cela réduira considérablement la fragmentation de la mémoire du tas et la probabilité d’échecs d’allocation de segments de mémoire ultérieurs. Envisagez également un changement de paradigme de l’allocation répétitive de mémoires tampons de travail temporaires à l’accès direct à la pile (pour les variables de taille raisonnable) ou aux mémoires tampons allouées globalement, qui augmentent en taille (jusqu’à
realloc
) en cas de dépassement (voir Conteneurs et mémoires tampons dynamiques). S’il est nécessaire de décharger la mémoire, envisagez de tirer parti de la mémoire inutilisée sur les cœurs M4 (consultez Mémoire disponible sur Azure Sphere), qui ont chacun 256 Ko, avec une application RT-core légère pour la mise en cache des données. Vous pouvez éventuellement utiliser des cartes SD externes ou flash. Vous trouverez des exemples dans les dépôts suivants :
Projet de disque distant du système de fichiers simple
Note
Les exemples ci-dessus n’implémentent pas le chiffrement, qui doit être pris en compte en fonction du type de données que vous allez stocker en externe.
Suivre les suggestions ci-dessus peut également aider à estimer et à réserver la mémoire nécessaire pour que l’application HL-core fonctionne à pleine capacité tout au long de son cycle de vie, tout en vous permettant de mieux estimer l’empreinte mémoire globale de l’application pour des optimisations de conception ultérieures. Pour plus d’informations sur l’optimisation de l’utilisation de la mémoire dans les applications HL-core, y compris les fonctionnalités du système d’exploitation Azure Sphere et de Visual Studio, consultez les articles suivants :