Wenn ich nun eine globale Variable erstelle, so wird das resultierende
Programm unnötig groß (abhängig von FIFO_SIZE). Jetzt wollte ich eine
automatische Initialisierung des internen Arrays unterbinden indem ich
die Struktur in die .noinit section verfrachte:
Matthias N. schrieb:> Wenn ich nun eine globale Variable erstelle, so wird das resultierende> Programm unnötig groß (abhängig von FIFO_SIZE).
Nein. Die Größe des Programms ändert sich dadurch überhaupt nicht.
Matthias N. schrieb:> Aber der Erfolg bleibt aus.
Ja, weil es eben nichts einzusparen gibt.
Bin direkt nochmal zurück zu AVR Studio 5 und habe folgendes
durchprobiert
Debug (No Optimisation):
#define FIFO_SIZE 64
Program: 3484 bytes Data: 150 bytes
#define FIFO_SIZE: 32
Program: 3420 bytes Data: 86 bytes
DiffProg: 64 bytes DiffData: 64 bytes
Release (Optimise for size):
#define FIFO_SIZE 64
Program: 2618 bytes Data: 150 bytes
#define FIFO_SIZE 32
Program: 2580 bytes Data: 86 bytes
DiffProg: 64 bytes DiffData: 64 bytes
Entspricht jeweils der zweifachen Instantiierung von fifo_t
Und die einzige Stelle wo sich durch das #define effektiv was ändert ist
diese hier:
1
fifo_t
2
rxFifo __attribute__ ((section (".noinit"))),
3
txFifo __attribute__ ((section (".noinit")));
Somit müssen ja anscheinend Daten generiert werden, die im Zusammenhang
mit der Initialisierung des Arrays stehen.
Wie lässt sich das unterbinden?
Hm. Mag sein, dass ich da was falsch einschätze, aber ich hätte auch
keine Änderung bei der Programmgrösse erwartet.
Vergleich doch mal die Map bzw. Listfiles. Dann sollte klarwerden, was
da passiert.
Am besten ein Minimalbeispiel machen, das diese Verhalten hat. Also die
Variable plus ein wenig Code der das manipuliert. Dann können wir das
bei uns evtl. nachvollziehen.
Ich habe mal irgendwo aufgeschnappt, dass globale variablen in c immer
initialisiert werden. Man müsste es nur ausschalten können.
Hier der Vollständigkeit halber meine Versuche und mein Ergebnis daraus:
GLOBAL:
1
#define SIZE 24
2
char buf[SIZE];
3
int main(void) { }
Program 116 (konstant), Data 24 (entspricht SIZE)
LOKAL:
1
#define SIZE 24
2
int main(void) {
3
volatile char buf[SIZE];
4
}
Program 120 (konstant), Data 0 (konstant)
WORKAROUND für Gloablen Buffer:
1
#define SIZE 24
2
volatile char *bufp;
3
int main(void) {
4
volatile char buf[SIZE];
5
bufp = buf;
6
}
Program 148 (konstant), Data 2 (konstant, entspricht Pointer-Grösse)
Die Variable liegt ab dem Eintritt in main() auf dem Stack und ist somit
gültig, solange die Routine, die sie initialisiert hat nicht wieder
verlassen wird.
Nicht schön, spart mir aber jetzt den benötigten Platz ein
Matthias N. schrieb:> Ich habe mal irgendwo aufgeschnappt, dass globale variablen in c immer> initialisiert werden.
Ja, aber wenn nichts explizites angegeben ist, mit 0. Und
Nullinitialisierte Variablen landen in der BSS-Sektion, die dann im
Startup-Code einfach nach memset-Manier mit 0 gefüllt wird. Daher
sollten deine Fifos eigentlich keinen zusätzlichen Flash-Speicher
verbrauchen. Es bleibt rätselhaft, warum das bei dir nicht funktioniert.
> GLOBAL:> #define SIZE 24> char buf[SIZE];> int main(void) { }>> Program 116 (konstant), Data 24 (entspricht SIZE)>> LOKAL:> #define SIZE 24> int main(void) {> volatile char buf[SIZE];> }>> Program 120 (konstant), Data 0 (konstant)
Also braucht das globale Array in diesem Fall keinen zusätzlichen
Speicher. Es scheint also nur dann nicht zu funktionieren, wenn du dein
Array in eine Struktur packst.
> WORKAROUND für Gloablen Buffer:> #define SIZE 24> volatile char *bufp;> int main(void) {> volatile char buf[SIZE];> bufp = buf;> }>> Program 148 (konstant), Data 2 (konstant, entspricht Pointer-Grösse)
Wozu soll das dann gut sein? Mehr Flash- und mehr RAM-Verbrauch.
Rolf Magnus schrieb:> Also braucht das globale Array in diesem Fall keinen zusätzlichen> Speicher. Es scheint also nur dann nicht zu funktionieren, wenn du dein> Array in eine Struktur packst.
Das ist dort aber nicht mehr global, sondern lokal in main() deklariert.
> Wozu soll das dann gut sein? Mehr Flash- und mehr RAM-Verbrauch.
Der entsteht durch den Code für den Kopiervorgang der Arrayadresse auf
den globalen Pointer.
OK, Profi Rolf war schneller, ich versuch's trotzdem...
Hallo Matthias,
ich mache eigentlich in Hardware, Software nur nebenbei, aber:
ich glaube Du bist auf der falschen Schiene.
Mit:
"fifo_t rxFifo"
wird die variable "rxFifo" in ihrer von Dir definierten Größe im RAM
angelegt, basta!
Wenn Du nun sagst:
"__attribute__ ((section (".noinit")))"
wird diese Variable in einen Speicherbereich verfrachtet, der nicht vom
Compiler explizit mit 0x00 vordefiniert wird; diese hat einen zufälligen
Wert der sich nach "Power On" zufällig einstellt.
"noinit" hat nix mit der Größe zu tun.
Kurzum, Du möchtest eine zur Laufzeit dynamische Variable,
hier ist Dein Stichwort: malloc (viel Spass).
*** hab gerade nochmal Deinen neuen Beitrag gelesen und sinniert.....
"resultierende Programm unnötig groß" ist natürlich so nicht richtig.
Dein RAM-Verbrauch ist dem entsprechend groß.
Na und ? wenn's reinpasst ? wurscht egal.
"Die Variable liegt ab dem Eintritt in main() auf dem Stack und ist
somit
gültig, solange die Routine, die sie initialisiert hat nicht wieder
verlassen wird.
Nicht schön, spart mir aber jetzt den benötigten Platz"
Trugschluß, Variablen werden ab "RAMSTART" draufgelegt, der Stack geht
von "RAMEND" runter!!! NIX GESPART.
Gruß Holger Sch
Erzeuge die assembler-listings für beide Versionen, und schau dir die
Unterschiede an. Danach weißt du, woher der zusätzliche Speicherbedarf
kommt.
Oliver
Matthias N. schrieb:> Rolf Magnus schrieb:>> Also braucht das globale Array in diesem Fall keinen zusätzlichen>> Speicher. Es scheint also nur dann nicht zu funktionieren, wenn du dein>> Array in eine Struktur packst.>> Das ist dort aber nicht mehr global, sondern lokal in main() deklariert.
Du meinst da wo "GLOBAL" drübersteht?
Das hier:
Matthias N. schrieb:> GLOBAL:> Program 116 (konstant), Data 24 (entspricht SIZE)> LOKAL:> Program 120 (konstant), Data 0 (konstant)
sagt doch aus, daß die globale Version nicht mehr Speicher braucht als
die lokale. Daß Data 24 Byte größer ist, liegt ja nur daran, daß die
Variable nicht wie bei der lokalen Version auf dem Stack liegt.
Benötigt werden die 24 Bytes natürlich in beiden Fällen,nur bei der
lokalen Version werden sie nicht angezeigt, weil die Stackbelegung zur
Compilezeit nicht bekannt ist.
Ahh, meine Anfangsformulierung war somit schon sehr ungüntig ;)
Klar, dass die Variable so oder so den benötigten RAM braucht, aber es
ging mir darum, dass der im Flash liegende Code unnötig aufgeblasen wird
;)
Somit, danke für die nachfolgenden Hinweise, die mir mal wieder zeigen,
dass ich meine Fragen klarer formulieren sollte ;)
Wenn es um den reinen Flashbedarf geht, dann hat der Workaround schon
hin.
holger schrieb:> Und volatile. Sehr sinnvoll in main() ;)
Nunja, habe ich geschrieben, damit die Optimierung mir nicht
reinquatscht ;)
Matthias N. schrieb:> Wenn es um den reinen Flashbedarf geht, dann hat der Workaround schon> hin.
Du hast doch in deinem eigenen Test selbst gezeigt, dass das nicht
stimmt:
> GLOBAL:> Program 116 (konstant), Data 24 (entspricht SIZE)> LOKAL:> Program 120 (konstant), Data 0 (konstant)
"Program" (und nur das) ist hier dein Flashbedarf.
Matthias N. schrieb:> Klar, dass die Variable so oder so den benötigten RAM braucht, aber es> ging mir darum, dass der im Flash liegende Code unnötig aufgeblasen wird> ;)>> Somit, danke für die nachfolgenden Hinweise, die mir mal wieder zeigen,> dass ich meine Fragen klarer formulieren sollte ;)>> Wenn es um den reinen Flashbedarf geht, dann hat der Workaround schon> hin.
Nicht .... wirklich.
Das wird alles mit 0 initialisiert. Der Linker sammelt alle diese
Variablen im Speicher und wenn das Programm hochfährt, kommt eine
Schleife zum Zug die diesen Speicher einfach mit 0 niederbügelt. Fertig.
Wenn du mehr 0-initialisierte Variablen hast, dann ändert das nicht
viel. Es wird einfach nur mehr Speicher mit 0 niedergebügelt, sprich die
Schleife hat einen anderen Endwert. Mehr passiert da nicht.
Wie erwartet vergößert sich die .bss-Section um 2×32 Bytes, die
.text-Section bleibt aber gleich. Stellt man die beiden FIFO-Variablen
in die .noinit-Section, steht in der Ausgabe von avr-size eben .noinit
anstelle von .bss, an den Zahlenwerten ändert sich aber nichts.
Matthias N. schrieb:> Ahh, meine Anfangsformulierung war somit schon sehr ungüntig ;)
Die glaube ich verstanden zu haben. Nur deine Schlußfolgerungen ergeben
irgendwie keinen Sinn.
> Klar, dass die Variable so oder so den benötigten RAM braucht, aber es> ging mir darum, dass der im Flash liegende Code unnötig aufgeblasen wird> ;)
Aber der Flash-Verbrauch ist doch bei der Variante GLOBAL am geringsten.
> Wenn es um den reinen Flashbedarf geht, dann hat der Workaround schon> hin.
Inwiefern? Wenn ich mir die Zahlen ansehe:
Matthias N. schrieb:> GLOBAL:> Program 116 (konstant), Data 24 (entspricht SIZE)> LOKAL:> Program 120 (konstant), Data 0 (konstant)> WORKAROUND für Gloablen Buffer> Program 148 (konstant), Data 2 (konstant, entspricht Pointer-Grösse)
sehe ich, daß die Variante GLOBAL am wenigsten Flash-Speicher braucht
und der "Workarund" am meisten.
Dann hing ich bisher dem Irrglauben an, dass das, was in .data steht, zu
beginn vom Flash "EINS ZU EINS" in den RAM kopiert wird.
Ich hatte diese Werte immer addiert und den Speicherbedarf eines
Programmes zu bestimmen.
Wenn das ganze in einer Schleife erfolgt, sieht es natürlich anders aus.
Danke.
Matthias N. schrieb:> Dann hing ich bisher dem Irrglauben an, dass das, was in .data steht, zu> beginn vom Flash "EINS ZU EINS" in den RAM kopiert wird.
Für die Section .data stimmt das ja auch. Aber deine Angaben sind ja
wohl offensichtlich das, was am Ende des Build-Outputs als "Program" und
"Data" ausgegeben wird. Und das "Data" dort entspricht nicht der Section
.data. Es steht dabei, wie sich das zusammensetzt, du musst es nur genau
anschauen:
1
Program: 3208 bytes (39.2% Full)
2
(.text + .data + .bootloader)
3
4
Data: 108 bytes (10.5% Full)
5
(.data + .bss + .noinit)
Wie du siehst, .data ist in "Program" bereits enthalten.
Und worum es hier geht, ist .bss. Das ist der Bereich mit den Null
initialisierten Variablen, der beim Startup per Schleife genullt wird.