Buffer optimiert in C kopieren

OP #7967918

Vermutlich simpel, aber komme gerade nicht drauf: es geht um rechenzeit-optimiertes Kopieren von Buffern.

Gegegeben ist ein größerer uint8_t-Buffer der prozesssicher in einem Mehrkern-uC als Ringbuffer mit 16 Bit-Wörter gefüllt wird. Zyklisch werden bei ausreichendem Füllstand wieder 16-Bit-Werte entnommen.

Stark vereinfacht und initial befüllt in etwa so:

1
uint8_t buf_uint8[8]={1,2,3,4,5,6,7,8};
2
int16_t buf_int16[4];
3

4
for  (uint16_t i=0; i<4; i++)
5
     {
6
     buf_int16[i]= (int16_t *)(buf_uint8[i*2] + (buf_uint8[i*2+1]<<8)); //?
7
     printf("buf_int16[%d]= %d \n",i, buf_int16[i]);
8
     }

So wie im Beispiel funktioniert die Sache, aber geht das nicht effizienter ohne schieben und addieren? Also direkt aus dem 8 Bit Buffer zwei Wörter zu einem 16 Bit Wort kopieren?

Muss man den Endian-Mode beachten, letztlich läuft das auf einem ARM. Wie sähe der C-Syntax dafür aus?

Alignment aufpassen! Wenn man Zugriffe mit 16 oder 32 bit grösse macht, etwarten viele Architekturen auch addressen die 16 oder 32bit aligned sind. Aus einer 8bit char buffer kann man deswegen nicht immer gleich 32 bit auskopieren. Klar wenn alignment stimmt geht.

Sonst ein memcpy müsste eigentlich das können. Gut implementationen sehen nach ob man am anfang oder ende noch 8bit weise kopiert. Dazwischen aber 32 bit weise. Teilweise gibt es architekturen wo der RAM eh 64bit breit ist (oder noch breiter) wegen ECC. Da kann man richtig gas geben, denn man kann 64bit weise kopieren.

OP

Danke für die Hinweise. Hat auch auf dem ARM funktioniert. Das Alignment müsste man vermutlich beim Anlegen des Buffers prüfen? Wäre jetzt davon Ausgegangen, dass der Compiler das nicht schräg über Wortgrenzen legt.

Geht um einen RP2350, also RPI Pico2. Ist 32Bit.

Wulf D. schrieb:

Gegegeben ist ein größerer uint8_t-Buffer der prozesssicher in einem Mehrkern-uC als Ringbuffer mit 16 Bit-Wörter gefüllt wird. Zyklisch werden bei ausreichendem Füllstand wieder 16-Bit-Werte entnommen.

Warum dann nicht gleich ein int16_t Array anlegen? Dann stimmt auch das Alignment.

Brauchst du wirklich eine kopie, oder reicht dir der Zugriff auf 8Bit bzw. 16Bit Ebene? Wenn es Keine Kopie sein muss, dann kannst du auch ein Union anlegen.

Falls es doch eine Kopie sein soll:

  • kopieren via Pointer (Dann gleich mit maximaler Bitbreite kopieren(32Bit?)
  • DMA (Falls der Prozessor das kann)

Wulf D. schrieb:

Danke, auf dem PC funktioniert memcpy schon mal.

Auch auf allen anderen Architekturen sollte man nichts eigenes machen. Die Compiler optimieren meist besser als man selber. Wenn du als Optimierung -O3 eingestellt hast, wird er vermutlich Intrinsic Funktionen nutzen.

Das einzige auf was man selber achten sollte ist das Alignment wie oben beschrieben.

Wulf D. schrieb:

Gegegeben ist ein größerer uint8_t-Buffer der prozesssicher in einem Mehrkern-uC als Ringbuffer mit 16 Bit-Wörter gefüllt wird. Zyklisch werden bei ausreichendem Füllstand wieder 16-Bit-Werte entnommen.

Wulf D. schrieb:

Geht um einen RP2350, also RPI Pico2. Ist 32Bit.

DMA. Der Pico hat so viele Kanäle davon, dass man die sogar gefahr- und kostenlos nutzen kann.

OP

Sorry für die verzögerte Reaktion, komme heute nur sehr sporadisch Zugriff zum Forum. Irgendwas hakelt.

Endian Mode dürfte in der Tat egal sein, da ja alles auf einem Prozessor läuft. Kann doch eigentlich nur beim Transport über Grenzen schief gehen. Denke, dass ARM big endian ist. Und x86 little endian. Jedenfalls sah die Byteanordnung im Testprogramm auf dem PC so aus.

Die Ringbuffer-Entnahmemethode ist so deklariert

1
RING_BUFFER_SIZE_TYPE ring_buffer_pop(ring_buffer_t *ring_buf, uint8_t* vals, RING_BUFFER_SIZE_TYPE maxvals);

RING_BUFFER_SIZE_TYPE ist uint16_t, uint8_t* vals mit dem eigentlichen Bufferspeicher verbunden. ring_buffer_t eine Struktur.

Letztlich gab es noch eine einfachere Variante die 16-Bit-Wörter aus dem 8-Bit Bufferspeicher zu ziehen, aber das konntet ihr mangels Infos nicht ahnen und ich bin mir nicht sicher ob der (uint8_t *)-Cast auf ein int16_t-Array guter Stil ist. Funktionieren tut es, decodebuf enthält die gewünschten 16Bit-Werte.

1
int16_t decodebuf[1920];
2
ring_buffer_pop(&ring_buffer, (uint8_t *)decodebuf, 1920*2);
OP

Norbert schrieb:

DMA. Der Pico hat so viele Kanäle davon, dass man die sogar gefahr- und kostenlos nutzen kann.

eh, guter Tipp. Vier werden bereits benutzt, aber da ist noch Luft. Versuche ich beim Optimieren. Leider ist das SDK qualitätsmäßig so mies, dass man den Debugger nicht nutzen kann. stdio_init_all(); stürzt zuverlässig ab.

Normales Compilieren und Laden geht, aber ohne Debugger äußerst lästig.

Wulf D. schrieb:

So wie im Beispiel funktioniert die Sache, aber geht das nicht effizienter ohne schieben und addieren? Also direkt aus dem 8 Bit Buffer zwei Wörter zu einem 16 Bit Wort kopieren?

Müsste mit logischen Operationen gehen. Das Hintergrundproblem ist hier die Umwandlung des Datenformats. Schaut man sich ein wenig um, könnte man sich noch auf memcpy stürzen (schneller machen), bzw. sich auf das Allignment konzentrieren, und memcpy weitgehend weglassen. Teilweise sind die angesprochenen Sachen hier sehr Hardware- bzw. Compilerabhängig.

https://stackoverflow.com/questions/17498743/how-does-the-internal-implementation-of-memcpy-work hier verlinkt noch (was zum Downloaden): http://www.danielvik.com/2010/02/fast-memcpy-in-c.html

https://stackoverflow.com/questions/6842363/why-are-structures-copied-via-memcpy-in-embedded-system-code

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 11 Monate alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.