Forum: Compiler & IDEs [ARM-GCC] malloc Page Size 4096 Byte änderbar?


von Mampf F. (mampf) Benutzerseite


Lesenswert?

Guten Mittag,

auf meinem Cortex M4 (STM32F429) verbraucht ein malloc immer mindestens 
4096 Byte - auch wenn ich nur Speicher für ein Struct anfordere, das 
selbst sizeof(x)=28 Byte hat.

Da ich kein OS und keine MMU mit virtueller Speicherverwaltung hab, 
erschließt sich mir der Sinn einer 4096-Byte "Page-Size" absolut nicht 
...

Kann man das dem Malloc austreiben?

*edit*: Hmm, man muss wohl die newlib mit -DSMALL_MEMORY kompilieren, 
dann bekommt man eine Page-Size von 128Byte ... Was ist denn das für ein 
Unsinn? kotz

Viele Grüße,
Mampf

: Verschoben durch Admin
von Carl D. (jcw2)


Lesenswert?

Das schöne an OpenSource ist, man darf reinschauen ;-)
Irgendwo wird malloc eben per sbrk() eine neue Seite vom 
"Betriebssystem" anfordern. Es gibt aber auch die AVRlibc, da ist die 
Heapverwaltung sicher für RAM kleiner 4k ausgelegt. Wenn es nur darum 
geht, eine vorher nicht genau bekannte Anzahl struct28 zu verwalten, 
dann böte sich auch ein Pool solcher Objekte (sprich Array) an. Auch 
Pools in 2er Potenzen Größe sind eine Möglichkeit. Deine ARMlib scheint 
sich am Raspi zu orientieren ;-)

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Carl D. schrieb:
> Das schöne an OpenSource ist, man darf reinschauen ;-)

Oh, wir hatten zeitgleich gepostet ... Ich hatte editiert, du hattest 
gepostet ...

Ich hatte geschrieben:

> Hmm, man muss wohl die newlib mit -DSMALL_MEMORY kompilieren,
> dann bekommt man eine Page-Size von 128Byte ... Was ist denn das für ein
> Unsinn? kotz

Also neu kompilieren :/

von Peter II (Gast)


Lesenswert?

Mampf F. schrieb:
> Kann man das dem Malloc austreiben?

ist das bei jedem malloc aufruf so oder nur beim ersten?

Was passiert wenn du 2 mal malloc(28) machst, sind dann 4096 oder 8192 
weg?

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Peter II schrieb:
> Mampf F. schrieb:
>> Kann man das dem Malloc austreiben?
>
> ist das bei jedem malloc aufruf so oder nur beim ersten?
>
> Was passiert wenn du 2 mal malloc(28) machst, sind dann 4096 oder 8192
> weg?

8192 ... Und bei 1230*6 mallocs sind es dann 28,8MB :/

Ich hab - weil ich externes SDRAM verwende - die _sbrk-Funktion selbst 
implementiert und dort sieht man ganz schön, dass es immer Blöcke zu 
4096 Bytes sind, die angefordert werden.

Glaub ich versuch einen großen Memory-Block von malloc zu bekommen und 
organisier meine Daten innerhalb des Blocks selbst, dann kann ich ihn 
auch auf die SD-Karte schreiben und wieder verwenden. (Der Teil ist ein 
ID3v2-Scanner für um die 1500 MP3s).

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Mampf F. schrieb:
> 8192 ... Und bei 1230*6 mallocs sind es dann 28,8MB :/
>
> Ich hab - weil ich externes SDRAM verwende - die _sbrk-Funktion selbst
> implementiert und dort sieht man ganz schön, dass es immer Blöcke zu
> 4096 Bytes sind, die angefordert werden.

kann ich mir gar nicht vorstellen, das jemand so etwas macht. Sicher das 
du dir nicht selber so einen Fehler eingebaut hast?

Ist es in der Original Toolchain auch so?

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Peter II schrieb:
> kann ich mir gar nicht vorstellen, das jemand so etwas macht. Sicher das
> du dir nicht selber so einen Fehler eingebaut hast?

Nein, das macht eigentlich schon Sinn, wenn man viiiel RAM und ein OS 
mit MMU hat ... Eine virtuelle Page hat ebenfalls 4k, da passt das gut 
zusammen.

> Ist es in der Original Toolchain auch so?

Aus dem Source-Code:
1
#ifndef _WIN32
2
#ifdef SMALL_MEMORY
3
#define malloc_getpagesize (128)
4
#else
5
#define malloc_getpagesize (4096)
6
#endif
7
#endif

https://github.com/eblot/newlib/blob/master/newlib/libc/stdlib/mallocr.c

Das macht malloc, um den Memory für die MMU an 4kB-Grenzen auszurichten.

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Mampf F. schrieb:
> 8192 ... Und bei 1230*6 mallocs sind es dann 28,8MB :/
>
> Ich hab - weil ich externes SDRAM verwende - die _sbrk-Funktion selbst
> implementiert und dort sieht man ganz schön, dass es immer Blöcke zu
> 4096 Bytes sind, die angefordert werden.
>
> Glaub ich versuch einen großen Memory-Block von malloc zu bekommen und
> organisier meine Daten innerhalb des Blocks selbst, dann kann ich ihn
> auch auf die SD-Karte schreiben und wieder verwenden. (Der Teil ist ein
> ID3v2-Scanner für um die 1500 MP3s).

Sind die 2 malloc's für unterschiedlich große Objekte? Wenn ja, dann 
verwaltet malloc intern 2 Pools dafür.
"externes SDRAM" impliziert aber, daß eine 4k-Pool-Größe nicht so 
verkehrt ist.

von Peter II (Gast)


Lesenswert?

Mampf F. schrieb:
> Nein, das macht eigentlich schon Sinn, wenn man viiiel RAM und ein OS
> mit MMU hat ... Eine virtuelle Page hat ebenfalls 4k, da passt das gut
> zusammen.

selbst auf einem PC wird es nicht gemacht, dort man viel RAM und eine 
MMU.

malloc -> heapverwaltung -> VirtualAlloc

erst VirtualAlloc holt sich komplette Pages.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Ich hab es jetzt so gelöst:
1
void* mymalloc(int s) {
2
  caddr_t addr = _sbrk(s+3);
3
  return (void*) ((uint32_t) (addr+3) & ~0x3);
4
}

Jetzt passts auch mit dem RAM ;-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Mampf F. schrieb:
> Jetzt passts auch mit dem RAM ;-)

Wenn Du nun mymalloc() verwendest, dann hattest Du gar nicht vor, eine 
dynamische Speicherverwaltung zu verwenden. Dynamisch heisst nämlich, 
dass man die Speicherbereiche auch wieder freigibt, wenn man sie nicht 
mehr benötigt, um sie dann später anderweitig zu benutzen. Diesen Weg 
hast Du Dir ja nun verbaut.

Offenbar brauchst Du nur N von solchen Strukturen. Warum legst Du sie 
dann nicht einfach statisch an?

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Frank M. schrieb:
> Wenn Du nun mymalloc() verwendest, dann hattest Du gar nicht vor, eine
> dynamische Speicherverwaltung zu verwenden. Dynamisch heisst nämlich,
> dass man die Speicherbereiche auch wieder freigibt, wenn man sie nicht
> mehr benötigt, um sie dann später anderweitig zu benutzen. Diesen Weg
> hast Du Dir ja nun verbaut.

Richtig ... und ohne OS hat man auch keine richtige Speicherverwaltung, 
d.h. es gibt keine Funktionen, um wieder Speicher freizugeben und ihn 
wieder zu verwenden.

Frank M. schrieb:
> Offenbar brauchst Du nur N von solchen Strukturen. Warum legst Du sie
> dann nicht einfach statisch an?

Das wär eine ziemliche Speicherverschwendung :)

von STM Apprentice (Gast)


Lesenswert?

Warum nutzt du nicht die statische Speicherzuweisung mittels
Linker Script und attribute section ?

von Carl D. (jcw2)


Lesenswert?

Mampf F. schrieb:
> Frank M. schrieb:
>> Wenn Du nun mymalloc() verwendest, dann hattest Du gar nicht vor, eine
>> dynamische Speicherverwaltung zu verwenden. Dynamisch heisst nämlich,
>> dass man die Speicherbereiche auch wieder freigibt, wenn man sie nicht
>> mehr benötigt, um sie dann später anderweitig zu benutzen. Diesen Weg
>> hast Du Dir ja nun verbaut.
..
> Richtig ... und ohne OS hat man auch keine richtige Speicherverwaltung,
> d.h. es gibt keine Funktionen, um wieder Speicher freizugeben und ihn
> wieder zu verwenden.
..
> Frank M. schrieb:
>> Offenbar brauchst Du nur N von solchen Strukturen. Warum legst Du sie
>> dann nicht einfach statisch an?
>
> Das wär eine ziemliche Speicherverschwendung :)

Deshalb macht Freigabe auch ohne OS Sinn. Es geht nicht um Rückgabe an 
das OS, sondern um Wiederverwendung nur temporär benötigter 
Speicher-Ressourcen.

von Dr. Sommer (Gast)


Lesenswert?

Mampf F. schrieb:
> Das wär eine ziemliche Speicherverschwendung :)
Na und? Da du den Speicher ja anscheinend ohnehin nicht für etwas 
anderes nutzt, ist es völlig egal ob du den direkt zu Beginn für diesen 
einen Zweck reservierst oder erst später. Für "nicht belegten" Speicher 
gibt es kein Geld zurück... Wie ukw schon korrekt angemerkt hat, macht 
dynamische Speicherverwaltung mit new/malloc nur genau dann Sinn, wenn 
du den Speicher für verschiedene Dinge abwechselnd brauchst, du aber 
vorher nicht weiß wieviel wofür gebraucht wird und so eben dynamisch 
zugewiesen wird. Wenn der RAM deines Systems groß genug für deinen 
gesamten Bedarf ist, allokiere einfach alles statisch (am Besten zentral 
in 1 Datei, die Instanzen aller Klassen anlegt) - das ist 
übersichtlicher, einfacher, effizienter, und produziert keine 
Out-Of-Memory-Fehler mitten im Betrieb...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Mampf F. schrieb:
> Richtig ... und ohne OS hat man auch keine richtige Speicherverwaltung,
> d.h. es gibt keine Funktionen, um wieder Speicher freizugeben und ihn
> wieder zu verwenden.

Das stimmt so nicht. Speicherbereiche, die ich mit free() wieder 
freigebe, kann ich später im Programm auch ohne OS mittels malloc() 
wiederverwenden.

> Das wär eine ziemliche Speicherverschwendung :)

