Frage

Bei einer 32-Bit-CPU ist eine Ganzzahl 4 Bytes und eine kurze Ganzzahl 2 Bytes. Wenn ich eine C/C ++ - Anwendung schreibe, die viele numerische Werte verwendet, die immer in den bereitgestellten Bereich einer kurzen Ganzzahl passen, ist es effizienter, 4 Byte -Ganzzahlen oder 2 Byte -Ganzzahlen zu verwenden?

Ich habe gehört, dass 4 Byte -Zahlen effizienter sind, da dies zur Bandbreite des Busses vom Speicher zur CPU passt. Wenn ich jedoch zwei kurze Ganzzahlen zusammenfasse, würde das CPU -Paket beide Werte in einem einzigen Pass parallel (so die 4 -Byte -Bandbreite des Busses überspannen)?

War es hilfreich?

Lösung

Ja, Sie sollten auf jeden Fall eine 32 -Bit -Ganzzahl auf einer 32 -Bit -CPU verwenden, sonst kann es die nicht verwendeten Bits abschließen (dh immer werden die Mathematik in 32 Bits immer ausgeführt und die Antwort dann in 16 Bit umwandeln)

Bearbeiten: Ich sollte hinzufügen, dass es auch etwas von Ihrer Definition von "effizient" abhängt. Während es in der Lage sein wird, 32-Bit-Operationen schneller auszuführen, werden Sie natürlich doppelt so viel Speicher verwenden.

Wenn diese für Zwischenberechnungen in einer inneren Schleife irgendwo verwendet werden, verwenden Sie 32-Bit. Wenn Sie dies jedoch von der Festplatte lesen oder auch wenn Sie nur einen Cache-Miss bezahlen müssen, kann es immer noch besser funktionieren, 16-Bit-Ganzzahlen zu verwenden. Wie bei allen Optimierungen gibt es nur eine Möglichkeit zu wissen: Profile es.

Andere Tipps

Wenn Sie eine große Auswahl an Zahlen haben, dann gehen Sie mit der kleinsten Größe, die funktioniert. Es wird effizienter sein, mit einer Reihe von 16 -Bit -Shorts als 32 -Bit -INTs zu arbeiten, da Sie die doppelte Cache -Dichte erhalten. Die Kosten für jegliche Vorzeichenverlängerung, die die CPU mit 16 Bitwerten in 32 -Bit -Registern arbeiten muss, ist im Vergleich zu den Kosten eines Cache -Fehls trivial vernachlässigbar.

Wenn Sie einfach Mitgliedsvariablen in Klassen verwenden, die mit anderen Datentypen gemischt sind, ist es weniger eindeutig, da die Polsteranforderungen wahrscheinlich den Vorteil der 16 -Bit -Werte von Platz sparen.

Wenn Sie "viele" Ganzzahlwerte verwenden, kann der Engpass in Ihrer Verarbeitung eine Bandbreite für den Speicher sein. 16 -Bit -Ganzzahlen packen enger in den Datencache ein und wären daher ein Leistungssieg.

Wenn Sie eine sehr große Datenmenge knirschen, sollten Sie lesen Was jeder Programmierer über den Speicher wissen sollte von Ulrich Drepper. Konzentrieren Sie sich auf Kapitel 6 über die Maximierung der Effizienz des Datencache.

Eine 32 -Bit -CPU ist eine CPU, die normalerweise intern 32 Bitwerte arbeitet. Dies bedeutet jedoch nicht, dass sie bei einem 8/16 -Bit -Wert langsamer bei der Ausführung des gleichen Betriebs ist. X86 kann zum Beispiel, das bis zum 8086 noch rückwärtskompatibel ist, mit Braktionen eines Registers arbeiten. Das heißt, selbst wenn ein Register 32 Bit breit ist, kann es nur mit den ersten 16 oder dem ersten 8 -Bit dieses Registers funktionieren, und es wird überhaupt keine Verlangsamung geben. Dieses Konzept wurde sogar von x86_64 übernommen, wo die Register 64 -Bit sind, aber sie können dennoch nur mit den ersten 32, 16 oder 8 Bits arbeiten.

