Viele Mikroarchitektur-Interessierte und hardwarenahe x86-Programmierer kennen bereits die x86-Optimierungsleitfäden sowie CPU-Architekturdiagnosen von Dr. Agner Fog von der Universität Kopenhagen. Nun hat er seine PDFs um AMDs Bulldozer-Architektur ergänzt.
Hier nun die schlimmsten Flaschenhälse im Überblick:
Instruktions-Dekoder 1
Zitat:
Instructions with up to three prefixes can be decoded in one clock cycle. There is a very large penalty for instructions with more than three prefixes. Instructions with 4-7 prefixes take 14-15 clock cycles extra to decode. Instructions with 8-11 prefixes take 21-22 clock cycles extra, and instructions with 12-14 prefixes take 28 clock cycles extra. It is therefore not recommended to make NOP instructions longer with more than three prefixes. The prefix count for this rule includes operand size, address size, segment, repeat, wait, REX and XOP prefixes. A three-bytes VEX prefix counts as one, while a two-bytes VEX prefix does not count. Escape codes (0F, 0F38, 0F3A) do not count.
Hier wird eine Schwachstelle beschrieben, bei der (sehr) lange x86-Instruktionen ab drei Präfixen einen starken Anstieg der Verweildauer im Dekoder verzeichnen. Mit mindestens 14 Takten zusätzlich und maximal gar 28 Takten ist in diesen Fällen zu rechnen, was ziemlich viel ist. In dieser Zeit könnte schon das Ergebnis der Berechnung feststehen - wenn der Dekoder eben nicht so langsam arbeiten würde.
Instruktions-Dekoder 2
Zitat:
The decode unit can handle four instructions per clock cycle. It is alternating between the two threads so that each thread gets up to four instructions every second clock cycle, or two instructions per clock cycle on average. This is a serious bottleneck in my tests because the rest of the pipeline can handle up to four instructions per clock. The situation gets even worse for instructions that generate more than one macro-op each. Instructions that generate two macro-ops are called double instructions. The decoders can handle one double instruction and two single instructions in one clock cycle, but not two double instructions. Instructions that generate more than two macro-ops are using microcode. The decoders cannot do anything else while microcode is generated. This means that both cores in a compute unit can stop decoding for several clock cycles after meeting an instruction that generates more than two macro-ops. The number of macro-ops generated by each instruction is listed in manual 4: "Instruction tables".
Schon früher tauchte die Vermutung auf, dass der - von beiden Kernen gemeinsam benutzte - Dekoder zu wenig Befehle dekodieren kann. Pro Takt und pro Kern schafft er im Schnitt maximal nur zwei x86 Instruktionen. Im schlimmsten Fall, falls externe x86-Instruktionen in mehr als eine CPU-interne Macro-Instruktion (Macro-Op) übersetzt werden müssen, sinkt der Durchsatz aber. Bei Befehlen, die durch die Microcode-Engine dekodiert werden müssen, steht der ganze Dekoder außerdem für ein paar Takte komplett still und blockiert damit den zweiten Kern.
Nun könnte man darauf hoffen, dass vielleicht MacroOp-Fusion, das Intel mit den Conroe-Chips (erste Generation der Core2 Duos) einführte und erstmals nun auch bei AMD im Bulldozer Verwendung findet, Abhilfe schaffen würde. Schließlich werden dabei zwei x86-Instruktionen zu einer Macro-Op dekodiert. Leider ist das aber bei AMD nicht der Fall:
Zitat:
No other ALU instruction can fuse with a conditional jump. The maximum decode rate is not increased by instruction fusion.
Warum das so ist, wird nicht erklärt. Eventuell liegt es daran, dass die Bündelung bei AMD erst nach dem Dekoder passiert, während sie bei Intel davor passieren könnte.
Execution units
Zitat:
The integer execution units are poorly distributed between the four pipes. Two of the pipes have all the execution units while the other two pipes are used only for memory read instructions, and on some models for simple register moves. This means that the Bulldozer can execute only two integer ALU instructions per clock cycle, where previous models can execute three. This is a serious bottleneck for pure integer code. The single-core throughput for integer code can actually be doubled by doing half of the instructions in vector registers, even if only one element of each vector is used.
Hier wird nun auf das altbekannte Dilemma eingegangen, dass es von den - offiziell vier - Pipelines trotz optimistischer Zählweise eigentlich doch nur zwei sind, die die Arbeit verrichten, also eine weniger als bisher bei den letzten Chips der "K"-Generationen. In Zukunft, mit den 20h-Modellen (siehe dazu auch unsere frühere Meldung), wird dies zwar etwas besser werden, aber eine Offenbarung ist das ebenfalls noch nicht. Es bleibt die Hoffnung auf Steamroller - falls es sich dabei nicht schon die 20h-Modelle handeln sollte.
L1-Daten Cache [Update]
Zitat:
The data cache has two 128-bit ports which can be used for either read or write. This means that it can do two reads or one read and one write in the same clock cycle. The measured throughput is two reads or one read and one write per clock cycle when only one core is active. We wouldn't expect the throughput to be less when both cores are active because the two cores in an execution unit have separate load/store units and data cache. But the measurements say otherwise. The measured throughput is typically 1.5 memory operation per core per clock, and the highest value that has been measured is 1.88 memory operation per core per clock when both cores are active. No explanation has been found for this reduced throughput. The decoders, which are shared between cores, should be able to handle two instructions per core per clock cycle.
Hier wird es nun interessant. Jeder Integer-Kern eines Bulldozer Moduls hat bekanntermaßen seinen eigenen L1-Datencache von 16kB, die unabhängig voneinander sind. Pro Takt können laut AMD-Manual zwei 128-Bit-Lesevorgänge (Load) und eine 128-Bit-Schreiboperation (Store) vorgenommen werden:
Zitat:
The load/store unit completes all memory accesses once address generation has occurred in the execution. The L1 data cache is a 16-Kbyte, way-predicted, write-through cache designed to support up to two 128-byte loads per cycle. In addition, one 128-byte store can be committed to the cache. Load-use latency is four cycles, and loads proceed in a fully out-of-order fashion.
Dem widerspricht Agner Fog nun. Mit einem aktiven Kern kann er nur maximal 2 Operationen messen, entweder zwei Load oder eine Load-/ und ein Storeoperation. Diese Diskrepantz läßt sich noch einfach auflösen. Da es nur zwei AGUs zur Adressberechnung gibt, kann es wirklich nur zwei unterschiedliche Adressen pro Takt geben. Der Unterschied liegt dann eigentlich nur in der nicht berücksichtigten Bandbreite. Die von AMD angegebenen zwei 128-Bit Loads beziehen sich sicherlich auf zwei 128-Bit-Load-Ports, die zusammen genommen auch einen 256-Bit Ladevorgang bewältigen können. Dafür reicht dann eine Adresse und die zweite Adresse kann für eine Store-Operation verwendet werden. Soweit so gut, merkwürdig wird es dann aber mit zwei gleichzeitig aktiven Kernen eines Moduls. Anstatt theoretisch möglichen zwei Speicheroperationen sind es im Mittel mit zwei aktiven Kernen nur noch 1,5 Speicheroperationen pro Kern, maximal 1,88. Nachdem die beiden Kerne eigentlich unabhängig voneinander sein sollten, erwartet man so einen Fall nicht. Eine Teilerklärung ist vielleicht die Write-Through-Arbeitsweise der L1-Caches. Das bedeutet, dass Store-Speicheroperationen auch unverzüglich in den gemeinsam genutzen L2 geschrieben werden müssen. Allerdings gibt es eben nur einen einzigen L2-Cache und nur einen Write-Combining-Puffer um darauf schreibend zugreifen zu können. Summiert man die max. möglichen Operationen beider Kernen auf und geht deshalb von theoretisch möglichen vier Speicheroperationen pro Modul aus, passen die typisch-gemessenen drei Operationen pro Modul / zwei Threads gut dazu. Es fehlt genau eine Operation - höchstwahrscheinlich eine Store-Operation. Allerdings sollten vier Ladeoperationen ohne Problem möglich sein. Woran es liegen kann, dass es maximal trotzdem nur 1,88 Operationen sind und nicht 2, ist unbekannt und merkwürdig. Der Sinn der beiden Kerne ist schließlich, sich nicht gegenseitig zu behindern bzw. auf die Füße zu treten.
Zuletzt wird dann noch von häufig auftretenden L1-Speicherbank-Konflikten berichtet:
Zitat:
The data cache is organized as 16 banks of 16 bytes each. The data cache cannot do two memory operations in the same clock cycle if they use banks that are spaced by a multiple of 100h bytes, except for two reads from the same cache line. This kind of cache bank conflict occurs very often:
Das hört sich wieder nicht gut an, aber immerhin sollte dieser Fall bereits im oben genannten "typical throughput" berücksichtig bzw. gemessen worden sein.
Fazit: Der Eindruck, dass die Bulldozer-Architektur mit angezogener Handbremse unterwegs ist, kam ja schon relativ früh auf, aber nach den Testergebnissen von Dr. Agner Fog muss man wohl eher von angezogener Handbremse samt Zusatzballast reden. Es bleibt zu hoffen, dass AMD die Schwachstellen in zukünftigen Designs behebt, oder wenigstens weitet. Laut eines c't-Artikels in Ausgabe 23/2011 soll die Steamroller-Generation (von der wir erst kürzlich berichteten) jeweils einen eigenen x86-Dekoder pro Kern bekommen. Wollen wir hoffen, dass das der Wahrheit entspricht. Zur Diskussion gibt es bereits einen Thread in unserem Forum: Zambezi - Fehler, Bugs, mangelnde Performance - Woran liegt es?
Diesen Artikel bookmarken oder senden an ...