Branch alignment for loops involving micro-coded instructions on Intel SnB-family CPU

Th, ist verwandt, aber nicht dasselbe, wie diese Frage:Leistungsoptimierungen der x86-64-Baugruppe - Ausrichtung und Verzweigungsvorhersage und hat etwas mit meiner vorherigen Frage zu tun:Unsigned 64-Bit zu Doppelkonvertierung: Warum dieser Algorithmus von g ++

Das Folgende ist einnicht real Testfall. Dieser Primalitätstest-Algorithmus ist nicht sinnvoll. Ich vermuteirgendei realer Algorithmus würde niemals eine so kleine innere Schleife so oft ausführen num ist eine Primzahl mit einer Größe von ungefähr 2 ** 50). In C ++ 11:

using nt = unsigned long long;
bool is_prime_float(nt num)
{
   for (nt n=2; n<=sqrt(num); ++n) {
      if ( (num%n)==0 ) { return false; }
   }
   return true;
}

Danng++ -std=c++11 -O3 -S erzeugt folgendes, wobei RCX @ enthän und XMM6 mitsqrt(num). In meinem vorherigen Beitrag finden Sie den verbleibenden Code (der in diesem Beispiel nie ausgeführt wird, da RCX nie groß genug wird, um als signiertes Negativ behandelt zu werden).

jmp .L20
.p2align 4,,10
.L37:
pxor    %xmm0, %xmm0
cvtsi2sdq   %rcx, %xmm0
ucomisd %xmm0, %xmm6
jb  .L36   // Exit the loop
.L20:
xorl    %edx, %edx
movq    %rbx, %rax
divq    %rcx
testq   %rdx, %rdx
je  .L30   // Failed divisibility test
addq    $1, %rcx
jns .L37
// Further code to deal with case when ucomisd can't be used

Ich Zeit dies mitstd::chrono::steady_clock. Ich bekam immer wieder merkwürdige Leistungsänderungen: vom Hinzufügen oder Löschen von anderem Code. Ich habe dies schließlich auf ein Ausrichtungsproblem zurückgeführt. Der Befehl.p2align 4,,10 hat versucht, an einer 2 ** 4 = 16-Byte-Grenze auszurichten, verwendet jedoch höchstens 10 Byte Auffüllung, um ein Gleichgewicht zwischen Ausrichtung und Codegröße herzustellen.

Ich habe ein Python-Skript geschrieben, um @ zu ersetze.p2align 4,,10 durch eine manuell gesteuerte Anzahl vonnop Anweisungen. Das folgende Streudiagramm zeigt die schnellsten 15 von 20 Läufen, die Zeit in Sekunden und die Anzahl der auf der x-Achse aufgefüllten Bytes:

Vonobjdump ohne Auffüllung wird die pxor-Anweisung bei Offset 0x402f5f ausgeführt. Laufen auf einem Laptop, Sandybridge i5-3210m, turboboostdeaktivier, Ich habe das gefunde

Für 0-Byte-Auffüllung, langsame Leistung (0,42 Sekunden)Für 1-4-Byte-Auffüllung (Offset 0x402f60 bis 0x402f63) etwas besser (0,41s, im Plot sichtbar).Für das Auffüllen von 5-20 Bytes (Offset 0x402f64 bis 0x402f73) erhalten Sie eine schnelle Leistung (0,37 s)Für 21-32-Byte-Auffüllung (Offset 0x402f74 bis 0x402f7f) langsame Leistung (0,42 Sekunden) Dann Zyklen auf einem 32-Byte-Sample

Also liefert eine 16-Byte-Ausrichtung nicht die beste Leistung - sie bringt uns in den etwas besseren Bereich (oder nur in den Bereich mit einer geringeren Abweichung vom Streudiagramm). Eine Ausrichtung von 32 plus 4 bis 19 ergibt die beste Leistung.

Warum sehe ich diesen Leistungsunterschied? Warum verstößt dies anscheinend gegen die Regel, Zweigziele an einer 16-Byte-Grenze auszurichten (siehe z. B. das Handbuch zur Intel-Optimierung

Ich sehe keine Probleme mit der Verzweigungsvorhersage. Könnte dies eine UOP-Cache-Skurrilität sei

Durch Ändern des C ++ - Algorithmus auf Cachesqrt(num) in einer 64-Bit-Ganzzahl und dann die Schleife rein ganzzahlig machen, entferne ich das Problem - Ausrichtung macht jetzt überhaupt keinen Unterschied.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage