Was ist der effizienteste Weg, 4 Schwimmer von 4 Schwimmern SSE multiplizieren mit?
Frage
Im Moment habe ich den folgenden Code:
float a[4] = { 10, 20, 30, 40 };
float b[4] = { 0.1, 0.1, 0.1, 0.1 };
asm volatile("movups (%0), %%xmm0\n\t"
"mulps (%1), %%xmm0\n\t"
"movups %%xmm0, (%1)"
:: "r" (a), "r" (b));
Ich habe zunächst einmal ein paar Fragen:
(1), wenn ich die Arrays auf 16-Byte-Grenzen auszurichten, würde es funktioniert auch? Da die Arrays auf dem Stack zugeordnet sind, ist es wahr, dass sie Ausrichtung nahezu unmöglich ist?
sehen die gewählte Antwort für diesen Beitrag: Sind stapeln Variablen vom GCC __attribute __ ausgerichtet ((ausgerichtet (x)) )?
(2) Kann der Code überhaupt Refactoring wird, um es effizienter? Was passiert, wenn ich beide Schwimmer-Arrays in Register setzen, anstatt nur ein?
Danke
Lösung
Wenn ich die Arrays auf 16-Byte-Grenzen auszurichten, würde es funktioniert auch? Da die Arrays auf dem Stack zugeordnet sind, ist es wahr, dass sie Ausrichtung nahezu unmöglich ist?
Es ist erforderlich, dass die Ausrichtung auf dem Stapel funktioniert. Sonst wäre intrinsics nicht funktionieren. Ich würde vermuten, die Post, den Sie mit dem exorbitanten Wert, den er für den Ausrichtungswert ausgewählt zu tun hatte, zitiert.
2:
Nein, es soll keinen Unterschied in der Leistung sein. Sehen Sie dieses Website für den Befehl Timings von mehreren Prozessoren rel="nofollow.
Wie Ausrichtung von Stack-Variablen funktioniert:
push ebp
mov ebp, esp
and esp, -16 ; fffffff0H
sub esp, 200 ; 000000c8H
Die und richtet sich die zu 16 Byte des Stapels beginnen.
Andere Tipps
Schreiben Sie es in C, verwenden Sie
gcc -S -mssse3
Wenn Sie eine ziemlich neue Version von gcc.
(1), wenn ich die Arrays auf 16-Byte-Grenzen auszurichten, würde es funktioniert auch? Da die Arrays auf dem Stack zugeordnet sind, ist es wahr, dass sie Ausrichtung nahezu unmöglich ist?
Nein, es ist ganz einfach, den Stapelzeiger mit and
auszurichten:
and esp, 0xFFFFFFF0 ; aligned on a 16-byte boundary
Aber Sie sollten verwenden, was GCC bietet, wie zum Beispiel eines 16 Byte-Typen oder __attribute__
zu Ausrichtung anpassen.
Bieten GCC Unterstützung für den __m128
Datentyp? Wenn ja, das ist die beste Plan, einen 16-Byte-ausgerichteten Datentypen für die Gewährleistung. Dennoch gibt es __attribute__((aligned(16)))
für Dinge ausrichten. Definieren Sie Ihre Arrays wie folgt
float a[4] __attribute__((aligned(16))) = { 10, 20, 30, 40 };
float b[4] __attribute__((aligned(16))) = { 0.1, 0.1, 0.1, 0.1 };
und dann MOVAPS verwendet stattdessen:)
intrinsische Verwendung ist viel schneller vor allem mit der Optimierung. Ich schrieb einfachen Test und vergleichen beide Version (asm und intrinsisch)
unsigned long long time1;
__m128 a1,b1;
a1=_mm_set_ps(10, 20,30,40);
b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1);
float a[4] = { 10, 20, 30, 40 };
float b[4] = { 0.1, 0.1, 0.1, 0.1 };
time1=__rdtsc();
a1=_mm_mul_ps(a1,b1);
time1=__rdtsc() - time1 ;
printf("Time: %llu\n",time1);
time1=__rdtsc();
asm volatile("movups (%0), %%xmm0\n\t"
"mulps (%1), %%xmm0\n\t"
"movups %%xmm0, (%1)"
:: "r" (a), "r" (b));
time1=__rdtsc() - time1 ;
printf("Time: %llu\n",time1);
Intrinsic Version 50-60 Prozessor Zeitstempel Asm Version ~ 1000 proc Zeitstempel
Sie können es auf Ihrem Rechner testen
Über Refactoring. Sie können intrinsische verwenden. Beispiel:
#include <emmintrin.h>
int main(void)
{
__m128 a1,b1;
a1=_mm_set_ps(10, 20,30,40);
b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1);
a1=_mm_mul_ps(a1,b1);
return 0;
}
Mit Optimierung gcc (-O2
, -O3
) es schneller arbeiten dann asm sein kann.