Forum: Compiler & IDEs RAM-"Rest" als Cache - malloc oder nicht malloc?


von Detlev T. (detlevt)


Lesenswert?

Hallo ihr GCC-Spezies,

angenommen, ich möchte bei einem Programm (AVR 8-Bit) den gesamten, 
bislang noch nicht genutzten, SRAM-Bereich mit einer eigenen 
Speicherverwaltung verwenden, z.B. als Cache - oder auch etwas anderes. 
Die Größe soll bei Programmänderungen möglichst automatisch angepasst 
werden, so dass immer die maximal mögliche Speichergröße zur Verfügung 
steht.

"Sauber" wären wohl folgende Möglichkeiten:
1.) uint8_t-array anlegen und manuell tunen, so dass am Ende aller 
Speicher genutzt wird.
2.) mit malloc() den gesamten Heap auf einmal reservieren. (Frage: Wie 
bekomme ich da die maximal mögliche Größe heraus?)

"Unsauber"(?):
3.) Einfach Zeiger auf den Bereich zwischen __heap_start und 
__malloc_margin setzen und so den Speicher nutzen. (Fragen: Gibt es 
diese Werte überhaupt, wenn ich malloc() & Co gar nicht nutze? Wie gebe 
ich GCC vor, wie groß der potentielle Stack sein soll, wo also 
__malloc_margin hinzeigen soll?)

Was würdet ihr da empfehlen?

Vielen Dank schon einmal für eure Antworten.

Gruß, DetlevT

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


Lesenswert?

Dein Problem ist das gleiche wie das, was malloc() hat: ohne genaue
Kenntnis, wie tief der Stack worst case maximal werden kann, kannst
du nur raten, wie viele Bytes oberhalb der regulären Variablen
wirklich frei sind.  Das ändert sich ja zur Laufzeit der Applikation
auch ständig.

malloc() dafür zu benutzen hat nur Sinn, wenn du auch seine
Verwaltung mit nutzen willst (also die Freigabe des Speichers, das
Wieder-zusammen-fügen der freigegebenen Bereiche etc.), ansonsten
ist das nur nutzloser Overhead, wenn du ohnehin deinen Cache selbst
verwalten willst.

von Detlev T. (detlevt)


Lesenswert?

Hallo Jörg,

wenn ich dich richtig verstehe, soll ich den Speicher also einfach 
nutzen. Mit irgendwelchen seltsamen Nebenwirkungen ist also nicht zu 
rechnen, richtig?

Was die maximale Stackgröße betrifft ist meine Vorstellung, dass ich in 
einer Konfigurationsdatei (.h) - oder auch als Kommandozeilen-Parameter 
von GCC - irgendeine Größe vorgeben kann und GCC mir dann __margin_heap 
entsprechend setzt, damit ich diesen Wert im Programm zur Verfügung 
habe. "Raten" würde ich diese Größe schon können :D. (O.K., so wichtig 
ist das nicht, weil ich ja auch RAMEND-maximale Stackgröße rechnen kann. 
Ob __heap_start auch ohne malloc() existiert werde ich gleich einmal 
ausprobieren.)

Zur Ergänzung vielleicht noch diese Information: Es soll mit demselben 
Quelltext vielleicht wahlweise ein ATMEGA644P oder, wenn mehr RAM 
gebraucht wird, auch ein ATMEGA1284P zum Einsatz kommen. Da die sich 
(zur Zeit?) im Preis aber nicht unterscheiden, wäre das nicht ganz so 
wichtig.

Gruß, DetlevT

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


Lesenswert?

Detlev T. schrieb:
> wenn ich dich richtig verstehe, soll ich den Speicher also einfach
> nutzen. Mit irgendwelchen seltsamen Nebenwirkungen ist also nicht zu
> rechnen, richtig?

Compiler oder Bibliothek fassen (mit Ausnahme von malloc() natürlich)
den Bereich zwischen den Variablen und dem Stack nicht an.

von Detlev T. (detlevt)


Lesenswert?

Hallo Jörg,

Jo, vielen Dank.

