Forum: Compiler & IDEs Verfügbarer RAM zur Laufzeit?


von GCC User (Gast)


Lesenswert?

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

von Marco S. (masterof)


Lesenswert?

ich bin zwar kein AVR-GCC-Freak aber zeigt der Compeiler daws nicht am
schluss an wie viel Flash und Ram das Programm verbraucht.

von GCC User (Gast)


Lesenswert?

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

von Rolf Magnus (Gast)


Lesenswert?

Und beim Scheitern von malloc diese Auslagerung durchführen und dann
nochmal versuchen geht nicht?

von Benedikt (Gast)


Lesenswert?

Keine Ahnung ob das passt, ist nur eine Idee:
Versuch mal folgendes:
Stackpointer Minus von malloc gelieferte Adresse.

von Patrick D. (oldbug) Benutzerseite


Lesenswert?

Such mal nach "Heap", Peter Dannegger hat hier irgendwo ein Stückchen
Code gepostet.

von GCC User (Gast)


Lesenswert?

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

von Hans-Christian (Gast)


Lesenswert?

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

von GCC User (Gast)


Lesenswert?

@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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von GCC User (Gast)


Lesenswert?

@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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 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.

von GCC User (Gast)


Lesenswert?

@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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 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.

von GCC User (Gast)


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> 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.

von GCC User (Gast)


Lesenswert?

> 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
Noch kein Account? Hier anmelden.