Das verstehe ich nicht. Willst Du den Speicher schonen oder bekommst Du 
für unbenutzten Speicher Geld zurück? Wenn Du von vornherein weisst, 
dass Du maximal ein Dutzend von diesen 128-Byte-Structs brauchst, dann 
kannst Du dieses Dutzend auch statisch anlegen. Das ist keine größere 
Verschwendung, als wenn Du zur Laufzeit 12 mal 128 Bytes per mymalloc() 
anforderst. Die "Verschwendung" ist absolut dieselbe.

Du hast sogar einen Vorteil bei der statischen Speicheranforderung: Du 
bemerkst schon zur Compile-Zeit knappes RAM. Wenn der Fehler erst zur 
Laufzeit zutage tritt, wird es fies...

: Bearbeitet durch Moderator
von Mampf F. (mampf) Benutzerseite


Lesenswert?

Carl D. schrieb:
> Deshalb macht Freigabe auch ohne OS Sinn. Es geht nicht um Rückgabe an
> das OS, sondern um Wiederverwendung nur temporär benötigter
> Speicher-Ressourcen.

Das macht man über lokale Variablen (quasi über den Stack ...) ;-)

Daten, die im SDRAM liegen, werden länger benötigt.

Leute, ich glaub nicht, dass man darüber diskutieren muss, wie ich 
meinen SDRAM verwende ... Ich mach es nach Lust und Laune und wie ich 
mir denke, dass es sinnvoll ist :)

Der Speicher im SDRAM wird tatsächlich nicht wieder verwendet ... 
Riesige Teile davon sind zirkulare Puffer für Dynamic-Compression, DMA 
und und und ...

Ein Teil, der nur beim Start initialisiert wird, erhält die 
ID3-Tag-Datenbank (da ändert sich vmtl nichts).

Trotzdem kann mir keiner verbieten, dass ich für jeden einzelnen String 
meiner ID3-Tags einen malloc aufrufe ... Ich werde sicher nicht statisch 
allokiertem RAM um mich werfen. Wofür denn auch, es gibt hierzu keinen 
Grund.

Ich denke, ich hab genug Erfahrung in den letzten 25 Jahren gesammelt, 
dass ich weiß, was sinnvoll ist und was nicht :-)

: Bearbeitet durch User
von Carl D. (jcw2)


Lesenswert?

Mampf F. schrieb:
> Ich denke, ich hab genug Erfahrung in den letzten 25 Jahren gesammelt,
> dass ich weiß, was sinnvoll ist und was nicht :-)

wozu fragst du dann?

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Carl D. schrieb:
> Mampf F. schrieb:
>> Ich denke, ich hab genug Erfahrung in den letzten 25 Jahren gesammelt,
>> dass ich weiß, was sinnvoll ist und was nicht :-)
>
> wozu fragst du dann?

Hab ich nicht ... Mit keinem Wort hab ich gefragt, wie ich meinen SDRAM 
verwenden soll^^

von Carl D. (jcw2)


Lesenswert?

Mampf F. schrieb:
> Carl D. schrieb:
>> Mampf F. schrieb:
>>> Ich denke, ich hab genug Erfahrung in den letzten 25 Jahren gesammelt,
>>> dass ich weiß, was sinnvoll ist und was nicht :-)
>>
>> wozu fragst du dann?
>
> Hab ich nicht ... Mit keinem Wort hab ich gefragt, wie ich meinen SDRAM
> verwenden soll^^

Erster Post:
> Kann man das dem Malloc austreiben?

Wenn man nach 25Jahren immer noch nicht ahnt, daß eine Heapverwaltung 
irgendwo im Sourcecode die Anforderungsblockgröße stehen hat...

von Peter II (Gast)


Lesenswert?

Mampf F. schrieb:
> Trotzdem kann mir keiner verbieten, dass ich für jeden einzelnen String
> meiner ID3-Tags einen malloc aufrufe ... Ich werde sicher nicht statisch
> allokiertem RAM um mich werfen. Wofür denn auch, es gibt hierzu keinen
> Grund.

man kann es auch anders rum sehen, warum malloc verwenden wenn es keine 
grund gibt? Dazu kommt noch die Fehlerbehandlung wenn malloc mal keine 
Speicher mehr hat. Das Programm wird damit nur komplizierter und bietet 
keinen Vorteil. Code den man spart verringert auch die Anzahl an 
Fehlern.

von TriHexagon (Gast)


Lesenswert?

Mampf F. schrieb:
> Richtig ... und ohne OS hat man auch keine richtige Speicherverwaltung,
> d.h. es gibt keine Funktionen, um wieder Speicher freizugeben und ihn
> wieder zu verwenden.

Da liegt wohl ein Missverständnis vor, du brauchst kein OS um einen 
richtigen Heap zu implementieren, der Speicher zuweisen und wieder 
freigeben kann. Ich habe selber mal einen Heap implementiert, der das 
kann (mit "first fit" Strategie), ist nicht schwer und gar nicht so viel 
Aufwand. Ein OS wird erst interessant, wenn Paging und virtuelle 
Adressierung ins Spiel kommt.

