Atmega objdump: Speicherfresser finden

Gast #6160045
Lesenswert?

Wie finde ich mit avr-objdump die großen Speicherfresser?

Problem:

>Globale Variablen verwenden 1537 Bytes (75%) des dynamischen Speichers, 511 Bytes 
für lokale Variablen verbleiben. Das Maximum sind 2048 Bytes.

avr-objdump -t meinProgramm.ino.elf > map.txt

Wenn ich's richtig weiß, ist das RAM im .bss segment.
Muss man alles von Hand zusammenzählen?
Gast #6160163
Lesenswert?

Im RAM landen beim AVR .bss und .data.  Das solltest du auch nicht ganz 
voll machen, da noch etwas für den Stack benötigt wird.

In der vorletzten Spalte der objdump-Ausgabe ist doch die Größe des 
Objekts - da sieht man eigentlich schnell, wer viel braucht.
Gast #6160170
Lesenswert?

> Wie finde ich mit avr-objdump die großen Speicherfresser?

Einfacher isses in den Code zu schauen, i.d.R. suchst Du nämlich nicht 
"die Großen" sondern vielviel Kleine. Zumindest bei atmegas dieser 
Größe.
Gast #6160173
Lesenswert?

>Im RAM landen beim AVR .bss und .data.  Das solltest du auch nicht ganz
>voll machen, da noch etwas für den Stack benötigt wird.

Das dachte ich mir schon. Bei ca. 200Byte Reserve fängt das Programm an, 
sich beim Start aufzuhängen.

>In der vorletzten Spalte der objdump-Ausgabe ist doch die Größe des
>Objekts - da sieht man eigentlich schnell, wer viel braucht.

Das habe ich schon gesehen. Ich wollte es nur nicht manuell durchsuchen 
müssen.
Was ist der Unterschied zwischen .bss und .data ?
Gast #6160178
Lesenswert?

g457 (Gast)
>Einfacher isses in den Code zu schauen, i.d.R. suchst Du nämlich nicht
>"die Großen" sondern vielviel Kleine. Zumindest bei atmegas dieser
>Größe.

Ja, es sind scheinbar viele kleine. Was mich ein wenig wundert ist, dass 
Objekte die noch nicht instantiiert sind und in einer Liste später 
gesammelt werden, schon ca. 10 Byte .data zu verbrauchen scheinen.
Gast #6160267
Lesenswert?

chris schrieb:
> Was ist der Unterschied zwischen .bss und .data ?

.data sind initialisierte Variablen, also z.B. String Literals wie in 
printf("Test"); - sofern Du nicht dafür Sorge trägst, dass sie erst bei 
Bedarf vom Flash ins RAM kopiert werden.

.bss sind nicht initialisierte Variablen, also z.B. globale Variablen 
ohne zugewiesenen Wert.
Gast #6160427
Lesenswert?

von Hmmm (Gast)
>chris schrieb:
>> Was ist der Unterschied zwischen .bss und .data ?

>.data sind initialisierte Variablen, also z.B. String Literals wie in
>printf("Test"); - sofern Du nicht dafür Sorge trägst, dass sie erst bei
>Bedarf vom Flash ins RAM kopiert werden.

>.bss sind nicht initialisierte Variablen, also z.B. globale Variablen
>ohne zugewiesenen Wert.

Danke dafür.

Hier mal der Speicherverbrauch der Basisklasse "Component":

008003ba g     O .data  00000010 .hidden _ZTV9Component

Tatsächlich werden auch für jede abgeleitete Klasse 16 Bytes .data 
reserviert, obwohl kein einziges Objekt beim Programmstart instantiiert 
ist. Die Objekte werden erst während des Programmlaufs initialisiert. Es 
können 0 bis mehrere Objekte einer Klasse durch das Programm erzeugt 
werden.

Hier die Zeile des Compiler-Laufs, um das Setup zu sehen:

"/home/christoph/tools/arduino-1.8.5/hardware/tools/avr/bin/avr-g++" -c 
-g -Os -w -std=gnu++11 -fpermissive -fno-exceptions -ffunction-sections 
-fdata-sections -fno-threadsafe-statics -MMD -flto -mmcu=atmega328p 
-DF_CPU=16000000L -DARDUINO=10805 -DARDUINO_AVR_NANO -DARDUINO_ARCH_AVR 
"-I/home/christoph/tools/arduino-1.8.5/hardware/arduino/avr/cores/arduin 
o" 
"-I/home/christoph/tools/arduino-1.8.5/hardware/arduino/avr/variants/eig 
htanaloginputs" 
"-I/home/christoph/tools/arduino-1.8.5/hardware/arduino/avr/libraries/EE 
PROM/src"  "-I/home/christoph/Arduino/libraries/MemoryFree" 
"/tmp/arduino_build_683962/sketch/Component.cpp" -o 
"/tmp/arduino_build_683962/sketch/Component.cpp.o"

Warum verbrauchen die Klassen 16Bytes an initialiertem .data-RAM, ohne 
ein einziges Objekt?
Gast #6160706
Lesenswert?

>Das liegt bei AVR an der vtable,

Danke dafür, so was habe ich schon vermutet.
Am Anfang des Projektes habe ich noch überlegt, ob ich es in C machen 
soll und die Klassen von Hand via Strukturen basteln. Es scheint mir, 
das wäre der bessere Weg gewesen.
Ich habe 30 Klassen a 16Bytes was mich ca. ein viertel des Speichers 
kostet.
Beitrag #6164574 wurde von einem Moderator gelöscht.
#6164712
Lesenswert?

Folgendes Tool könnte vielleicht nützlich sein:
http://www.sikorskiy.net/prj/amap/

"amap : A tool to analyze .MAP files produced by 32/64-bit Visual Studio 
compiler and report the amount of memory being used by data and code.
This app can also read and analyze MAP files produced by the GCC, 
Xbox360, Wii, PS3 (gcc and SNC), and PS4 compilers."

Das erleichtert zumindest das Suchen etwas...
Gast #6164966
Lesenswert?

Wilhelm M. schrieb:
> Joggel E. schrieb:
>> Aaaaahhhhhh ... Objekte auf einem AVR ... aaaaahhh.
>> Man kann auchb wirklich alles falsch machen.
>
> Was hast Du gegen Objekte?

Vermutlich hatte er gerade einen Schlaganfall.

Joggel E. schrieb:
> Ja, ich habe etwas gegen Objekte auf Controllern.
>
> Was sollen die bringen ?

Sauberen Code? Gegenfrage, wo siehst du das Problem darin, wenn man sie 
richtig verwendet?
#6165003
Lesenswert?

Textest Du die Leute voll?
Bei Textvariablen wird diese in's RAM kopiert, was mal schnell ein paar 
Bytes verbraucht.
Also: Texte explizit im Flash ablegen.

Ansonsten fällt mir nur noch ein:
So viele Variablen, wie möglich, lokal, in den Funktionen anlegen. Da 
brauchst Du kein malloc und so'n Kram und das Recycling passiert beim 
Rücksprung.
#6165377
Lesenswert?

Sebastian S. schrieb:
> Ansonsten fällt mir nur noch ein:
> So viele Variablen, wie möglich, lokal, in den Funktionen anlegen. Da
> brauchst Du kein malloc und so'n Kram und das Recycling passiert beim
> Rücksprung.

Es hat aber auch einen großen Nachteil: Es ist zur Compilezeit nicht 
überschaubar, wie viel RAM man tatsächlich braucht. Und wenn die Daten 
zu groß für den Speicher sind, gibt's einfach nur fehlerhaftes 
Verhalten.
#6165386
Lesenswert?

@Rolf M.

>Es hat aber auch einen großen Nachteil: Es ist zur Compilezeit nicht
>überschaubar, wie viel RAM man tatsächlich braucht. Und wenn die Daten
>zu groß für den Speicher sind, gibt's einfach nur fehlerhaftes
>Verhalten.
Stimmt, aber nur so kommt man auf ein "Minimum" zur Laufzeit und kann 
nicht vergessen zu "putzen".
Gast #6165417
Lesenswert?

Sebastian S. schrieb:
>>Es hat aber auch einen großen Nachteil: Es ist zur Compilezeit nicht
>>überschaubar, wie viel RAM man tatsächlich braucht. Und wenn die Daten
>>zu groß für den Speicher sind, gibt's einfach nur fehlerhaftes
>>Verhalten.
> Stimmt, aber nur so kommt man auf ein "Minimum" zur Laufzeit und kann
> nicht vergessen zu "putzen".

