2015-06-02 8 views
5

Sto cercando un modo rapido per calcolare il prodotto punto di vettori con 3 o 4 componenti. Ho provato diverse cose, ma la maggior parte degli esempi online utilizza una serie di float mentre la nostra struttura dati è diversa.Prodotto a punti veloci usando intrinseci SSE/AVX

Utilizziamo le strutture allineate a 16 byte. estratto di codice (semplificato):

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

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

Nei test precedenti (utilizzando SSE4 prodotto scalare intrinseco o FMA) non ho potuto ottenere un aumento di velocità, rispetto al utilizzando il seguente codice C++ regolare.

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

I test sono stati eseguiti con gcc e clang su Intel Ivy Bridge/Haswell. Sembra che il tempo speso per caricare i dati nei registri SIMD e tirarli fuori di nuovo uccide tutti i vantaggi.

Gradirei un po 'di aiuto e idee, come il prodotto punto può essere calcolato in modo efficiente utilizzando le nostre strutture dati float3/4. SSE4, AVX o anche AVX2 va bene.

Grazie in anticipo.

+3

Hai controllato l'ASM generato? Per gcc, puoi attivare la generazione di output ASM usando l'opzione '' -S'' (l'output è scritto sull'obiettivo dato con '' -o''). Quali sono le tue opzioni di compilazione? È possibile che gcc produca già il codice SSE? –

+4

Come regola generale, SSE accelera le cose solo se si hanno molti calcoli senza lasciare i registri SSE. Quello che hai nella tua funzione punto sembra non abbastanza (e confermato anche dai tuoi test). Se avete qualcosa di più grande che include una chiamata a punto() (idealmente un ciclo che chiama punto() un migliaio di volte, e l'intero ciclo può essere implementato come SSE) - allora avete una buona possibilità di accelerazione generale. –

+4

Sarebbe utile vedere più contesto, in particolare il codice che chiama 'punto'. Stai chiamando 'punto' in un ciclo, ad es.per un array di 'float3' o' float4'? –

risposta

4

Algebricamente, SIMD efficiente sembra quasi identico al codice scalare. Quindi il modo giusto per fare il prodotto dot è di operare su quattro vettori float contemporaneamente per SEE (otto con AVX).

Considerate costruire il vostro codice come questo

#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; 
} 

Si noti che le ultime due funzioni sembrano quasi identico al vostro scalare dot funzione, a meno che float diventa float4 e float4 diventa block3 o block4. Questo farà il punto del prodotto in modo più efficiente.

0

Per ottenere il meglio dagli intrinsechi AVX, è necessario pensare in una dimensione diversa. Invece di fare un prodotto con un punto, fai 8 punti in un colpo solo.

Cercare la differenza tra SoA and AoS. Se i vettori sono in dichiarazione di affidabilità (strutture di array) formato, i dati si presenta come questo in memoria:

// 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]; 

Poi, per moltiplicare tutte le 8 a vettori con tutti i 8 B vettori, si utilizzano tre moltiplicazioni SIMD, uno per ciascuno di x, y, z.

Per punto, è necessario aggiungere in seguito, naturalmente, che è un po 'più complicato. Ma la moltiplicazione, la sottrazione, l'aggiunta di vettori, l'uso di SoA è abbastanza facile e molto veloce. Quando AVX-512 è disponibile, puoi eseguire 16 moltiplicazioni vettoriali 3D in sole 3 istruzioni.

Problemi correlati