Peter II schrieb:
> Mampf F. schrieb:
>> Trotzdem kann mir keiner verbieten, dass ich für jeden einzelnen String
>> meiner ID3-Tags einen malloc aufrufe ... Ich werde sicher nicht statisch
>> allokiertem RAM um mich werfen. Wofür denn auch, es gibt hierzu keinen
>> Grund.
>
> man kann es auch anders rum sehen, warum malloc verwenden wenn es keine
> grund gibt? Dazu kommt noch die Fehlerbehandlung wenn malloc mal keine
> Speicher mehr hat. Das Programm wird damit nur komplizierter und bietet
> keinen Vorteil. Code den man spart verringert auch die Anzahl an
> Fehlern.

Da kann ich nur zustimmen, malloc zu verwenden obwohl man es nicht 
braucht, macht eigentlich nur Probleme. Es wird schnell unübersichtlich, 
ob der Speicher bei jedem Programmverlauf ausreicht oder nicht. Bei 
statischer Speicherverwaltung kannst du direkt sehen wie viel gebraucht 
wird (wenn man mal vom Stack absieht) und Probleme zuverlässig aus dem 
Weg gehen.

von Rolf M. (rmagnus)


Lesenswert?

Mampf F. schrieb:
>> Was passiert wenn du 2 mal malloc(28) machst, sind dann 4096 oder 8192
>> weg?
>
> 8192 ... Und bei 1230*6 mallocs sind es dann 28,8MB :/

Dann hast du irgendwas falsch gemacht.

> Ich hab - weil ich externes SDRAM verwende - die _sbrk-Funktion selbst
> implementiert und dort sieht man ganz schön, dass es immer Blöcke zu
> 4096 Bytes sind, die angefordert werden.

Ja, das ist ganz normal. Es wäre aber völliger Blödsinn, wenn für jede 
Allkoation von 28 Bytes ein separater 4k-Block verwendet würde. Dann 
würden ja für deinen Fall pro allokierter Struktur 4068 von den 4096 
Bytes verschwendet, also ungefähr 99,3% des Speichers.

Mampf F. schrieb:
> Peter II schrieb:
>> kann ich mir gar nicht vorstellen, das jemand so etwas macht. Sicher das
>> du dir nicht selber so einen Fehler eingebaut hast?
>
> Nein, das macht eigentlich schon Sinn, wenn man viiiel RAM und ein OS
> mit MMU hat ...

Nein, macht es nicht. Auch dort ist ein Overhead von über 99% nicht 
sinnvoll.

> Eine virtuelle Page hat ebenfalls 4k, da passt das gut
> zusammen.

Keiner bestreitet, dass eine Blockgröße von 4k sinnvoll ist. Aber für 
jedes Objekt, egal wie groß, immer ein Vielfaches von 4k zu allokieren, 
ist nicht sinnvoll.

Mampf F. schrieb:
> Richtig ... und ohne OS hat man auch keine richtige Speicherverwaltung,
> d.h. es gibt keine Funktionen, um wieder Speicher freizugeben und ihn
> wieder zu verwenden.

Doch, natürlich gibt es die. Was bringt mir denn auch eine dynamische 
Speicherverwaltung, wenn ich den Speicher einmal am Anfang allokiere und 
dann für immer so lasse?

Mampf F. schrieb:
> Carl D. schrieb:
>> Deshalb macht Freigabe auch ohne OS Sinn. Es geht nicht um Rückgabe an
>> das OS, sondern um Wiederverwendung nur temporär benötigter
>> Speicher-Ressourcen.
>
> Das macht man über lokale Variablen (quasi über den Stack ...) ;-)

Die bleiben aber nur bis zum Rücksprung aus der Funktion gültig, in der 
sie definiert sind. Außerdem kann man im Gegensatz zu dynamischem 
Speicher nicht prüfen, ob überhaupt noch genug davon vorhanden ist. 
Also: Anderer Anwendungsfall.

> Leute, ich glaub nicht, dass man darüber diskutieren muss, wie ich
> meinen SDRAM verwende ... Ich mach es nach Lust und Laune und wie ich
> mir denke, dass es sinnvoll ist :)

Das steht dir natürlich frei. Uns steht aber frei, dich darauf 
hinzuweisen, dass deine Herangehensweise unsinnig erscheint.

> Der Speicher im SDRAM wird tatsächlich nicht wieder verwendet ...
> Riesige Teile davon sind zirkulare Puffer für Dynamic-Compression, DMA
> und und und ...

Dann verstehe ich nicht, was dir da malloc bringen soll.

> Trotzdem kann mir keiner verbieten, dass ich für jeden einzelnen String
> meiner ID3-Tags einen malloc aufrufe ... Ich werde sicher nicht statisch
> allokiertem RAM um mich werfen. Wofür denn auch, es gibt hierzu keinen
> Grund.

Ich sehe es eher umgekehrt: Wozu den Umstand machen, den Speicher 
dynamisch zu allokieren, wenn sich eh nichts dynamisch dran ändert?

von Carl D. (jcw2)


Lesenswert?

Rolf M. schrieb:
>
> Keiner bestreitet, dass eine Blockgröße von 4k sinnvoll ist. Aber für
> jedes Objekt, egal wie groß, immer ein Vielfaches von 4k zu allokieren,
> ist nicht sinnvoll.

Vermutlich wird die Heapverwaltung Pools für Objekt verschiedener 
Größenklassen bilden. Und wenn man dann Strings allokiert, dann ist die 
Größenvarianz 100%ig sicher:

>> Trotzdem kann mir keiner verbieten, dass ich für jeden einzelnen String
>> meiner ID3-Tags einen malloc aufrufe ... Ich werde sicher nicht statisch
>> allokiertem RAM um mich werfen.

