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
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 ;-)
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 :/
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?
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
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?
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
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.
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.
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 ;-)
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?
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 :)
Warum nutzt du nicht die statische Speicherzuweisung mittels Linker Script und attribute section ?
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.
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...
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
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
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?
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^^
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...
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.
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.
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?
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
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 :/
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
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?
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 :)
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
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.
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.
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
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.
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
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.
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
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!
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.
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
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
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^^
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 *.
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?
Dumpfbacke schrieb: > Ist SRAM auf "dem" STM32 (F4) schneller als SDRAM? Gemeint ist natürlich jeweils externes SRAM/SDRAM
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 :)
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?
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 ;-)
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^^
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.
Ä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 :/
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.