2015-06-02 9 views
5

Szukam szybkiego sposobu obliczania iloczynu kropek wektorów z 3 lub 4 komponentami. Próbowałem kilku rzeczy, ale większość przykładów online korzysta z szeregu zmiennych, podczas gdy nasza struktura danych jest inna.Szybki produkt z kropką za pomocą intrisics SSE/AVX

Używamy struktur, które są wyrównane do 16 bajtów. fragment kodu (uproszczony):

struct float3 { 
    float x, y, z, w; // 4th component unused here 
} 

struct float4 { 
    float x, y, z, w; 
} 

W poprzednich badaniach (z wykorzystaniem SSE4 dot produkt wewnętrzną lub FMA) nie mogłem uzyskać przyspieszenie w porównaniu z użyciem po regularnych kodu C++.

float dot(const float3 a, const float3 b) { 
    return a.x*b.x + a.y*b.y + a.z*b.z; 
} 

Testy zostały wykonane za pomocą gcc i clang na Intel Ivy Bridge/Haswell. Wydaje się, że czas poświęcony na załadowanie danych do rejestrów SIMD i wyciągnięcie ich ponownie zabija wszystkie zalety.

Byłbym wdzięczny za pomoc i pomysły, w jaki sposób można efektywnie obliczyć produkt z wykorzystaniem naszych struktur danych float3/4. SSE4, AVX lub nawet AVX2 jest w porządku.

Z góry dziękuję.

+3

Czy sprawdziłeś wygenerowany ASM? W przypadku gcc można włączyć generowanie wyjścia ASM za pomocą przełącznika '' -S'' (wyjście jest zapisywane w celu podanym za pomocą '' -o''). Jakie są twoje opcje kompilacji? Czy jest możliwe, że gcc generuje już kod SSE? –

+4

Z reguły SSE przyspiesza działanie tylko wtedy, gdy masz dużo obliczeń bez opuszczania rejestrów SSE. To, co masz w swojej funkcji dot, wygląda na niewystarczające (i potwierdzone przez twoje testy). Jeśli masz coś większego, co obejmuje wywołanie kropki() (najlepiej pętlę wywołującą kropkę() tysiąc razy, a cała pętla może być zaimplementowana jako SSE) - wtedy masz dużą szansę na ogólne przyspieszenie. –

+4

Byłoby pomocne zobaczenie większego kontekstu, szczególnie kodu, który wywołuje 'kropkę'. Czy nazywasz 'kropką' w pętli, np.dla tablicy 'float3' lub' float4'? –

Odpowiedz

4

Algebraicznie efektywna karta SIMD wygląda niemal identycznie jak kod skalarny. Tak więc właściwą drogą do zrobienia produktu z kropką jest operowanie na czterech wektorach float jednocześnie dla SEE (osiem z AVX).

rozważyć budowę kodu jak ten

#include <x86intrin.h> 

struct float4 { 
    __m128 xmm; 
    float4() {}; 
    float4 (__m128 const & x) { xmm = x; } 
    float4 & operator = (__m128 const & x) { xmm = x; return *this; } 
    float4 & load(float const * p) { xmm = _mm_loadu_ps(p); return *this; } 
    operator __m128() const { return xmm; } 
}; 

static inline float4 operator + (float4 const & a, float4 const & b) { 
    return _mm_add_ps(a, b); 
} 
static inline float4 operator * (float4 const & a, float4 const & b) { 
    return _mm_mul_ps(a, b); 
} 

struct block3 { 
    float4 x, y, z; 
}; 

struct block4 { 
    float4 x, y, z, w; 
}; 

static inline float4 dot(block3 const & a, block3 const & b) { 
    return a.x*b.x + a.y*b.y + a.z*b.z; 
} 

static inline float4 dot(block4 const & a, block4 const & b) { 
    return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w; 
} 

zauważyć, że dwie ostatnie funkcje wyglądają niemal identycznie do skalara dot funkcję tą różnicą, że float staje float4 i float4 staje block3 lub block4. Spowoduje to najbardziej efektywne wykorzystanie produktu dot.

0

Aby uzyskać jak najlepsze efekty wewnętrzne AVX, trzeba myśleć w innym wymiarze. Zamiast robić produkt z jedną kropką, rób produkty z ośmioma kropkami za jednym razem.

Sprawdź różnicę między SoA and AoS. Jeśli wektory są w SoA (struktury tablic) format, dane wygląda to w pamięci:

// eight 3d vectors, called a. 
float ax[8]; 
float ay[8]; 
float az[8]; 

// eight 3d vectors, called b. 
float bx[8]; 
float by[8]; 
float bz[8]; 

Następnie do namnażania wszystkie 8 a wektory z wszystkich 8 b wektorach, należy użyć trzech SIMD mnożenia, po jednym dla każdy z x, y, z.

Jeśli chodzi o kropkę, nadal trzeba dodać, co jest nieco trudniejsze. Ale mnożenie, odejmowanie, dodawanie wektorów przy użyciu SoA jest dość łatwe i naprawdę szybkie. Gdy AVX-512 jest dostępny, możesz wykonać 16 wektorowych multiplikacji wektorowych w zaledwie 3 instrukcjach.

Powiązane problemy