Bei kleinem RAM und Strings kann ein Allokator natürlich auch einfach 
einen Block verwalten, in den man die Strings hintereinander hängt. 
Verwaltungdaten sind dann ein Zeiger auf den Block, einer aufs(/hinters) 
End und einer auf den aktuellen Füllstand. Einschränkung: keine 
Einzelfreigebe.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Carl D. schrieb:
> Vermutlich wird die Heapverwaltung Pools für Objekt verschiedener
> Größenklassen bilden. Und wenn man dann Strings allokiert, dann ist die
> Größenvarianz 100%ig sicher:

Dann schon. Ich bin aber davon ausgegangen, dass es auch auftritt, wenn 
er immer die gleiche Größe allokiert. Das könnte man zumindest da 
rauslesen:

Mampf F. schrieb:
>> Was passiert wenn du 2 mal malloc(28) machst, sind dann 4096 oder 8192
>> weg?
>
> 8192 ... Und bei 1230*6 mallocs sind es dann 28,8MB :/

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Vielen Dank für all eure Antworten!

Ich denke ihr habt Recht - das macht keinen Sinn für jeden Mini-Alloc 4k 
RAM zu allozieren ... Also irgendwas ist da wohl gründlich schief 
gelaufen.

Man würde dann auch mehr Foren-Threads zu dem Problem finden, da es ja 
schon erhebliche Auswirkungen hat.

Ich werd mal tiefer reinkucken und versuchen zu Debuggen, warum das 
passiert ist.

VG
Mampf

von Markus F. (mfro)


Lesenswert?

Ich würde mich sehr wundern, wenn newlib sich so wie beschrieben 
verhielte.

Natürlich allokiert ein malloc()-Aufruf (sehr) viel größere Blöcke als 
angefordert - das ist völlig normal und das machen alle dynamischen 
Speicherverwaltungen so, die ich kenne.

Ein malloc(16) allokiert also 4 kByte (oder was auch immer in 
malloc_getpagesize steht) - obwohl Du nur 16 Bytes haben willst. Das 
nächste malloc(16) allokiert aber keineswegs nochmal 4 kByte, sondern 
vergibt die nächsten 16 Bytes (+ "unsichtbaren" Verwaltungs-Overhead) 
aus dem bereits allokierten Block. Solange, bis der "verbraucht" ist 
(dann wird ein neuer, "großer" Block allokiert).

Wenn malloc(16) tatsächlich nur 16 Bytes allokieren würde, wo bliebe 
dann der Verwaltungs-Overhead?

Newlib-Malloc() schreibt den Overhead vor und hinter den "kleinen" 
allokierten Block im "großen". Verschmelzen von aneinanderliegenden 
freien Blöcken bei free() wird dann ganz einfach: der erste Block 
"vereinnahmt" einfach den zweiten.

Wie würdest Du das wohl sonst machen, wenn Du das selber machen 
müsstest?

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Markus F. schrieb:
> Ein malloc(16) allokiert also 4 kByte (oder was auch immer in
> malloc_getpagesize steht) - obwohl Du nur 16 Bytes haben willst. Das
> nächste malloc(16) allokiert aber keineswegs nochmal 4 kByte, sondern
> vergibt die nächsten 16 Bytes (+ "unsichtbaren" Verwaltungs-Overhead)
> aus dem bereits allokierten Block. Solange, bis der "verbraucht" ist
> (dann wird ein neuer, "großer" Block allokiert).

Ja genau, das war das Problem. Bei mir wurde jedesmal 4kB angefordert, 
egal wie wenig ich eigentlich benötigt habe.

Ich konnte zusehen, wie das meinen RAM auffrisst (der ARM hängt an einem 
ESP8266 und per Browser kann ich meinen SDRAM-Verbrauch in Echtzeit 
ansehen, während die ID3-Tags gelesen werden).

Um die 10MB für 1300 ID3-Tags ... Mit der "mymalloc"-Änderung war das 
nur noch im kB-Bereich.

Aber wie gemeint, irgendwas ist da wohl schief gegangen ...

Vlt entsorge ich - wie mir mehrfach vorgeschlagen wurde - die komplette 
dynamische Speicher"verwaltung".

Die großen und schnellen Controller verführen zudem zu netten Features 
wie die C++ STL ... Aber ein std::vector oder eine std::map verwendet 
auch dynamisch allozierten Speicher.

Also entweder ganz oder gar nicht ... Schade eigentlich :)

von Markus F. (mfro)


Lesenswert?

Mampf F. schrieb:
> Ja genau, das war das Problem. Bei mir wurde jedesmal 4kB angefordert,
> egal wie wenig ich eigentlich benötigt habe.

Dann hast Du - das ist zumindest, was mir zuerst einfiele - 
möglicherweise irgendwie die internen Verwaltungsinformationen 
kaputtgeschrieben, die newlib zur Verwaltung der "kleinen" Blöcke vor 
dem eigentlich allokierten Speicher ablegt.

Oder mit deiner newlib ist irgendwas grundsätzlich faul.

: Bearbeitet durch User
von Markus F. (mfro)


Lesenswert?

Mampf F. schrieb:
> Vlt entsorge ich - wie mir mehrfach vorgeschlagen wurde - die komplette
> dynamische Speicher"verwaltung".

Die kompromisslosen Verfechter von irgendwas (man könnte auch 
"Fanatiker" sagen) haben selten in allen Fällen recht.

Was für deine Anwendung richtig oder falsch ist, kannst letztendlich nur 
Du entscheiden.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Markus F. schrieb:
> Dann hast Du - das ist zumindest, was mir zuerst einfiele -
> möglicherweise irgendwie die internen Verwaltungsinformationen
> kaputtgeschrieben, die newlib zur Verwaltung der "kleinen" Blöcke vor
> dem eigentlich allokierten Speicher ablegt.

Mmhmm, interessant ...

Bei mir wird das SDRAM nicht in der Startup initialisiert sondern erst 
in der Main-Methode.

Ich hab in der _sbrk eine Unterscheidung, ob das SDRAM schon 
initialisiert wurde oder nicht und entweder wird dann internes RAM 
allokiert oder SDRAM.

Evtl geht hier irgendwas schief beim Umschalten ... Ich schalte mal die 
Unterscheidung aus und teste mal, ob das Verhalten sich dann ändert.

von root (Gast)


Lesenswert?

Das ganze nennt sich "Root Cause Analysis". erstmal alle falschen 
Entscheidungen finden und die darauf basierende Implementierungen 
überprüfen.

Es ist völlig unüblich das SDRAM erst im Main zu implementieren.

Leider ist es schon länger her das ich mit STM Controllern gearbeitet 
habe
Deshalb kann ich nicht genau sagen wie du die Initialisierung des SDRAM 
in deinen Startup Code bekommst. Wenn du das aber geschafft hast und 
auch die Linker Scripts entsprechend angepasst sind dann brauchst du 
keine eigne Implementierung  für _sbrk

von Sebastian V. (sebi_s)


Lesenswert?

root schrieb:
> Es ist völlig unüblich das SDRAM erst im Main zu implementieren.

Ist doch total egal ob in der main Funktion oder in der "Startup" 
Funktion die dann die main aufruft. SDRAM ist nicht so super wichtig, 
dass er direkt am Anfang initialisiert werden muss. Außer man hat mit 
C++ globale Objekte irgendwo rumliegen die schon vor der main dynamisch 
Speicher reservieren. Dann müsste man es tatsächlich vorher machen.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Sebastian V. schrieb:
> root schrieb:
>> Es ist völlig unüblich das SDRAM erst im Main zu implementieren.
>
> Ist doch total egal ob in der main Funktion oder in der "Startup"
> Funktion die dann die main aufruft. SDRAM ist nicht so super wichtig,
> dass er direkt am Anfang initialisiert werden muss.

STs HAL-Framework sieht eine Initialisierung im Startup-Code sogar vor, 
aber nach 3h debuggen hab ich es nicht zum Laufen bekommen, obwohl es 
von den Registern passen hätte müssen - dann nahm ich den bequemeren 
Weg^^

: Bearbeitet durch User
von Mampf F. (mampf) Benutzerseite


Lesenswert?

Hah, jetzt hab ich das mit dem SDRAM im Startup hinbekommen.

In den Templates oder Beispielen war ja quasi alles unpassend von der 
SDRAM- bis zur GPIO-Konfiguration.

SDRAM wird brav initialisiert und ein Memory-Test direkt am Anfang der 
Main sagt, dass es funktioniert.

Dummerweise bekomm ich bei der bss-Initialisierung noch einen 
Hard-Fault, obwohl zuvor das SDRAM schon initialisiert wurde ...

Muss mal schauen, was das noch ist.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Ah jetzt hab ich es!

Jetzt kann ich meine statischen Riesen-Arrays definieren ... Weil das 
nicht ging, hatte ich malloc verwendet ;-)

Die Sections liegen jetzt in:

.text FLASH
.data RAM
.bss SDRAM
.heap SDRAM
.stack RAM

Dachte mir, es wäre eine gute Idee, den Stackpointer im RAM zu lassen :)

Eine _sbrk-Funktion brauch ich jetzt nicht mehr.

Vielen Dank nochmal an alle, ich hätte mir das Problem nicht nochmal 
angeschaut, wären von euch keine Einwände gekommen :)

: Bearbeitet durch User
von Mampf F. (mampf) Benutzerseite


Lesenswert?

Gibt's doch nicht ... Bin ich der einzige, der die STM32 jemals mit 
externem SDRAM verwendet hat?

Im Startup-Code (startup_stm32f4xx.s) erfolgt die 
Hardware-Initialisierung NACH DEM NULLEN des BSS-Bereichs.

Klar, dass dann alle Variablen, die sich in BSS befinden, irgendeinen 
alten Datenschrott enthalten und so dann garnichts funktioniert.

Unglaublich, was ist das für ein unausgegorener Schrott!

von Nop (Gast)


Lesenswert?

Mampf F. schrieb:

> Unglaublich, was ist das für ein unausgegorener Schrott!

Die ST-Software hat ja auch keinen so guten Ruf, jetzt weißt Du wieso. 
Möglicherweise ist das deswegen nicht aufgefallen, weil das SDRAM im 
Test bloß für den Heap benutzt wurde.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Nop schrieb:
> weil das SDRAM im
> Test bloß für den Heap benutzt wurde.

In den Beispielprojekten von ST leider nicht ... Da haben sie die 
RAM-Section direkt auf das SDRAM gelegt, d.h. data, bss, stack(!!!) sind 
alle im SDRAM.

