Ich "möchte" (ich bin mir sicher das eigentlich nicht zu wollen und
suche nach einer vernünftigen Lösung) in C ein grosses Array verwenden
(z.B. um Messdaten abzuspeichern, momentan gehts aber eher ums Prinzip).
Die Plattform ist ein Zynq mit insgesamt 1 GB RAM. In einem naiven
Ansatz habe ich nun einfach ein grosses Array definiert:
1
uint32_tTestArray[125000000];
Da ein unit32_t 4 bytes benötigt belegt das Array also gut 500 MB (den
halben Speicher).
Eigentlich hätte ich erwartet, dass der Compiler (bzw. Linker) sich
beschwert, aber er frisst das ganze ohne Probleme.
Als nächsten Schritt habe ich eine Schleife geschrieben die das Array
mit unnützen Daten beschreibt, zudem gibt die Schleife für jeden
Millionsten Eintrag eine Meldung aus damit ich ein Gefühl für die
benötigte Zeit bekommen. Dabei viel mir auf:
- für die ersten 40 Blöcke (à 1e6 uint32_t Werte, also 4e6 bytes)
benötigt das Programm pro Block ca. eine Sekunde.
- Von da an wird die Zeit massiv länger, ein Block benötigt dann etwa 10
Sekunden
Die Frage die sich mir nun stellt:
- Wo wird das Array abgespeichert? Ich dachte Arrays laden auf dem
Stack, das erscheint mir bei der Grösse aber wenig realistisch, zudem
ist der Stack laut Linker Script nur 64 kB gross
- Woher kommt die massiv länger Schreibzeit ab Block 40? Der Zynq hat
256 kB internen Speicher, das reicht aber nicht ansatzweise für 40
Blöcke. Der L2 Chache ist mit 512 kB auch nicht gross genug um irgendwas
in der Grössenordnung zu halten.
- Wie macht man so etwas richtig? Die Idee, ein Riesenarray zu
definieren erscheint mir nicht wirklich sinnvoll, ehrlicherweise fällt
mir allerdings nichts besseres ein. Es geht eigentlich darum,
Referenzwerte zu generieren die dann per DMA vom FPGA Teil aus dem
Speicher gelesen werden. Die Samplerate ist dabei allerdings zwischen 10
MHz und 50 MHz auf mehreren Kanälen, eine Online-Generierung per CPU
geht sich also zeitlich niemals aus.
Array on Diet schrieb:> Ich dachte Arrays laden auf dem Stack, das erscheint mir bei der Grösse> aber wenig realistisch, zudem ist der Stack laut Linker Script nur 64 kB> gross
Kommt drauf an. Wenn Du es lokal innerhalb einer Funktion definierst,
kommt es auf den Stack. Globale Arrays und auch static Arrays (innerhalb
einer Funktion) kommen nicht auf den Stack.
Nur letzteres ist sinnvoll bei einer derartigen Größe.
Wenn du das Array global deklarierst hast, liegt das nicht auf dem
Stack, sondern in .bss. Über alles andere sollte dir die Doku deiner
toolchain und des (ungenannten) Betriebssystems Auskunft geben.
Du kannst ja mal schauen, was passiert, wenn du das array auf dem heap
anlegen willst. Da meldet dir malloc zumindest zurück, ob das geklappt
hat.
Oliver
Frank M. schrieb:> Kommt drauf an. Wenn Du es lokal innerhalb einer Funktion definierst,> kommt es auf den Stack. Globale Arrays und auch static Arrays (innerhalb> einer Funktion) kommen nicht auf den Stack.
Danke, das erklärt schon mal wieso ich Platz dafür habe (das Array is
global).
Oliver S. schrieb:> Über alles andere sollte dir die Doku deiner> toolchain und des (ungenannten) Betriebssystems Auskunft geben.
Die Toolchain ist Xilinx SDK, es gibt kein Betriebssystem (SDK
bezeichnet das als "baremetal application").
Oliver S. schrieb:> Du kannst ja mal schauen, was passiert, wenn du das array auf dem heap> anlegen willst. Da meldet dir malloc zumindest zurück, ob das geklappt> hat.
Werde ich bei Gelegenheit machen.
Array on Diet schrieb:> - für die ersten 40 Blöcke (à 1e6 uint32_t Werte, also 4e6 bytes)> benötigt das Programm pro Block ca. eine Sekunde.> - Von da an wird die Zeit massiv länger, ein Block benötigt dann etwa 10> Sekunden
Kann es nicht sein, dass ein Teil des Arrays ins Flash ausgelagert
wird?
https://de.m.wikipedia.org/wiki/Auslagerungsdatei
Array on Diet schrieb:> (ich bin mir sicher das eigentlich nicht zu wollen und> suche nach einer vernünftigen Lösung) in C ein grosses Array verwenden> (z.B. um Messdaten abzuspeichern, momentan gehts aber eher ums Prinzip)
Das kommt immer darauf an was du mit dem Array vorhast und wie schnell
du an die Daten musst.
Abspeichern von Messdaten macht man eher auf eine sequentielle Datei.
Chronologisches Suchen oder sequentielles Verarbeiten geht dann auch
noch halbwegs schnell.
Für dünn besetzte Arrays gibt es extra Algorithmen, die das nicht als
riesiges fast leeres Array anlegen, sondern als Listen oder Bäume.
Wenn du aber maximal schnell wahlfrei auf alle Elemente zugreifen können
musst bleibt nur das Array im Speicher solange es passt.
Array on Diet schrieb:> Es geht eigentlich darum,> Referenzwerte zu generieren die dann per DMA vom FPGA Teil aus dem> Speicher gelesen werden. Die Samplerate ist dabei allerdings zwischen 10> MHz und 50 MHz auf mehreren Kanälen, eine Online-Generierung per CPU> geht sich also zeitlich niemals aus.
Verstehe ich nicht so ganz, aber bei der Geschwindigkeit bleibt dir
ausser im Speicher halten nichts anderes.
Array on Diet schrieb:> Oliver S. schrieb:>> Über alles andere sollte dir die Doku deiner>> toolchain und des (ungenannten) Betriebssystems Auskunft geben.>> Die Toolchain ist Xilinx SDK, es gibt kein Betriebssystem (SDK> bezeichnet das als "baremetal application").
Wenn es kein Betriebssystem gibt, wird der Krempel statisch im Adreßraum
angeordnet. Vom Linker nach Vorgabe des Linkerskripts. Der hätte sich
dann schon beschwert, wenn das nicht reinpaßt. Irgendeine lazy
Allocation gibt es dann auch nicht. Tatsächlich muß der Laufzeitcode ein
globales Array vor dem Aufruf von main() auch initialisieren (vulgo:
beschreiben).
Array on Diet schrieb:> Woher kommt die massiv länger Schreibzeit ab Block 40? Der Zynq hat> 256 kB internen Speicher
Speicher? Meinst du L1 Cache? Oder hat das SoC internen und externen
RAM?
> das reicht aber nicht ansatzweise für 40> Blöcke. Der L2 Chache ist mit 512 kB auch nicht gross genug
Ich kenne die Architektur nicht. Vielleicht ist ja nicht aller RAM
gleichmäßig schnell an alle Kerne angebunden (NUMA)? Und dann haben
etliche ARMe ja auch mehrere RAM Regionen. Mancher RAM hängt direkt an
der CPU, anderer wird über einen Peripheriebus angesprochen. Wenn da ein
Bus langsamer getaktet ist, kann das gut zum beobachteten Faktor 10
führen.
Array on Diet schrieb:> Ich "möchte" (ich bin mir sicher das eigentlich nicht zu wollen und> suche nach einer vernünftigen Lösung) in C ein grosses Array verwenden> (z.B. um Messdaten abzuspeichern, momentan gehts aber eher ums Prinzip).> Die Plattform ist ein Zynq mit insgesamt 1 GB RAM. In einem naiven> Ansatz habe ich nun einfach ein grosses Array definiert
Ich bin mir ziemlich brutal sicher ;-) dass Du nicht alle diese Daten
gleichzeitig im Speicher benötigen wirst. Sondern eben nur einen Teil
davon, der gerade groß genug ist um die jeweils benötigten Berechnungen
anzustellen. Der Ansatz wäre also:
1.) Herausfinden, wieviel Speicher man tatsächlich benötigt für:
Eingangsadaten und Ablage der Ergebnisse (evtl. auch Zwischenergebnisse)
2.) Diese Menge an Speicher allokieren
Axel S. schrieb:> Tatsächlich muß der Laufzeitcode ein> globales Array vor dem Aufruf von main() auch initialisieren (vulgo:> beschreiben).
Naja...
Mein lieblings Gcc kennt eine .noinit Section.
Andere machen es lieber mit #pragma NOINIT
Also:
Grundsätzlich stimmt deine Aussage, aber es ist keine Mussbedingung,
sondern mit Alternativen versehen.
Array on Diet schrieb:> Die Frage die sich mir nun stellt:> - Wo wird das Array abgespeichert?
Der Compiler/Linker wird's wissen. Guck mal in den Listing-File den
deine Tool Chain erstellt oder zumindest erstellen kann.
Eine eigene Frage?
Dieser Thread ist über 5 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.