Vor allem, da der Compiler dann versuchen wird, so viel wie möglich ohne 
RAM-Nutzung in den Registern zu erledigen.
Gast #6165451
Lesenswert?

> Vor allem, ...

Compiler denken nicht mit. Es gibt auch keine Optimierung die
"so viel wie möglich ohne RAM-Nutzung in den Registern zu erledigen."

Das waere allenfalls ueber eine Optimierung in Richtung minimaler
Laufzeit des Programms steuerbar.

Im Stack gehaltene Variable sind am Funktionsende auch nicht
mehr zugreifbar.

Und ob ich die Variablen statisch deklariere oder in der main
vom Stack hole, macht keinen Unterschied.
#6165524
Lesenswert?

Compiler schrieb:
>> Vor allem, ...
>
> Compiler denken nicht mit. Es gibt auch keine Optimierung die
> "so viel wie möglich ohne RAM-Nutzung in den Registern zu erledigen."

Doch, natürlich gibt es die. Das dürfte sogar zu den ältesten 
Optimierungen überhaupt zählen.

> Und ob ich die Variablen statisch deklariere oder in der main
> vom Stack hole, macht keinen Unterschied.

Es macht einen Unterschied. Darum ging es ja gerade. Bei statischen 
Variablen sehe ich bereits zur Linkzeit, wie viel Platz sie brauchen. 
Dafür brauchen sie den Platz über die gesamte Laufzeit des Programms. 
Automatische Variablen dagegen existieren nur während der Laufzeit der 
Funktion, in der sie definiert sind. Davor und danach existieren sie 
nicht. Dafür sieht man nicht, wieviel am Ende wirklich an Platz 
gebraucht wird. Allerdings werden sie wenn möglich rein in Registern 
gehalten, wodurch sie zum Teil gar keinen Speicher brauchen.
#6165538
Lesenswert?

vn nn schrieb:
> Sebastian S. schrieb:
>>>Es hat aber auch einen großen Nachteil: Es ist zur Compilezeit nicht
>>>überschaubar, wie viel RAM man tatsächlich braucht. Und wenn die Daten
>>>zu groß für den Speicher sind, gibt's einfach nur fehlerhaftes
>>>Verhalten.
>> Stimmt, aber nur so kommt man auf ein "Minimum" zur Laufzeit und kann
>> nicht vergessen zu "putzen".
>
> Vor allem, da der Compiler dann versuchen wird, so viel wie möglich ohne
> RAM-Nutzung in den Registern zu erledigen.

Das macht der eh, wenn man nicht gerade Code hat, der nur mit -O0 
richtig läuft. Was der AVR auch macht: Globale Variablen immer mit 
kompletter Adresse ansprechen (also 2-Wort-LDS-STS, statt via 
Frameptr+ofs). Wenn man viele Funktionen mit kleinem lokalem 
Speicherbedarf hat, dann kann die "Stack-Variante" günstiger sein als 
die "Globals-Variante". BTW, "static type var;" ist auch "global".
Ich vermute die "static"-"Idee" stammt aus der 8051-Zeit. Dort sind 
Pointer-Zugriffe ein Horror.

Wenn man dann vom AVR Richtung ARM schaut, der hat so viele breite 
Index-Register zur Verfügung, daß lokal praktisch immer besser ist als 
(viele) globale Variablen. Wenn schon "global/static", dann wenigstens 
keine einzelnen Variablen, sondern Strukturen aus zusammen verwendeten 
Variablen. Dann kennt der Compiler für jede Variable den Offset 
innerhalb der Struktur und braucht (innerhalb gewisser Grenzen, ARM:4k) 
nur eine Basisadresse. Andernfalls: Mem-Adresse relative zum PC aus 
Flash holen und auf genau eine Variable zugreifen. Für jede einzelne 
Variable ein anderes Adressregister, bis diese ausgehen und dann 
eventuell eben mehrfach Adressen laden. Mit bis zu 4K-struct: einmal 
Basisadresse laden und dann Zugriff über Offset.
Selbst wenn man die 32bit nicht zum Rechnen braucht, die 
Adressierungsarten dieser CPU möchten man nicht mehr missen, hat man sie 
mal entdeckt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren