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? p>
6 Réponses :
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. P>
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 code>. P>
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.
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 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. P>
Vérifiez les tables de recherche qui n'ont pas utilisé correctement la déclaration 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. P> Si vous n'utilisez pas de tas, vous pouvez éventuellement éliminer cela. P> 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. P> Vérification de l'utilisation inutile de variables pouvant être plus petites, par exemple. 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. P> p> const code> 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 code> du côté correct du
* code> ou peuvent nécessiter deux em>
Const code> déclarations. Par exemple: p>
pile et tas h2>
Autre h2> < 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: p>
Variables locales VS H3>
statique code> 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 code>, é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 em> 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.) P>
variables plus petites h3>
int16_t code> (
court code>) ou
int8_t code> (
char code>) au lieu de
int32_t code> (
INT code>). P>
Enum variable Taille h3>
Enum code> 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 code> variables 2 octets même si la définition
Enum code> n'est vraiment requise que nécessaire 1 octet pour stocker sa gamme. Vérifiez les paramètres du compilateur. P>
Mixement d'algorithme h3>
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. P>
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. P>
Voici les astuces que j'ai utilisées sur la cellule: p>
alloca () code> ne nettoie pas jusqu'à ce qu'une fonction ne revienne, alors pouvez gaspiller une pile plus longue que prévu. li>
- 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. LI>
- 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 EM> en orlinant certaines fonctions, si la surcharge de prolog / epilog est supérieure à celle du corps de fonction. LI>
ul>
Le dernier n'est pertinent que sur les architectures qui stockent le code dans la RAM, je suppose. p>
Fonctions W.R.T, voici les poignées pour optimiser la RAM P>
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. p> li>
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. p> li>
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. P> li>
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 p> li>
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. P> li>
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. P> li> ol>
Cordialement P>
barani kumar venkatesan p>
Ajout aux réponses précédentes. P>
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. p>
Ceci peut être appliqué à la section de données identifiée comme non utile après une certaine étape de votre programme. p>
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.