Hallo AVR-GCC Freaks, gibt es eine Möglichkeit zur Laufzeit den noch freien RAM zu ermitteln? Ich habe in meinem Code jede Menge an enfach verketteten Listen, wo ich dynamisch struct Elemente mit unterschiedlicher Grösse dranhängen kann. Interessant ist, wie viele Elemente noch in den RAM passen, sodass man evtl. neue Elemente abweist, oder aber Elemente in den EEPROM auslagert. Hat da jemand eine Idee? Gruss Mario
ich bin zwar kein AVR-GCC-Freak aber zeigt der Compeiler daws nicht am schluss an wie viel Flash und Ram das Programm verbraucht.
Naja - eben nur zur Compile Zeit. Zur Laufzeit wird bei mir aber per malloc weiter Speicher allokiert - und irgendwann ist Schluss. Wann Schluss ist - würd ich im Programm gern vorher wissen. Klar würde mir malloc nen NULL pointer zurückgeben, wenn der RAM am Ende ist. Ich würde aber gern vorher rauskriegen, wie viel Platz noch ist, um evtl. ein Teil vom RAM in den (langsameren) EEPROM auszulagern... Gruss Mario
Und beim Scheitern von malloc diese Auslagerung durchführen und dann nochmal versuchen geht nicht?
Keine Ahnung ob das passt, ist nur eine Idee: Versuch mal folgendes: Stackpointer Minus von malloc gelieferte Adresse.
Such mal nach "Heap", Peter Dannegger hat hier irgendwo ein Stückchen Code gepostet.
Hallo * danke für die vielen Antworten! Meine Anwendung ist übrigens ein Funkempfänger für die batterielosen ENOCEAN Funkschalter. Diese Funkschalter sollen dynamisch (zur Laufzeit) eingelernt und zu Relais zugeordnet werden. Wenn ein Funktelegramm empfangen wird, soll der Schalter im RAM gefunden werden und die zugeordneten Relais entsprechend geschaltet werden. Funktioniert auch schon ganz gut... Hier der Entwicklungsthread im Hausbus Forum (dort noch ohne dynamische Schalter und Relaisverwaltung): http://www.mikrocontroller.net/forum/read-11-270943.html#new @Rolf Würde schon gehen, aber ich hätte gern einen Status rausgegeben, wie viele Datensätze (Schalter & Relais) noch reinpassen. Am liebsten wäre mir, wenn ich alles komplett im RAM halten könnte und nen Backup im EEPROM - aber 4kB sind nun mal nicht gerade viel... @Benedikt Danke für den SUPER Tip. Hab darüber mal im libc manual nachgeschaut, und gesehen, dass man mit globalen Variablen die Heap Position rauskriegt: http://www.nongnu.org/avr-libc/user-manual/malloc.html Ganz krass ist natürlich, dass der malloc heap in den Stack reinlaufen kann, weil das malloc heap end am Stack Anfang liegt. Hoffe, dass die malloc Implementation das verhindert. Aber in der Tat ist es schwierig den freien RAM zu ermitteln - vor allem, wenn der RAM nach und nach fragmentiert wird - mmh... Vielleicht mache ich es so, dass ich vor dem ersten malloc die Heap Size ermittle minus kleinem offset für den stack. Und immer, wenn ein bereich belegt wird, wird die Anzahl der Bytes abgezogen und wenn ein Bereich wieder freigegeben wird, dann wird er wieder dazuaddiert. Um das Fragmentieren zu verhindern, sollte ich selten Speicher freigeben. Naja - wird eher selten vorkommen, dass ein Funkschalter im Haus wieder entfernt wird... na - mal schaun! @Patrick hab den Code Schipsel leider nicht gefunden... :-( Gruss Mario
Hallo Mario, ich würde die Speicherverwaltung selber machen, also mir den restlichen freien Speicher statisch anlegen, und die verketteten Listen da hinein legen. Damit umgehst Du dann auch, daß der Heap in den Stack wächst. Gruss Hans-Christian
@Hans-Christian ja ist ne Idee - aber dann muss ich auch mit der Fragmentierung kämpfen - also die Löcher verwalten und ggf. wieder neu belegen. Würde ganz gut gehen, wenn die Listenelemente alle immer die gleiche Grösse haben. Haben sie aber noch nicht - und ich würde das auch gern vermeiden, weil ich zu einem Schalter auch beliebig viele Relais zuordnen will - also z.B. nen "Alle Lichter aus" Schalter - und auch beliebige Namenstrings pro Schalter speichen will. Und die malloc implementation verwaltet ja schon die Löcher... Na mal schaun - hab vorsichtshalber schon mal ne eigene malloc function eingebunden, damit ich im Code rummanschen kann ;-) Gruss Mario
Ich habe nichts dagegen, mal eine "__malloc_status()" oder sowas Funktion in die Bibliothek einzubringen, mit der man bestimmte Dinge abfragen kann. Dazu sollten wir aber vorher (auf avr-libc-dev at nongnu.org bitte) über das API diskutieren, damit es nicht nur ein Schnellschuss wird. Was ich mir vorstelle, was Sinn haben kann: . Bericht über den noch freien Platz bis zum derzeitigen __malloc_margin . Statistik über die derzeitige freelist: größter verfügbarer Block, Anzahl der Blöcke, gesamter Speicher in der freelist. Damit müsste man, wenn man das während der Testphase regelmäßig abfragt, eine Abschätzung über die Fragmentierung des Speichers vornehmen können. Das API sollte aber wohl durchdacht sein, vielleicht will man auch gleich mehr als eine Funktion haben. Die freelist- Statistik dürfte ein wenig Rechnerei erfordern, wer das nicht haben will, kann sich eigentlich den ROM und die Rechenzeit dafür sparen.
@jörg Nen malloc status würd ich gut finden - kommt für mich aber zu spät. Hab nur noch zwei Wochen für den Funkempfänger. Mir würde aber erstmal reichen, wenn ich den noch freien Platz zwischen malloc_heap_end zum aktuellen Stackpointer rauskriegen würde. Aus dem malloc tutorial werde ich nicht ganz schlau... Was bedeutet z.B. brkval(<=*SP-__malloc_margin) ? Gruss Mario
> Was bedeutet z.B. brkval(<=*SP-__malloc_margin)? Es fragt, ob der neue "break value" (also der küftige top of heap) noch in den Platz im Stack passt, der sich aus dem aktuellen Stackpointer verringert um den "malloc margin" ergibt. Der malloc margin ist eine Sicherheitsreserve, die dem Stack eingeräumt wird, bevor er mit dem Heap kollidieren würde. Die Voreinstellung sind 32 Bytes, die Applikation darf dort auch mehr oder weniger eintragen, falls sie weiß, dass sie beonders viel oder besonders wenig lokale Variablen auf dem Stack anlegt etc. __malloc_heap_end ist dabei eine Alternative um festzulegen, bis wohin der Heap maximal erweitert werden darf (unabhängig vom aktuellen Stackpointer). Wenn __malloc_heap_end gesetzt ist, bekommt es Vorrang vor der Stack-Evaluierung. > Mir würde aber erstmal reichen, wenn ich den noch freien Platz > zwischen malloc_heap_end zum aktuellen Stackpointer rauskriegen > würde. Letztlich ist das der Teil des Codes:
1 | cp = __malloc_heap_end; |
2 | if (cp == 0) |
3 | cp = STACK_POINTER() - __malloc_margin; |
4 | avail = cp - __brkval; |
Wenn __malloc_heap_end gesetzt ist, wird die Verfügbarkeit dagegen getestet, andernfalls gegen den Stack vermindert um __malloc_margin. In deiner Applikation weißt du ja selbst, ob du __malloc_heap_end setzt oder nicht, also kannst du eine der beiden Alternativen ausschließen. __brkval ist der aktuelle top of heap. avail bezeichnet danach die Anzahl der noch freien Bytes.
@Jörg, Da bei mir __malloc_heap_end auf Default 0 steht, würde ich also den freien platz bis zum aktuellen Stack Pointer + Sicherheitsreserve so rauskriegen: avail = STACK_POINTER() - __malloc_margin - __brkval; Na mal schaun - werd ich heute mal ausprobieren und bestimmt nen Schreck kriegen - wie wenig noch übrig ist mit meinen bisher nur 8 eingelernten Schaltern & Relais... Hab aber schon ein paar Ideen, wie ich meine Strukturen im RAM schlanker gestalte. Ich werde dann halt mehr und mehr pointer in den EEPROM nutzen müssen, und da dann die Relaisaktionen und Namestrings ablegen. Die Frage ist - wieviel langsamer ist es einen Wert aus dem EEPROM zu lesen - als aus dem RAM... Übrigens - Vielen Dank! Hab mal wieder was gelernt ;-) Gruss Mario
> Die Frage ist - wieviel langsamer ist es einen Wert aus dem > EEPROM zu lesen - als aus dem RAM... Lesen geht, aber Schreiben braucht vergleichsweise eine Ewigkeit.
Ok funktioniert! So sieht die Funktion nun aus: #include "stdlib_private.h" uint16_t getFreeMem(void) { if(__brkval) return(STACK_POINTER() - __malloc_margin - __brkval); return(STACK_POINTER() - __malloc_margin - __malloc_heap_start); } Wichtig ist, das include - sonst hat man kein Zugriff aufs STACK_POINTER() Makro und __brkval. Die Include Datei findet man in der avr-libc source distribution... Dem Rückgabewert der Funktion darf man aber nur glauben, solange noch kein Speicher mit free freigegeben wurde. Ist bei meiner Anwendung aber erstmal egal - geb selten was frei :-) Und - ich hab noch 3434 Bytes frei - hätt ich nicht gedacht ;-) Danke nochmal an alle, die geantwortet haben. Gruss Mario
> Dem Rückgabewert der Funktion darf man aber nur glauben, solange > noch kein Speicher mit free freigegeben wurde. Nein, der Rückgabewert stimmt dahingehend, dass er dir den noch für entweder Heap oder Stack verfügbaren Speicher nennt. Das, was du schon einmal alloziert hast und wieder freigibst, wird fürderhin als zum Heap zugehörig betrachtet und ist daher dort nicht erwähnt (es ist nur noch in der freelist). Die Zusammensetzung dieses freien Speichers kann vielfältig sein (und das wäre eine Aufgabe für die genannte malloc-Statistik), von völlig zerklüftet (sodass der nächste malloc()-Aufruf neuen Speicher ausfassen muss) bis hin zu einem kompletten Block zwischen dem Ende der Variablen und dem Ende des derzeitigen Heap (__brkval). Ersteres ist der ungünstigste Fall, letztgenannte Variante ist praktisch ,,wie neu'', also wie sofort nach dem Start, nur dass __brkval eben schon weitergerückt worden ist.
> Das, was du schon einmal alloziert hast und wieder freigibst, wird > fürderhin als zum Heap zugehörig betrachtet und ist daher dort nicht > erwähnt (es ist nur noch in der freelist). Ja genau das ist die Unschärfe - und das meinte ich mit meiner Anmerkung. Wenn Blöcke in der freelist sind, dann sind sie freier RAM, tauchen aber als solcher im Rückgabewert meiner Funktion nicht mehr auf. Der tatsächlich freie RAM ist also höher, wenn schonmal Blöcke freigegeben wurden. Aber mit dieser Unschärfe können viele Anwendungen leben - denk ich. Gruss Mario
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.