Forum: Compiler & IDEs 16 bit Sofware "SIMD" auf 32 MCU?


von Moritz N. (mox-mox)


Lesenswert?

Hi, ich hatte heute morgen einen Einfall: kann man auf einer 32-Bit MCU 
(in meinem Fall einen STM32 (Cortex m3), die an sich keine SIMD-Befehle 
kennt, 16-Bit Daten Parallel rechen? Ich mein, eigentlich wäre es 
naheliegend, ich sehe nur ein paar Probleme.

Wenn ich jetzt Daten von zum Beispiel dem DMA an eine Stelle im Speicher 
bringen lasse, und dann jeweils zwei aufeinander folgende uint16_t als 
einen uint32_t auffasse, dann kann ich mit den 32-Bit Zahlen rechnen, 
und so zwei 16-Bit Rechnungen einsparen, oder?

Beispiel für Addition:

int32 summand_a, summand_b:
0xxxxxxxxxxxxxxx0xxxxxxxxxxxxxxx
^               ^
Beginn Wert1    Beginn Wert2
(erste Stelle muss 0 sein, damit keine Überläufe passieren können)

int32 ergebnis = summand_a + summand_b;
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
^               ^
Beginn Wert1    Beginn Wert2
(Jetzt ist die erste stelle möglicherweise auch belegt)
Analog sollte auch die Mulatiplikation gehen, nur dass ich da dann eben 
mehr Platz brauche, um Überläufe zu vermeiden.

Bis jetzt denke ich, dass das ganze noch ganz gut möglich sein müsste, 
aber wenn ich statt mit integern mit Fixkommazahlen arbeite, wird das 
schwierig:
Bei einer Fixkomma-Multiplikation muss ich nach der normalen 
Multiplikation ja nochmal durch den Skalierungsfaktor teilen, 
normalerweise mache ich das, indem ich einen Skalierungsfaktor habe, der 
eine zweierpotenz ist, und dann einfach Linkschifts ausführe.
Der Cortex-M3 kann schönerweise direkt im gleichen Takt nach einer 
Addition, Subtraktion oder Muliplikation eine Schiftoperation ausführen, 
sodass. Aber wenn ich jetzt mit meinen Ergebnissen weiterrechnen will, 
habe ich das Problem, dass in meinem unteren Halbwort ja jetzt dann 
Quasi die Datenleichen des oberen Halbwortes liegen. Und wenn ich jetzt 
weiterrechne, dann machen die mein Ergebnis zwar nicht falsch, aber in 
sofern anders, als dass ich dann im oberen Halbwort mit einer 
Genauigkeit rechne, die beim unteren Halbwort (wie es nunmal bei 
Fixkommarechnung üblich ist) abgeschnitten ist. Um das zu vermeiden, 
müsste ich also die die Ergebnisse mit einer Maske von den Datenleichen 
befreien, quasi so:

//skalierungsfaktor = 16 = (2^4) => uint16_t Wert = xxxxxxxxxxxx,xxxx
uint32_t ergebnis = uint32_t multiplikator * uint32_t multiplikant;
ergebnis = (ergebnis>>4);
erbehnis = (ergebnis & (00001111111111110000111111111111);

Und damit habe ich doch im Prinzip den Vorteil, den ich mit dem 
doppelten Rechnen gewonnen habe wieder verspielt, oder? Zumindest, wenn 
die Multiplikation nur einen Taktzyklus dauert.

Additionen sollten damit bei geeigneten eingangsdaten um den Faktor zwei 
schneller gerechnet werden können, bei Multiplikationen seh ich jetzt 
noch keinen Vorteil, wenn die Rechnungen vergleichbar sein sollen, weil 
wenn man die Maskierung weglässt, dann werden die Ergebnisse ja auch 
nicht falsch, sondern nur eines genauer. Man muss dann nur zum Schluss, 
wenn man wieder mit einzelnen Datenteilen Weiterarbeitet einmalig die 
Maskierung machen.
Jedenfalls wollte ich diese Idee mal mit euch teilen, vielleicht hilft 
es jemandem, vielleicht hat jemand eine Idee, wie man an dem ganzen noch 
etwas verbessern kann.
Gruß,
Mox-Mox

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ich denk nicht, daß ma damit nen Blumentopf gewinnt.

Zum einen müssen die Daten ein- und ausgepackt werden, was Zeit und 
Speicherplatz kostet, zum anderen kann man kaum was mit dem Zeug machen 
ausser addieren, und je mehr Additionen man auf den gleichen Daten 
macht, desto kleiner werden die erlaubten Datenbereiche. Oder man muss 
nach jeder Addition ne Maske drüberlegen. Die Einschränkungen an 
Subtraktion sind noch unangenehmer.

Ein SIMD-Ansatz ist erst dann sinnvoll, wenn alle Instruktionen, die man 
so braucht, ohne größeren Widerstand umsetzbar sind.

Am ehesten geht das für die Gruppe der Bitoperationen wie &,|,~,^

Sobald das, was man an Operationen braucht, darüber hinausgeht, wird's 
echt eklig und ausser dem dauernden Ein-/Auspacken verunstaltet man die 
Quelle durch Makros/Inline-Funktionen oder Builtins.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Moritz Nöltner schrieb:
> Hi, ich hatte heute morgen einen Einfall: kann man auf einer 32-Bit MCU
> (in meinem Fall einen STM32 (Cortex m3), die an sich keine SIMD-Befehle
> kennt, 16-Bit Daten Parallel rechen?

Man könnte sich auch einfach zurücklehnen und auf Cortex-M4 Devices 
warten. Den hat ST schließlich ebenfalls lizensiert.

--
Marcus

von Moritz N. (mox-mox)


Lesenswert?

Johann L. schrieb:
> Zum einen müssen die Daten ein- und ausgepackt werden, was Zeit und
> Speicherplatz kostet,..

Ich weis nicht genau, wo Du beim Ein- und Auspacken ein Problem siehst.
Wenn man eine Anwendung hat, bei der man größere Datenmengen anfallen, 
dann wird man die (sofern man das wie bei den STM32 kann) die Daten von 
dem DMA dahin bringen lassen, wo man sie haben will. Zum Beispiel 
liefern mir die beiden ADC jweils einen 12-Bit Wert, aber es werden 
schon immer zwei Werte auf einmal von der DMA übertragen und wahlweise 
auch so abgelegt (ist die die schnellste Art Daten zu verschicken, so 
gehn die in einem Bustakt durch die Leitung, sonst wären es mehr). Und 
damit habe ich, wenn ich die ADC-Werte hintereinander im Speicher 
ablege, meine Daten perfekt angeordnet. Und dann kommt es nur noch drauf 
an, als was ich sie denn nun anspreche. Kostet also keinen 
(zusätzlichen) Speicherplatz und eigentlich auch keine Zeit. (kann man 
einfach ein riesiges Union draus machen:
1
union
2
{
3
  array_32[x];
4
  array_16[2x];
5
}
Johann L. schrieb:
> ...zum anderen kann man kaum was mit dem Zeug machen
> ausser addieren, und je mehr Additionen man auf den gleichen Daten
> macht, desto kleiner werden die erlaubten Datenbereiche.

Naja, das ist doch aber immer so bei Fixkommaberechnungen, oder? Ich 
mein, wenn ich da nicht nach jeder Operation auf nen Überfluss prüfen 
will, dann werde ich das so auslegen müssen, dass da nix überläuft. Mit 
allen Konsequenzen, und eben auch, dann ich genau überlegen muss, 
wieviel Bits ich brauche. Wenn 16-Bit Rechnungen nicht reichen, dann ist 
der Ansatz zugegebenermaßen nicht verwendbar. Andererseits gibts 
genügent Dinge, die sich mit 8-Bit rechnen lassen, siehe AVR und Co.


Johann L. schrieb:
> Oder man muss
> nach jeder Addition ne Maske drüberlegen.

Inwiefern sollte denn eine Maske helfen, überläufe bei Additionen 
abzufangen? Damit würde ich ja nur bestenfalls meine jeweiligen MSBs 
abschneiden.

Marcus Harnisch schrieb:
> Man könnte sich auch einfach zurücklehnen und auf Cortex-M4 Devices
> warten. Den hat ST schließlich ebenfalls lizensiert.
Klar kann man. ST hat da einige Süppchen am kochen, auf die ich mich 
freu. Aber ich will jetzt was machen, und eigentlich denk ich, das der 
STM32 schon fast zu groß wär dafür, wenn ich nicht Wert darauf legen 
würde, dass es wirklich schnell geht. Also versuch ich doch eher, das, 
was ich habe, effizient zu nutzen.

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

Moritz Nöltner schrieb:
> Aber ich will jetzt was machen, und eigentlich denk ich, das der
> STM32 schon fast zu groß wär dafür, wenn ich nicht Wert darauf legen
> würde, dass es wirklich schnell geht. Also versuch ich doch eher, das,
> was ich habe, effizient zu nutzen.

Klar. Aber, da Du Dir anscheinend bereits Gedanken über Nebeneffekte
gemacht hast, warum versuchst Du es nicht einfach?

Aber vergiss nicht, das Ergebnis mit "normalem" Code zu
vergleichen. Ich vermute, dass sich der Aufwand dieses "SIMD für Arme"
nicht lohnt. Was Dich Deinem Ziel etwas näher bringen könnte und
relativ wenig Stress macht ist das Laden der Wertepaare mit einem
einzelnen Wortzugriff (array of unions, anstatt union of arrays).
Lokal werden die Worte dann wieder aufgeteilt. Spart ein paar
Speicherzugriffe.

Gruß
Marcus

von Moritz N. (mox-mox)


Lesenswert?

Jau, wenn ich dazu komm, und noch ein paar andere Unbekannte klarer sind 
(zum Beispiel die Dimensionierung von Fixpnktzahlen) dann werd ich das 
testen. Aber für jetzt mal danke für die Antworten.

von Murkser (Gast)


Lesenswert?

Die Idee mit dem Software-SIMD (also eben ohne H/W-SIMD Unterstützung) 
hatte schon jemand vor Dir:

Stefan Kraemer, Rainer Leupers, Gerd Ascheid, Heinrich Meyr:
SoftSIMD - exploiting subword parallelism using source code 
transformations
Proceedings of the Conference on Design, Automation and Test in Europe
http://portal.acm.org/citation.cfm?id=1266660&dl=GUIDE&coll=GUIDE&CFID=89273050&CFTOKEN=43293959


   Murkser

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.