Aber das hätte ja nie richtig funktionieren können ... Data enthält 
initialisierte Daten und die wären dann auch nicht in das SDRAM kopiert 
worden. Ich hab die startup-Sourcen von den Projekten mit meinen 
verglichen und die haben das gleiche Problem.

Muss mal schauen, wo man einen Bug-Report submitten kann^^

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Mampf F. schrieb:
> Guten Mittag,
>
> auf meinem Cortex M4 (STM32F429) verbraucht ein malloc immer mindestens
> 4096 Byte - auch wenn ich nur Speicher für ein Struct anfordere, das
> selbst sizeof(x)=28 Byte hat.
>
> Da ich kein OS und keine MMU mit virtueller Speicherverwaltung hab,
> erschließt sich mir der Sinn einer 4096-Byte "Page-Size" absolut nicht
> ...
>
> Kann man das dem Malloc austreiben?
>
> *edit*: Hmm, man muss wohl die newlib mit -DSMALL_MEMORY kompilieren,
> dann bekommt man eine Page-Size von 128Byte ... Was ist denn das für ein
> Unsinn? *kotz*

Vielleicht war dein Distributor nicht sonderlich achtsam beim Erstellen 
der Toolchain.

SMALL_MEMORY hat nur eine Wirkung wenn INTERNAL_NEWLIB gesetzt ist.  Per 
default ist letzteres nicht gesetzt, es sei denn Newlib ist Teil einer 
Cygwin Distribution (und falls die seehr ausführlichen Newlib-Kommantare 
stimmen).

SMALL_MEMORY hat in diesem Fall Wirkung auf Definition von 
malloc_getpagesize(); falls es in dem Block nicht festgelegt wird — was 
wie gesagt default ist — gibt es weiter unten feinziselierte Möglichkeit 
der Festlegung von malloc_getpagesize() anhängig von (System)Headern.

Insbesondere wird, falls HAVE_GETPAGESIZE defined ist,
1
extern size_t getpagesize();
2
#define malloc_getpagesize getpagesize()
gesetzt, so dass die Seitengröße konfigurierbar ist, etwa indem die 
Implementierung ein mit default-Wert vorbelegte Variable liest oder den 
Wert eines Symbols, das im Linker-Skript nur denn gesetzt wird, wenn es 
nicht bereits definiert ist.

Im letzten Falle könnte man dann die Pagesize sogar erst zur Link-Time 
angeben qua -Wl,--defsym,my_malloc_page_size=128 und es wäre noch 
nichtmal Neucompilieren der Quellen nötig um eine andere Pagesize zu 
bekommen — neu Linken würde genügen.

Aber wie gesagt, hängt alles davon ab, wie achtsam deine Distribution 
zusammengestellt wurde...

: Bearbeitet durch User
von Mampf F. (mampf) Benutzerseite


Lesenswert?

Hah, alles umsonst ;-)

Nachdem jetzt alles funktioniert, funktioniert das wichtigste nicht mehr 
... Meine MP3s werden nicht mehr in der nötigen Geschwindigkeit 
abgespielt.

Also wieder zurückkonfiguriert, BSS landet wieder im internen RAM, für 
die großen Puffer gibt es einen malloc xD

Im Prinzip hat mir das dann fast nichts gebracht, weil so hatte ich es 
vor ein paar Tagen schon. Schöne Zeitverschwendung ;-)

Das was es gebracht hat: malloc verhält sich jetzt so, wie man es 
erwarten würde ... :)

Also Problem gelöst^^

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


Lesenswert?

Mampf F. schrieb:
> Schöne Zeitverschwendung ;-)

Nö: du weißt jetzt zumindest, dass man sich den Startup-Code im Zweifel
doch mal genauer ansehen sollte. ;-)

Ja, der Wildwuchs beim Startup-Code und den zugehörigen Linkerscripts
bei den diversen ARM-Toolchains ist ätzend.  Es geistert da so viel
Mist auch durchs Netz, und wie du siehst, ist wohl auch nicht alles
ausgegoren, was die Hersteller selbst da liefern.

Schade eigentlich.

Nicht ordentlich initialisierte Variablen im BSS haben wir hier auch
schon mal aufwändig suchen müssen.  Da fehlte im Linkerscript ein *.

von Dumpfbacke (Gast)


Lesenswert?

Mampf F. schrieb:
> Meine MP3s werden nicht mehr in der nötigen Geschwindigkeit
> abgespielt.

Und woran liegt's?

RAM zu langsam oder von den Zugriffszeiten nicht richtig konfiguriert?
Laufen da keine Prefetch/Buffer Algorithmen?

Frage in die Runde? Ist SRAM auf "dem" STM32 (F4) schneller als SDRAM?

von Dumpfbacke (Gast)


Lesenswert?

Dumpfbacke schrieb:
> Ist SRAM auf "dem" STM32 (F4) schneller als SDRAM?

Gemeint ist natürlich jeweils externes SRAM/SDRAM

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Dumpfbacke schrieb:
> Und woran liegt's?
>
> RAM zu langsam oder von den Zugriffszeiten nicht richtig konfiguriert?
> Laufen da keine Prefetch/Buffer Algorithmen?

Ich denke, es wurden einige Buffer im internen SRAM angelegt.