Auch X86 -CPUs laden immer eine ganze Cache -Zeile aus dem Speicher, wenn nicht bereits im Cache, und eine Cache -Zeile ist ohnehin größer als 4 Byte (für 32 -Bit -CPUs, eher 8 oder 16 Bytes) und das Laden von 2 Byte aus dem Speicher ist gleich schnell wie schnell wie Laden Sie 4 Byte aus dem Speicher. Wenn viele Werte aus dem Speicher verarbeitet werden, können 16 -Bit -Werte tatsächlich viel schneller sein als 32 Bitwerte, da weniger Speichertransfers vorhanden sind. Wenn eine Cache -Zeile 8 Byte beträgt, gibt es vier 16 -Bit -Werte pro Cache -Zeile, aber nur zwei 32 -Bit -Werte. Wenn Sie also 16 -Bit -INTs verwenden , was doppelt so viele Überweisungen zur Verarbeitung eines großen Int -Arrays führt.

Andere CPUs wie PPC können beispielsweise nicht nur einen Bruchteil eines Registers verarbeiten, sie verarbeiten immer das vollständige Register. Diese CPUs haben jedoch normalerweise spezielle Lastvorgänge, die es ihnen ermöglichen, z. B. einen 16 -Bit -Wert aus dem Speicher zu laden, sie auf 32 Bit zu erweitern und in ein Register zu schreiben. Später haben sie einen Special Store -Betrieb, der den Wert aus dem Register nimmt und nur die letzten 16 -Bit zurück in den Speicher speichert. Beide Operationen benötigen nur einen CPU -Zyklus, genau wie eine 32 -Bit -Last/-speicherin erforderlich wäre, sodass auch keine Geschwindigkeitsdifferenz vorhanden ist. Und da PPC nur arithmetische Operationen in Registern ausführen kann (im Gegensatz zu X86, der auch direkt im Speicher arbeiten kann), erfolgt diese Last-/Speicherprozedur ohnehin, unabhängig davon, ob Sie 32 -Bit -INTs oder 16 -Bit -INTs verwenden.

Der einzige Nachteil, wenn Sie mehrere Operationen auf einer 32 -Bit -CPU ketten, die nur bei vollständigen Registern arbeiten kann, besteht darin, dass das 32 -Bit -Ergebnis der letzten Operation möglicherweise auf 16 Bit "zurückgeschnitten" werden muss, bevor die nächste Operation durchgeführt wird. Andernfalls ist das Ergebnis möglicherweise nicht korrekt. Ein solcher Ausschnitt ist jedoch nur ein einzelner CPU -Zyklus (ein einfacher und operierender Operation), und Compiler sind sehr gut darin, herauszufinden, wann ein solcher Schnitt wirklich notwendig ist und wenn das Ablassen keinen Einfluss auf das Endergebnis hat So wird ein solcher Schnitt nach jeder Anweisung nicht durchgeführt, sondern nur, wenn sie wirklich unvermeidlich ist. Einige CPUs bieten verschiedene "verbesserte" Anweisungen, die einen solchen Schnitt unnötig machen, und ich habe in meinem Leben viel Code gesehen Vermeiden Sie es vollständig.

Wenn Sie hier eine allgemeine Regel erwarten, muss ich Sie enttäuschen. Weder kann man mit Sicherheit sagen, dass 16 -Bit -Operationen gleich schnell wie 32 Bitoperationen sind, noch kann jemand mit Sicherheit sagen, dass 32 Bit -Operationen immer schneller sein werden. Es kommt auch darauf an, was genau Ihr Code mit diesen Zahlen macht und wie er das tut. Ich habe Benchmarks gesehen, bei denen 32 Bit -Operationen bei bestimmten 32 -Bit -CPUs schneller waren als im gleichen Code mit 16 -Bit -Operationen, aber ich habe auch schon gesehen, wie das Gegenteil der Fall war. Selbst wenn Sie von einem Compiler zu einem anderen wechseln oder Ihre Compiler -Version aktualisieren, kann es bereits wieder alles umdrehen. Ich kann nur Folgendes sagen: Wer behauptet, dass die Arbeit mit Shorts erheblich langsamer ist als mit INTs, soll bitte einen Beispielquellcode für diesen Anspruch angeben und CPU und Compiler benennen, den er zum Testen verwendet habe, da ich so etwas nie erlebt habe um die letzten 10 Jahre. Es kann einige Situationen geben, in denen die Arbeit mit INTs möglicherweise 1-5% schneller ist, aber alles unter 10% ist nicht "signifikant", und es ist die Frage, dass es sich lohnt, in einigen Fällen nur dann das Doppelte des Gedächtnisses zu verschwenden, weil es Sie möglicherweise kaufen kann 2% Leistung? Ich glaube nicht.

