12
votes

Comment optimiser ou réduire la taille de la RAM dans un logiciel système intégré?

Je travaille sur des projets logiciels intégrés dans le domaine automobile. Dans l'un de mes projets, le logiciel d'application consomme près de 99% de la mémoire RAM. La taille réelle de la RAM disponible est de 12kb. Nous utilisons TMS470R1B1 Titan F05 Microcontroller. J'ai fait une certaine optimisation, comme trouver des messages inutilisés dans des logiciels et les supprimer, mais il ne vaut toujours pas la peine de réduire la RAM. Pourriez-vous suggérer de bonnes façons de réduire la RAM par une optimisation logicielle?


3 commentaires

Vous devriez commencer par tirer le gars qui aime dire "l'optimisation est la racine de tout mal".


Vous devriez décrire votre structure actuelle. Utilisez-vous une allocation dynamique, existe-t-il un RTO, y a-t-il de gros consommateurs dans votre fichier de carte?


L'industrie automobile n'autorise pas l'allocation de mémoire dynamique, car MISRA-C interdit cela.


6 Réponses :


7
votes

Suppression de littéraux à chaîne inutilisés n'aura aucun effet sur l'utilisation de la RAM car ils ne sont pas stockés dans la RAM mais en ROM. Il en va de même pour le code.

Ce que vous devez faire est de réduire les variables réelles et éventuellement la taille de votre pile / pile. Je chercherais des tableaux pouvant être redimensionnés et des varaibles non utilisés. De plus, il est préférable d'éviter une allocation dynamique en raison du danger de fragmentation de la mémoire . < / p>

En plus de cela, vous voudrez vous assurer que des données constantes telles que des tables de recherche sont stockées dans la ROM. Cela peut généralement être obtenu avec le mot-clé const .


2 commentaires

Traiter avec l'optimisation de la RAM dans les microcontrôleurs peut être une douleur ... à côté de cela, le O.P devrait également vérifier les fuites de mémoire, non sécurisée en veillant à ce que la mémoire Malloc'd est correctement libérée. Disposer de tout objet jetable tant qu'ils ne sont plus nécessaires.


Paulo, cela ne serait-il pas une considération d'exécution, à quel point Heap Malloc () S aurait-il d'échouer? Je pense que l'OP parle de l'utilisation de la mémoire rapportée à l'heure de la compilation, auquel cas des fuites de mémoire, MALLOC et l'élimination ne signifient rien.



22
votes

Contrairement à l'optimisation de la vitesse, l'optimisation de la RAM pourrait être quelque chose qui nécessite un "un peu ici, un peu là" tout au long du code. D'autre part, il peut s'avérer être un "fruit suspendu bas".

Les tableaux et les tables de recherche

Les tableaux et les tables de recherche peuvent être de bons "fruits à faible suspendre". Si vous pouvez obtenir une carte mémoire à partir de la liaison, vérifiez que les gros éléments de la RAM.

Vérifiez les tables de recherche qui n'ont pas utilisé correctement la déclaration const correctement, qui les met dans la RAM au lieu de ROM. Cherchez particulièrement les tables de recherche des pointeurs, qui ont besoin du const du côté correct du * ou peuvent nécessiter deux Const déclarations. Par exemple: xxx

pile et tas

Peut-être que votre liaison config réserve de grandes quantités de RAM pour le tas et la pile, plus grand que nécessaire pour votre application.

Si vous n'utilisez pas de tas, vous pouvez éventuellement éliminer cela.

Si vous mesurez votre utilisation de la pile et c'est bien sous la répartition, vous pourrez peut-être réduire l'allocation. Pour les processeurs de bras, plusieurs piles peuvent y avoir plusieurs piles, pour plusieurs des modes de fonctionnement et vous pouvez constater que les piles attribuées aux modes de fonctionnement d'exception ou d'interruption sont plus grandes que nécessaire.

Autre < P> Si vous avez vérifié les économies faciles, et vous avez toujours besoin de plus, vous devrez peut-être suivre votre code et enregistrer "ici un peu, un peu". Vous pouvez vérifier les choses comme:

Variables locales VS

Vérification de l'utilisation inutile de statique ou de variables globales, où une variable locale (sur la pile) peut être utilisé à la place. J'ai vu du code qui avait besoin d'un petit tableau temporaire dans une fonction, qui a été déclaré statique , évidemment parce que "cela prendrait trop d'espace de pile". Si cela se produit suffisamment de fois dans le code, il enregistrerait en réalité une utilisation totale de la mémoire pour rendre à nouveau des variables locales. Cela peut nécessiter une augmentation de la taille de la pile, mais sauvera plus la mémoire sur des variables globales / statiques réduites. (En tant qu'enfonge latérale, les fonctions sont plus susceptibles d'être ré-entraving, fil-coffre-fort.)

variables plus petites

variables pouvant être plus petites, par exemple. int16_t ( court ) ou int8_t ( char ) au lieu de int32_t ( INT ).

Enum variable Taille

Enum La taille de la variable peut être plus grande que nécessaire. Je ne me souviens pas de ce que les compilateurs de bras font généralement, mais certains compilateurs que j'ai utilisés dans le passé par défaut effectué par défaut Enum variables 2 octets même si la définition Enum n'est vraiment requise que nécessaire 1 octet pour stocker sa gamme. Vérifiez les paramètres du compilateur.

Mixement d'algorithme

retravailler vos algorithmes. Certains algorithmes ont une gamme d'implémentations possibles avec un compromis de vitesse / mémoire. Par exemple. Le cryptage AES peut utiliser un calcul de clé à vol, ce qui signifie que vous n'avez pas besoin d'avoir toute la clé étendue en mémoire. Qui sauve la mémoire, mais c'est plus lent.


0 commentaires

5
votes

Assurez-vous que la liaison produit un fichier de carte - il vous montrera où la RAM est utilisée. Parfois, vous pouvez trouver des choses comme des littéraux / constantes de chaîne qui sont conservées dans la RAM. Parfois, vous trouverez qu'il y a des tableaux / variables inutilisés pose là par quelqu'un d'autre.

Si vous avez le fichier de carte de lieur, il est également facile d'attaquer les modules qui utilisent le plus d'abord de la RAM.


0 commentaires

3
votes

Voici les astuces que j'ai utilisées sur la cellule:

  • Commencez par l'évidence: Appuyez sur les mots 32 bits dans les 16 secondes dans la mesure du possible, réorganisez les structures pour éliminer le rembourrage, coupez-vous sur le mou dans les matrices. Si vous avez des matrices de plus de huit structures, cela vaut la peine d'utiliser des champs de bit pour les emballer plus serré.
  • Effectuez une allocation de mémoire dynamique et utilisez des pools statiques. Une empreinte de mémoire constante est beaucoup plus facile à optimiser et vous serez sûr de ne pas avoir de fuites.
  • Portée des allocations locales serrées de manière à ce qu'ils ne restent pas sur la pile plus longtemps que ce qu'ils doivent. Certains compilateurs sont très mauvais de reconnaissance lorsque vous avez terminé une variable et la laissera sur la pile jusqu'à ce que la fonction revienne. Cela peut être mauvais avec de grands objets dans des fonctions extérieures qui mangent ensuite une mémoire persistante, ils ne doivent pas nécessiter que la fonction extérieure appelle plus profondément dans l'arbre.
  • alloca () ne nettoie pas jusqu'à ce qu'une fonction ne revienne, alors pouvez gaspiller une pile plus longue que prévu.
  • Activer le corps de la fonction et la fusion constante dans le compilateur, de sorte que s'il voit huit constructeurs différents de la même valeur, cela ne mettra qu'un dans le segment de texte et les alias avec le lien de liaison.
  • optimise le code exécutable pour la taille. Si vous avez une date limite en temps réel dure, vous savez exactement la rapidité avec laquelle votre code doit fonctionner, donc si vous avez des performances de rechange, vous pouvez effectuer des compromis de vitesse / de taille jusqu'à ce que vous atteigniez ce point. Boucles de rouleau, tirez le code commun dans des fonctions, etc. Dans certains cas, vous pouvez réellement obtenir un espace l'amélioration en orlinant certaines fonctions, si la surcharge de prolog / epilog est supérieure à celle du corps de fonction.

    Le dernier n'est pertinent que sur les architectures qui stockent le code dans la RAM, je suppose.


0 commentaires

3
votes

Fonctions W.R.T, voici les poignées pour optimiser la RAM

  1. Assurez-vous que le nombre de paramètres transmis à une fonction est profondément analysé. Sur les architectures de bras selon AAPCS (standard d'appels de procédure ARCH), le maximum de 4 paramètres peut être passé à l'aide des registres et le reste des paramètres serait enfoncé dans la pile.

  2. Considérons également le cas d'utilisation d'un global plutôt que de transmettre les données à une fonction la plus fréquemment appelée avec le même paramètre.

  3. Plus les appels de fonction, plus le plus lourd est l'utilisation de la pile. Utilisez n'importe quel outil d'analyse statique, pour connaître le pire chemin d'appel de la fonction coulée et rechercher des sites pour le réduire. Lorsque la fonction A est une fonction d'appel B, B appelle C, ce qui appelle à son tour D, qui appelle à son tour e et va plus loin. Dans ce cas, les registres ne peuvent pas être à tous les niveaux de transmettre les paramètres et donc évidemment une pile seront utilisées.

  4. Essayez des sites pour clubbing les deux paramètres dans l'un des endroits où applicable. N'oubliez pas que tous les registres sont de 32 bits au bras et une optimisation supplémentaire est donc aussi possible. vide ABC (BOOL A, BOOL B, UINT16_T C, UINT32_T D, UINT8_T E) // fait usage de registres et de pile Void ABC (UINT8 AB, UINT16_T C, UINT32_T D, UINT8_T E) // Les 2 premiers paramètres peuvent être cloutées. Donc, le total de 4 paramètres peut être transmis à l'aide de registres

  5. Reprise des vecteurs d'interruption imbriqués. Dans n'importe quelle architecture, nous utilisons pour avoir des registres de pad-cavaliers et des registres préservés. Les registres préservés sont quelque chose qui doit être sauvé avant le service de l'interruption. En cas d'interruption imbriquée, il aura besoin d'un énorme espace de pile pour sauvegarder les registres conservés vers et depuis la pile.

  6. Si des objets de type tels que la structure sont transmis à la fonction par valeur, il pousse une telle quantité de données (en fonction de la taille de la structure) qui mangera facilement l'espace de pile. Cela peut être changé pour passer par référence.

    Cordialement

    barani kumar venkatesan


0 commentaires

0
votes

Ajout aux réponses précédentes.

Si vous exécutez votre programme à partir de la RAM pour une exécution plus rapide, vous pouvez créer une section définie par l'utilisateur contenant toutes les routines d'initialisation que vous êtes assuré qu'il ne fonctionnera pas plus d'une fois après la botte de votre système. Après toutes les fonctions d'initialisation exécutées, vous pouvez utiliser la région pour le tas.

Ceci peut être appliqué à la section de données identifiée comme non utile après une certaine étape de votre programme.


0 commentaires