Nachdem ich die bss-Section auf externes SDRAM umgestellt hatte, landete 
dann einiges im SDRAM und hat einiges timing-kritisches erheblich 
verlangsamt.

Ich war dann ehrlich gesagt zu faul, mir jede Variable im bss 
anzuschauen und zu entscheiden, ob sie doch besser im internen RAM 
aufgehoben wäre.

Hatte es zurückgebaut und eine eigene Section für meine ID3-Datenbank im 
Linker-Script angegeben und dann das Monster-Struct per 
__attribute__(section(".id3db"))) in einen ungenutzen SDRAM-Bereich 
"gezwungen".

Seitdem geht alles wunderbar :)

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Dumpfbacke schrieb:
> Dumpfbacke schrieb:
>> Ist SRAM auf "dem" STM32 (F4) schneller als SDRAM?
>
> Gemeint ist natürlich jeweils externes SRAM/SDRAM

Mmhmm, da bin ich mir nicht so sicher ... SRAM ist ja meistens asynchron 
(außer PSRAM?) und die Setup- und Hold-Zeiten müssen eingehalten werden.

Wenn man 15ns RAMS verwendet könnte das aber schon gut sein, dass SRAM 
schneller ist, weil viel Brimborium garnicht gemacht werden muss.

Allerdings bekommt man SRAM nicht in der Größenordnung, da es sonst 
zuviel Adress-Leitungen benötigen würde.

Aber PSRAM (pseudo-static-RAM) ist SRAM mit SDRAM-Interface oder wie war 
das?

von Dumpfbacke (Gast)


Lesenswert?

Mampf F. schrieb:
> Allerdings bekommt man SRAM nicht in der Größenordnung, da es sonst
> zuviel Adress-Leitungen benötigen würde.

Was heisst "zuviel Adress-Leitungen"?

Die F4-Serie bietet bis zu 64 MByte Adressraum mit den Adress-
leitungen die vorhanden sind. Wenn man alle Chip Selects nutzt
dann noch mal vier.

Mampf F. schrieb:
> Allerdings bekommt man SRAM nicht in der Größenordnung

Von welcher Grössenordnung sprichst du?

Wenn man mit einem SRAM nicht auskommt kann man auch mehrere
nebeneinander verwenden, das hat man schon in den Anfängen
der Computertechnik so gemacht ;-)

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Dumpfbacke schrieb:
> Was heisst "zuviel Adress-Leitungen"?
>
> Die F4-Serie bietet bis zu 64 MByte Adressraum mit den Adress-
> leitungen die vorhanden sind. Wenn man alle Chip Selects nutzt
> dann noch mal vier.

Oh du hast recht ... Die STM32F4 können 26 Adressen * 16 Bit = 64MB 
statisches RAM.

Dumpfbacke schrieb:
> Von welcher Grössenordnung sprichst du?

Bei mir ist ein SDRAM mit 32MB (Megabyte^^) für 3,50EUR drauf ...

> Wenn man mit einem SRAM nicht auskommt kann man auch mehrere
> nebeneinander verwenden, das hat man schon in den Anfängen
> der Computertechnik so gemacht ;-)

Ja schon, aber ... ist teuer^^

von Dumpfbacke (Gast)


Lesenswert?

Mampf F. schrieb:
> Bei mir ist ein SDRAM mit 32MB (Megabyte^^) für 3,50EUR drauf ...

Schön billich  .... aber vermutlich auch schön langsam(er) ....
Ich weiss es nicht ... aber deshalb hatte ich ja gefragt.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Ähm, seltsam das ist ...

Hab quasi mein Projekt wieder von vorne angefangen und den ganzen 
HAL-Kram entsorgt.

Bin leider noch lange nicht dort, wo ich war ... Aber das Scannen der 
ID3-Datenbank funktioniert.

Was ich nicht verstehe ... Das Scannen von 1300 MPs braucht jetzt nur 
noch 2 Sekunden anstatt vorher sowas um die 30 ...

Soviel Overhead kann HAL doch garnicht rein bringen ... Aber irgendwas 
war da eh faul, weil ich keine Sektoren auf der µSD schreiben konnte, 
weshalb ich den HAL-Dreck in erster Linie komplett entsorgen wollte, 
weil er mir zuviel macht, was keiner mehr durchsteigt, teilweise 
fehlerbehaftet ist und sich wie ein Virus alle IRQ- und DMA-Handler 
krallt und sich überall rein hängt ... Dann darf man über 3-5 Ebenen 
sich zum eigentlichen Handler hangeln ... Zum Kotzen!

Ein CMSIS-Only Projekt für den STM32F429 komplett neu zu starten hat 
mich auch einen halben Tag arbeit gekostet :/

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Der SDRAM Zugriff braucht nen paar Takte und du hattest den Stackpointer 
in den SDRAM gelegt.
Das wird natürlich sacklahm ;)
Also Stackpointer immer schön im internen RAM lassen.

von Mampf F. (mampf) Benutzerseite


Lesenswert?

Mw E. schrieb:
> Der SDRAM Zugriff braucht nen paar Takte und du hattest den Stackpointer
> in den SDRAM gelegt.
> Das wird natürlich sacklahm ;)
> Also Stackpointer immer schön im internen RAM lassen.

Nana, das war es nicht ...

Im Linker-Script gab es eine Section
.user_heap_stack

und ich hatte es in
.user_heap

und
.user_stack

aufgetrennt und den Stack im internen RAM gelassen :)

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.