Ich habe viel über die Vorteile der Organisation von Daten in "Structs of Arrays" (SoA) anstelle des typischen "Array of Structs" (AoS) gelesen, um einen besseren Durchsatz bei Verwendung von SIMD- Anweisungen zu erzielen . Obwohl das Warum für mich absolut sinnvoll ist, bin ich mir nicht sicher, wie viel ich tun soll, wenn ich mit Dingen wie Vektoren arbeite.
Vektoren selbst können als Struktur eines Datenarrays (fester Größe) verstanden werden, sodass Sie ein Array davon in eine Struktur von X-, Y- und Z-Arrays konvertieren können. Auf diese Weise können Sie 4 Vektoren gleichzeitig bearbeiten und nicht jeweils einen.
Aus dem speziellen Grund poste ich dies auf GameDev:
Ist dies sinnvoll für die Arbeit mit Vektoren auf der SPU? Ist es insbesondere sinnvoll, mehrere Arrays nur für einen einzelnen Vektor zu dMA? Oder wäre es besser, beim DMAing des Vektorarrays zu bleiben und es in die verschiedenen Komponenten abzuwickeln, mit denen gearbeitet werden soll?
Ich konnte den Vorteil des Ausschaltens des Abrollens erkennen (wenn Sie es 'AoS' gemacht haben), aber es scheint, als könnten Ihnen schnell die DMA-Kanäle ausgehen, wenn Sie diesen Weg einschlagen und mit mehreren Vektorsätzen gleichzeitig arbeiten würden.
(Hinweis: Noch keine Berufserfahrung mit Cell, aber ich habe eine Weile in OtherOS herumgespielt.)
quelle
SPUs sind tatsächlich ein interessanter Sonderfall, wenn es um die Vektorisierung von Code geht. Die Anweisungen sind in die Familien "Arithmetik" und "Laden / Speichern" unterteilt, und die beiden Familien werden in separaten Pipelines ausgeführt. Die SPU kann pro Zyklus einen von jedem Typ ausgeben.
Der mathematische Code ist offensichtlich stark an mathematische Anweisungen gebunden. Daher haben mathematische Schleifen auf SPU normalerweise viele, viele offene Zyklen in der Lade- / Speicherleitung. Da das Laden / Speichern von Rohren gemischt wird, verfügen Sie häufig über genügend kostenlose Lade- / Speicheranweisungen, um das xyzxyzxyzxyz-Formular ohne Overhead in das xxxxyyyyzzzz-Formular umzuwandeln.
Diese Technik wird zumindest bei Naughty Dog verwendet - Einzelheiten finden Sie in den Präsentationen der SPU-Baugruppen ( Teil 1 und Teil 2 ).
Leider ist der Compiler oft nicht intelligent genug, um dies automatisch zu tun. Wenn Sie sich für diesen Weg entscheiden, müssen Sie entweder die Assembly selbst schreiben oder Ihre Schleifen mithilfe von Intrinsics abrollen und den Assembler überprüfen, um sicherzustellen, dass er Ihren Wünschen entspricht. Wenn Sie also allgemeinen plattformübergreifenden Code schreiben möchten, der auf SPU gut funktioniert, sollten Sie sich für SoA oder AoSoA entscheiden (wie von jpaver vorgeschlagen).
quelle
Wie bei allen Optimierungen Profil! Die Lesbarkeit steht an erster Stelle und sollte nur geopfert werden, wenn die Profilerstellung einen bestimmten Engpass feststellt und Sie alle Optionen für die Optimierung des High-Level-Algorithmus ausgeschöpft haben (der schnellste Weg, die Arbeit zu erledigen, besteht darin, die Arbeit nicht erledigen zu müssen!). Sie sollten immer ein neues Profil erstellen Befolgen Sie eine Optimierung auf niedriger Ebene, um zu bestätigen, dass Sie die Dinge wirklich schneller als umgekehrt gemacht haben, insbesondere bei Pipelines, die so eigenartig sind wie die der Zelle.
Welche Techniken Sie dann verwenden, hängt von den Einzelheiten des Engpasses ab. Wenn Sie mit Vektortypen arbeiten, repräsentiert eine Vektorkomponente, die Sie in einem Ergebnis ignorieren, im Allgemeinen verschwendete Arbeit. Das Wechseln von SoA / AoS ist nur dann sinnvoll, wenn Sie durch das Befüllen solcher nicht verwendeter Komponenten (z. B. ein Punktprodukt auf der PS3-PSU gegenüber vier Punktprodukten parallel in derselben Zeitspanne) nützlichere Arbeiten ausführen können. Um Ihre Frage zu beantworten, klingt es für mich nach einer Pessimisierung, wenn Sie Zeit damit verbringen, Komponenten zu mischen, um nur eine Operation an einem einzelnen Vektor auszuführen!
Die Kehrseite von SPUs ist, dass der Großteil der Kosten für kleine DMA-Übertragungen im Setup liegt. Bei weniger als 128 Bytes dauert die Übertragung dieselbe Anzahl von Zyklen, bei weniger als einem Kilobyte nur wenige Zyklen mehr. Machen Sie sich also keine Sorgen, dass Sie mehr Daten DMAen, als Sie unbedingt benötigen. Das Reduzieren der Anzahl der ausgelösten sequentiellen DMA-Übertragungen und das Ausführen von Arbeiten während der DMA-Übertragungen - und damit das Entfalten von Schleifenprologen und Epilogen zur Bildung von Software-Pipelines - ist der Schlüssel zu einer guten SPU-Leistung, und es ist am einfachsten, Eckfälle durch Abrufen zusätzlicher Daten zu behandeln / Verwerfen teilweise berechneter Ergebnisse als Springen durch Reifen, um zu versuchen, die genaue Datenmenge zu ermitteln, die zum Lesen und Verarbeiten erforderlich ist.
quelle
Nein, das wäre im Allgemeinen nicht sehr sinnvoll, da die meisten Vektor-Opcodes mit einem Vektor als Ganzes und nicht mit separaten Komponenten arbeiten. Sie können also bereits einen Vektor in einer Anweisung multiplizieren, während Sie beim Aufteilen der einzelnen Komponenten 4 Anweisungen dafür ausgeben würden. Da Sie also im Allgemeinen viele Operationen an einem Teil einer Struktur ausführen, ist es besser, sie in ein Array zu packen, aber Sie tun kaum etwas nur an einer Komponente eines Vektors oder an jeder Komponente, die so stark beschädigt ist out würde nicht funktionieren.
Wenn Sie eine Situation finden, in der Sie nur mit den (sagen wir) x-Komponenten von Vektoren etwas tun müssen, könnte dies natürlich funktionieren, aber die Strafe, alles zurückzuschwenken, wenn Sie den tatsächlichen Vektor benötigen, wäre nicht billig, also könnten Sie es Ich frage mich, ob Sie zunächst keine Vektoren verwenden sollten, sondern nur eine Reihe von Floats, die es Vektor-Opcodes ermöglichen, ihre spezifischen Berechnungen durchzuführen.
quelle