CineFX (NV30) Inside
31. August 2003 / von Demirug / Seite 5 von 7
Leistungsbetrachtung der CineFX Architektur (Forts.)
Nachdem wir die Rohleistung nun ausführlich diskutiert haben, kommen wir zum zweiten wichtigen Punkt bei der Leistungsbetrachtung. Rohleistung ist zwar etwas schönes, um es auf der Verpackung zu vermerken, aber am Ende zählt immer noch das, was wirklich herauskommt. Aufgrund einer reinen Architekturbeschreibung kann man dies natürlich nur theoretisch untersuchen, aber genau das gleiche müssen Chipdesigner mit ihren Entwürfen ja auch tun.
Schauen wir uns also einmal an, wie anfällig das NV30 Design für das Verpuffen von Rohleistung ist. Seine Universal-FPU kann in jedem Takt einen beliebigen Befehl ausführen, wodurch das Verhältnis von Textur- zu Aritmetik-Operationen keinen Einfluss auf die Leistung hat. Wir erinnern uns jedoch, dass jeweils 2 Texturoperationen auf einmal ausgeführt werden können. Damit dies aber auch wirklich funktioniert, müssen Texturoperationen paarweise auftreten. Tun sie das nicht, verliert man die Hälfte der möglichen Texturoperationen.
Ziehen wir nun wieder unseren Vergleichschip heran: Da der R300 sich nicht einer Universal-FPU bedient, sondern zwei getrennte Einheiten für Textur- und Arithmetik-Operationen nutzt, hat das Verhältnis dieser Operationen zueinander natürlich eine direkte Auswirkung auf den Nutzungsgrad der Rohleistung. Jede Abweichung vom 1:1-Ideal führt unweigerlich zu einem Verlust von Rohleistung. Dagegen spielt es keine Rolle, ob die Texturinstruktionen nun paarweise auftreten.
Im folgendem Diagramm sehen wir, wie sich das Textur/Arithmetik-Verhältnis auf die Summe der ausgeführten Instruktionen pro Sekunden auswirkt. Die 3 Kurven zeigen uns den NV30 mit paarweisen Textureanweisungen, NV30 mit einzelnen Textureanweisungen und den R300:
Der R300 erreicht wie bereits erwähnt sein Maximum von 5200 MI/S beim Verhältnis von 1:1 und fällt zu den beiden Extremfällen (nur Textur- bzw. nur Arithmetik-Anweisungen) auf 2600 MI/s ab. Treten die Texturenoperationen nicht paarweise auf, erreicht der NV30 konstant 2000 MI/s und kommt damit nicht einmal dort in Bereiche der R300-Rohleistung, wo der R300 seine größten Schwächen hat.
Etwas besser sieht es beim paarweisen Auftreten von Texturoperationen aus. Hier erreicht der NV30 einen Spitzenwert mit 4000 MI/s, wenn nur Texturoperationen vorhanden sind. Dieser Wert fällt aber nun kontinuierlich ab, je mehr Texturoperationen durch Arithmetik-Anweisungen ersetzt werden, bis am Ende ein reiner Rechenshader mit 2000 MI/s berechnet werden kann. Bis zu einem Verhältnis von etwa 4 Texturops zu einer Arithemetikop kann der NV30 die kleine Schwäche des R300 Designs ausnutzen. Dieser Bereich hat aber in der Praxis kaum Bedeutung, so dass man hier bestenfalls von einem kleinen Achtungserfolg sprechen kann.
Eine weitere kleine Schwäche des R300 Designs tritt im Falle von dependent reads (benötigt für Enviromental Bump Mapping) zutage. Hier kann es trotz des eigentlich idealen 1:1-Verhältnis dazu kommen, dass dennoch nur mit 2600 MI/s gerechnet werden kann. Bei "dependent Reads" handelt es sich um Texturanweisungen, die mit Texturkoordinaten rechnen, welche vorher durch den Pixelshader verändert wurden. Ein kombiniertes Enviroment Bumpmapping ist ein Effekt, welcher "dependent Reads" benötigt. Der NV30 kennt dieses Problem nicht und kann in solchen Fällen etwas Boden gut machen.
Abschließend kann man sagen, dass der NV30 zwar weit weniger anfällig für Rohperformanceverluste durch widrige Umstände als der R300 ist. Der R300 wiederum verfügt über so viel Rohperformance, dass er die Verluste verschmerzen kann. Dem NV30 fehlt hier ganz klar die Rechenleistung der Combiner, die er ja beim PS 2.0 nicht einsetzten kann.
Zu guter Letzt wollen wir natürlich nicht verschweigen, dass der R300 noch die Option hat, seine Arithmetik-FPU unter bestimmten Umständen dafür zu benutzen, eine Vector3- und eine Skalar-Operation gleichzeitig auszuführen. Um die Diagramme aber nicht noch weiter zu verkomplizieren, haben wir darauf verzichtet, diese Eigenschaft zu berücksichtigen. Zudem halten wir die Universal FPU des NV30 für prinzipiell auch dazu fähig (siehe Teil 3).
Vergleicht man nun die bisher gewonnenen Erkenntnisse mit den realen Ergebnissen, welche ein NV30 bei Pixelshadertests erzielt, so kann das noch nicht alles gewesen sein. Irgendwo im NV30 muss noch etwas vorhanden sein, was ihn bei 2.0-PS behindert. Ein besonderes Anliegen von nVidia bei der Verwendung von Pixelshadern ist, dass man möglichst wenige Temp-Register benutzen sollte. Bei der Analyze der Torwächter-Funktion haben wir erkannt, dass die Anzahl der gleichzeitig in der Pipeline speicherbaren Quads in einem direkten Verhältnis zur Anzahl der Temp-Register steht: Je weniger Temp-Register benutzt werden, desto mehr Quads passen in den Speicher.
nVidia möchte also mit der Empfehlung erreichen, das möglichst viele Quads in die Pipeline passen. Welche Vorteile ergeben sich daraus wenn sich viele Quads bzw. welche Nachteile hat es wenn sich nur wenige Quads in der Pipeline befinden? Im wesentlichen haben wir drei Gründe erkennen können:
Bevor die Quads einen zusätzlichen Durchlauf durch die Pipeline vornehmen können, ist es aus technischen Gründen notwendig, mindestens ein Leer-Quad durch die Pipeline zu schicken. Dies ist natürlich einen Schmälerung der effektiv nutzbaren Rohleistung. Der Verlust fällt umso geringer aus, je weniger dieser Leerquads erforderlich sind. Und das wird dadurch erreicht, dass man die Anzahl der Quads in der Pipeline erhöht.
Aufgrund der Pipelinelänge und der Latenzen bei Texturauslesen besteht die Gefahr, dass nachdem das letzte Quad in die Pipeline eingebracht wurde, das erste Quad noch nicht das Ende der Pipeline erreicht hat. In diesem Fall muss der Torwächter solange warten, bis dieses verfügbar ist. Jeder Takt, der dabei vergeht, ist Verlustleistung pur. Mit steigender Quadanzahl sinkt die Gefahr eines solchen Pipeline Stalls.
Bei jedem Durchlauf können die Texturen, aus denen ausgelesen werden soll, gewechselt werden. Da nun weniger Textursamples am Stück aus einer Textur gewonnen werden, führt das in der Regel zu einem Sinken der Trefferrate im Cache. Es müssen also mehr Daten über den Bus einglesen werden.
Ein nach den Empfehlungen von ATi geschriebener oder mit dem im DX9-SDK enthaltenen Compiler erzeugter 2.0-Pixelshader ist nun leider genau so aufgebaut, das er alle diese Probleme forciert. Solche Shader benutzen immer viele Temp-Register und haben die Textureanweisungen als Block gebündelt. Auch ein 1.4-Pixelshader ist genau nach diesem Prinzip aufgebaut.
nVidia wird also sich dieser Probleme annehmen müssen, und zwar besser heute als morgen. Microsoft arbeitet bereits an einem SDK Update, welches eine neue Version des Compilers enthält, der Shader auch so compilieren kann, das sie mit weniger Temp-Register auskommen und die Texturezugriffe immer nur in 2er Blöcken einfügt. Nur wenn die Entwickler 1.4-Pixelshader benutzen oder nur einen 2.0 Shader erzeugen, ist die Aktion von Microsoft zwar ein gut gemeinter Zug, aber für nVidia recht nutzlos. Daher wird nVidia das Problem im Treiber lösen müssen.