Es hängt davon ab, ob. Wenn Sie CPU -gebunden sind, sind 32 -Bit -Operationen auf einer 32 -Bit -CPU schneller als 16 Bit. Wenn Sie Speichergebundene sind (insbesondere wenn Sie zu viele L2 -Cache -Missen haben), verwenden Sie die kleinsten Daten, in die Sie sich drücken können.

Sie können herausfinden, welche Sie einen Profiler verwenden, der sowohl die CPU- als auch die L2 -Misses wie gemessen hat Intel's vtune. Sie werden Ihre App 2 Mal mit derselben Last ausführen und die 2 Läufe in einer Ansicht der Hotspots in Ihrer App verschmelzen, und Sie können für jede Codezeile sehen, wie viele Zyklen für diese Zeile ausgegeben wurden. Wenn Sie bei einer teuren Codezeile 0 Cache -Misses sehen, sind Sie von der CPU gebunden. Wenn Sie Tonnen von Fehlschlägen sehen, sind Sie Speichergebunden.

Hören Sie nicht auf den Rat, versuchen Sie es.

Dies wird wahrscheinlich stark von der Hardware/Compiler abhängen, die Sie verwenden. Ein kurzer Test sollte eine kurze Arbeit dieser Frage machen. Wahrscheinlich weniger Zeit, um den Test zu schreiben, als hier die Frage zu schreiben.

Wenn Sie in einem großen Datensatz arbeiten, ist das größte Anliegen der Speicher Fußabdruck. Ein gutes Modell in diesem Fall ist anzunehmen, dass die CPU unendlich schnell ist und sich um Ihre Zeit verbringen, um sich Gedanken darüber zu machen, wie viel Daten in/aus dem Speicher verschoben werden müssen. Tatsächlich ist CPUs jetzt so schnell, dass es manchmal effizienter ist, die Daten zu codieren (z. B. komprimieren). Auf diese Weise leistet die CPU (möglicherweise viel) mehr Arbeit (Dekodierung/Codierung), aber die Speicherbandbreite wird wesentlich reduziert.

Wenn Ihr Datensatz groß ist, sind Sie wahrscheinlich besser damit, 16 -Bit -Ganzzahlen zu verwenden. Wenn Ihre Liste sortiert ist, können Sie ein Codierungsschema entwerfen, das eine differentielle oder längere Codierung beinhaltet, die die Speicherbandbreite noch mehr verringert.

Wenn Sie 32bit sagen, gehe ich davon aus, dass Sie x86 meinen. 16-Bit-Arithmetik ist ziemlich langsam: Das Präfix der Operand-Größe macht Decodierung Ja wirklich langsam. Machen Sie Ihre Temperaturvariablen also nicht kurz int oder int16_t.

X86 kann jedoch 16 und 8 -Bit -Gauner effizient in 32- oder 64 -Bit -Register laden. (MOVZX / MOVSX: Null- und Zeichenerweiterung). Verwenden Sie also keine kurze INT für Arrays und Strukturfelder. Stellen Sie jedoch sicher, dass Sie INT oder Sehn in Ihren Temp -Variablen verwenden.

Wenn ich jedoch zwei kurze Ganzzahlen zusammenfasse, würde das CPU -Paket beide Werte in einem einzigen Pass parallel (so die 4 -Byte -Bandbreite des Busses überspannen)?

Das ist Unsinn. Last-/Speicheranweisungen interagieren mit L1 -Cache, und der begrenzende Faktor ist die Anzahl der OPs. Breite ist irrelevant. EG auf Core2: 1 Last und 1 Speicher pro Zyklus, unabhängig von der Breite. L1 Cache hat einen 128- oder 256 -Bit -Pfad zu L2 -Cache.

Wenn Ladungen Ihr Engpass sind, kann eine breite Ladung, die Sie nach dem Laden mit Schichten oder Masken geteilt haben, helfen. Oder verwenden Sie SIMD, um Daten parallel zu verarbeiten, ohne nach dem Laden parallel zu entpacken.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top