2013-05-22 13 views
5

Wie wir wissen, hat X86 CPU einen 64-Bit-Datenbus. Mein Verständnis ist, dass CPU nicht auf beliebige Adresse zugreifen kann. Die Adresse, auf die die CPU zugreifen kann, ist ein ganzzahliges Vielfaches der Breite ihres Datenbusses. Für die Leistung sollten Variablen bei diesen Adressen beginnen (auf diese ausgerichtet sein), um zusätzlichen Speicherzugriff zu vermeiden. 32-Bit-Variablen, die an die 4-Byte-Grenze angepasst sind, werden automatisch auf 8-Byte-Grenze (64-Bit-Grenze) ausgerichtet, was einem x86-64-Bit-Datenbus entspricht. Aber warum Compiler 128bit Variablen auf 16Byte Grenze ausrichten? Nicht die 8Byte Grenze?warum 128bit Variablen auf 16Byte Grenze ausgerichtet werden sollten

Danke

Lassen Sie mich die Dinge spezifischer machen. Compiler verwenden die Länge einer Variablen, um sie auszurichten. Wenn eine Variable beispielsweise eine Länge von 256 Bit hat, richtet Complier sie auf 32 Byte Grenze aus. Ich glaube nicht, dass irgendeine Art von CPU diesen langen Datenbus hat. Darüber hinaus übertragen gewöhnliche DDR-Speicher nur 64-Bit-Daten nur einmal, trotz des Cache, wie könnte ein Speicher den breiteren Datenbus der CPU füllen? oder nur mittels Cache?

+3

"Wie wir wissen, X86 CPU hat einen 64-Bit-Datenbus" - das ist nicht wahr. x86 sagt nichts über Datenbusgrößen aus. Moderne Prozessoren haben tatsächlich größere Datenbusbreiten als diese. – Mysticial

+4

Prozessor liest keine Daten vom Datenbus, sie lesen es aus dem Cache. Eine 16-Byte-Ausrichtung ist erforderlich, um eine Überbrückung einer Cache-Zeilengrenze zu vermeiden. –

+0

@Mysticial Ich denke, die beliebtesten x86 CPUs haben derzeit 64-Bit-Datenbus, nicht wahr? – iqapple

Antwort

4

Es gibt so viele verschiedene Prozessormodelle, die ich nur theoretisch und allgemein beantworten werde.

Betrachten Sie ein Array von 16-Byte-Objekten, das an einer Adresse beginnt, die ein Vielfaches von acht Byte, aber nicht von 16 Byte ist. Nehmen wir an, der Prozessor hat einen 8-Byte-Bus, wie in der Frage angegeben, auch wenn einige Prozessoren dies nicht tun. Beachten Sie jedoch, dass an einem Punkt im Array eines der Objekte eine Seitenbegrenzung überspannen muss: Die Speicherzuordnung funktioniert normalerweise in 4096-Byte-Seiten, die an 4096-Byte-Grenzen beginnen. Bei einem acht Byte ausgerichteten Array beginnt ein Element des Arrays bei Byte 4088 einer Seite und geht bis zum Byte 7 der nächsten Seite weiter.

Wenn ein Programm versucht, das 16-Byte-Objekt zu laden, das eine Seitengrenze überschreitet, kann es keine einzelne virtuelle-physische Speicherzuordnung mehr ausführen. Es muss eine Suche nach den ersten acht Bytes und eine weitere Suche nach den zweiten acht Bytes durchführen. Wenn die Lade-/Speichereinheit nicht dafür ausgelegt ist, benötigt die Anweisung eine spezielle Handhabung. Der Prozessor könnte seinen anfänglichen Versuch, den Befehl auszuführen, abbrechen, ihn in zwei spezielle Mikrobefehle aufteilen und diese zur Ausführung in die Befehlswarteschlange zurückschicken. Dies kann den Befehl um viele Prozessorzyklen verzögern.

Darüber hinaus interagiert, wie Hans Passant bemerkte, Alignment mit Cache. Jeder Prozessor hat einen Speichercache, und es ist üblich, dass der Cache in 32-Byte- oder 64-Byte- "Zeilen" organisiert ist. Wenn Sie ein 16-Byte-Objekt laden, das 16 Byte ausgerichtet ist und das Objekt im Cache ist, kann der Cache eine Cachezeile bereitstellen, die die erforderlichen Daten enthält. Wenn Sie 16-Byte-Objekte aus einem Array laden, das nicht 16-Byte-ausgerichtet ist, werden einige der Objekte im Array zwei Cache-Zeilen spreizen. Wenn diese Objekte geladen werden, müssen zwei Zeilen aus dem Cache abgerufen werden. Dies kann länger dauern. Selbst wenn es nicht länger dauert, zwei Zeilen zu bekommen, vielleicht weil der Prozessor so ausgelegt ist, dass er zwei Cache-Zeilen pro Zyklus bereitstellt, kann dies andere Dinge beeinträchtigen, die ein Programm ausführt. Üblicherweise lädt ein Programm Daten von mehreren Orten. Wenn die Lasten effizient sind, kann der Prozessor möglicherweise zwei gleichzeitig ausführen. Wenn jedoch eine von ihnen zwei Cache-Zeilen anstelle der normalen benötigt, blockiert sie die gleichzeitige Ausführung anderer Ladeoperationen.

Darüber hinaus erfordern einige Anweisungen explizit ausgerichtete Adressen. Der Prozessor könnte diese Anweisungen direkter versenden und einige der Tests, die Operationen ohne ausgerichtete Adressen reparieren, umgehen. Wenn die Adressen dieser Befehle aufgelöst sind und sich als falsch erwiesen haben, muss der Prozessor sie abbrechen, da die Reparaturoperationen umgangen wurden.

+0

Ich weiß, dass Sie Recht haben, selbst wenn einige Punkte esoterisch zu mir sind – iqapple

+0

IMO, das meiste dieser Antwort, während es selbst wahr ist, ist irrelevant für die Frage, die "aber warum Compiler war 128bit-Variablen auf 16Byte-Grenze ausrichten? ". Die Antwort auf diese Frage ist einfach, dass die Hardware es erfordert, der Compiler tut es nicht, weil es effizienter ist, sondern weil jede andere Methode nicht funktioniert Sie sagen "Betrachten Sie ein Array von 16-Byte-Objekten, die an einer Adresse beginnt, die ein Vielfaches von acht Bytes ist, aber nicht von 16 Bytes.", das wird einfach nicht funktionieren (weil die CPU-Hardware es nicht unterstützt) ob das Array eine Seitengrenze überschreitet. – Bull

+0

Eigentlich hängt es davon ab, was die Frage mit "variabel" meint. Ich dachte an 128 Variablen wie __m128i. Wenn es um Dinge wie "struct foo {char x [128];};" geht, stimme ich Eric zu. – Bull

5

Ein Grund ist, dass die meisten SSE2-Anweisungen auf X86 erfordern, dass die Daten 128-Bit-ausgerichtet sind. Diese Design-Entscheidung wäre aus Leistungsgründen getroffen worden und um übermäßig komplexe (und daher langsame und große) Hardware zu vermeiden.

+0

Ich denke, das ist wahrscheinlich richtig. Ich bin hier in einer Schleife fest, um herauszufinden, welche Compiler __m128i automatisch ausrichten Typ, der für die vektorisierte SIMD Berechnung verwendet wird –

Verwandte Themen