Zur Ergänzung: Dieser Code lässt sich mit avr-gcc kompilieren (und tut 
hoffentlich das, was ich will ;-) )
1
#include <avr/io.h>
2
#include <stdlib.h>
3
4
#define MAX_STACK_SIZE 512
5
6
int main(void)
7
{
8
  uint16_t  buffer_size;
9
  uint8_t * buffer = (uint8_t *) __malloc_heap_start;
10
11
    buffer_size = RAMEND - (uint16_t) buffer - MAX_STACK_SIZE;
12
    return 0;
13
}

Gruß, DetlevT

von sebastians (Gast)


Lesenswert?

Mal angenommen, ich verwende keine Rekursion.
Kann avr-gcc mir dann berechnen, wie viel Stack ich maximal brauche?
Kann avr-gcc den Callgraphen nach Zyklen durchsuchen (und mich warnen 
wenn doch irgendwo eine Rekursion steckt)?

von Andreas F. (aferber)


Lesenswert?

sebastians schrieb:
> Kann avr-gcc mir dann berechnen, wie viel Stack ich maximal brauche?

Nein.

> Kann avr-gcc den Callgraphen nach Zyklen durchsuchen (und mich warnen
> wenn doch irgendwo eine Rekursion steckt)?

Nein.

Andreas

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


Lesenswert?

Andreas Ferber schrieb:
> sebastians schrieb:
>> Kann avr-gcc mir dann berechnen, wie viel Stack ich maximal brauche?
>
> Nein.

Jein. ;-)

Wenn du dir den generierten Assemblercode ansiehst (das ist nicht
der disassemblierte Code, der im .lss-File gezeigt wird!), dann findest
du da Angaben zur Größe des jeweiligen stack frames.  Denn Graphen
musst du dir schon selbst bauen, aber anhand dieser Angaben solltest
du schnell zu einer Idee über den Stackverbrauch gelangen können.

von thorstendb (Gast)


Lesenswert?

Hi,

bevor du irgendetwas machst in deinem code, hole dir nen Pointer auf 
dein RAM und schreibe es mit einem pattern komplett voll (z.B. 
0xdeadbeef, 0x55, 0xaa, ...)

Aber kein malloc!
Mit "komplett" musst du allerdings aufpassen, dass der Bereich von 
main() nicht überschrieben wird, sowie ZI etc. Das müsste man vorher aus 
der map ableiten, wo die Sachen liegen und wie gross die sind.

Alternativ kannst du auch in der pre-main btw. im ASM Code diese Rotine 
unterbringen.

Danach lässt du dein Programm wie gewohnt ne Weile laufen, es sollten 
möglichst alle Zweige durchlaufen werden (worst case), und schaust, was 
überschrieben wurde.

Je nach Laufzeit gibt dir das eine recht verlässliche Idee über den 
RAM Bedarf.


VG,
/th.

von Detlev T. (detlevt)


Lesenswert?

thorstendb schrieb:
> Das müsste man vorher aus
> der map ableiten, wo die Sachen liegen und wie gross die sind.

Ich habe inzwischen festgestellt, dass __malloc_heap_start auch dann 
gültig ist, wenn man malloc() selbst nicht aufruft. Damit hat man schon 
einmal den Beginn des "freien" Bereiches ohne irgendwelche 
.map-Kalkulationen. RAMEND ist ebenfalls verfügbar.

Einfach Ausprobieren ist manchmal recht praktisch, seinen Code zu kennen 
aber hier wohl noch besser. Im Zweifelsfall hängt das Laufzeitverhalten 
ja auch von den Parametern ab, da sollte man zumindest abschätzen 
können, was das worst case scenario sein sollte.

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


Lesenswert?

Detlev T. schrieb:
> Ich habe inzwischen festgestellt, dass __malloc_heap_start auch dann
> gültig ist, wenn man malloc() selbst nicht aufruft.

Ja, diese Variable wird statisch mit dem vom Linker bereitgestellten
Symbol __heap_start vorbelegt:

char *__malloc_heap_start = &__heap_start;

> RAMEND ist ebenfalls verfügbar.

Sinnvoller ist es aber in jedem Falle, den Stackpointer selbst
abzufragen.  Dann hast du zumindest bereits den "bottom of stack"
zum Zeitpunkt der Abfrage.

von Josef D. (jogedua)


Lesenswert?


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.