2016-02-10 41 views
5

ben tutorial tanıdığımız ile hafızada bir hizalanmamış konuma bir vektör saklamak için nasıl olduğunu unaligned yükleme ve gibi bakabilirsiniz depolanması: Korkunç görünüyorAltiVec

//Load a vector from an unaligned location in memory 
__vector unsigned char LoadUnaligned(const unsigned char * src) 
{ 
    __vector unsigned char permuteVector = vec_lvsl(0, src); 
    __vector unsigned char low = vec_ld(0, src); 
    __vector unsigned char high = vec_ld(16, src); 
    return vec_perm(low, high, permuteVector); 
} 

//Store a vector to an unaligned location in memory 
void StoreUnaligned(__vector unsigned char v, __vector unsigned char * dst) 
{ 
    //Load the surrounding area 
    __vector unsigned char low = vec_ld(0, dst); 
    __vector unsigned char high = vec_ld(16, dst); 
    //Prepare the constants that we need 
    __vector unsigned char permuteVector = vec_lvsr(0, (int*) dst); 
    __vector signed char oxFF = vec_splat_s8(-1); 
    __vector signed char ox00 = vec_splat_s8(0); 
    //Make a mask for which parts of the vectors to swap out 
    __vector unsigned char mask = vec_perm(ox00, oxFF, permuteVector); 
    //Right rotate our input data 
    v = vec_perm(v, v, permuteVector); 
    //Insert our data into the low and high vectors 
    low = vec_sel(v, low, mask); 
    high = vec_sel(high, v, mask); 
    //Store the two aligned result vectors 
    vec_st(low, 0, dst); 
    vec_st(high, 16, dst); 
} 

. Bir vektörü saklamak için çok fazla iş var! Ve uygun performans kaybı vardır.

void SomeFuncA(const unsigned char * src, size_t size, unsigned char * dst) 
{ 
    for(size_t i = 0; i < size; i += 16) 
    { 
     __vector unsigned char a = vec_ld(0, src + i); 
     //simple work 
     vec_st(a, 0, dst + i); 
    }  
} 

void SomeFuncU(const unsigned char * src, size_t size, unsigned char * dst) 
{ 
    for(size_t i = 0; i < size; i += 16) 
    { 
     __vector unsigned char a = LoadUnaligned(src + i); 
     //simple work 
     StoreUnaligned(dst + i, a); 
    }  
} 

İkinci işlev, ilkinden 3-4 kez yavaşça çalışır. Giriş ve çıkış belleğinin hizalamasını kontrol edemediğimden, her iki sürümü de uygulamak zorundayım. Hizalanmamış durumdaki performans kaybını nasıl en aza indirebilirim?

cevap

4

Her şeyden önce, Altivec vektörünü hizalanmamış bir belleğe kaydederseniz, birçok kez önceki bellek durumunu dizinin ortasında yalnızca başlangıç ​​ve sonunda kaydetmeniz gerekmediğini belirtmek isterim.

template<bool align> void SomeFunc(const unsigned char * src, size_t size, unsigned char * dst) 
{ 
    Storer<align> _dst(dst); 
    __vector unsigned char a = Load<align>(src); 
    //simple work 
    _dst.First(a);// save first block 
    for(size_t i = 16; i < size; i += 16) 
    { 
     __vector unsigned char a = Load<align>(src + i); 
     //simple work 
     _dst.Next(a);// save body 
    } 
    _dst.Flush(); // save tail  
} 

Performans kaybı% 30-40 oranında hizalanmış karşılaştırmak olacaktır: gibi

typedef __vector uint8_t v128_u8; 
const v128_u8 K8_00 = vec_splat_u8(0x00); 
const v128_u8 K8_FF = vec_splat_u8(0xFF); 

template <bool align> inline v128_u8 Load(const uint8_t * p); 

template <> inline v128_u8 Load<false>(const uint8_t * p) 
{ 
    v128_u8 lo = vec_ld(0, p); 
    v128_u8 hi = vec_ld(16, p); 
    return vec_perm(lo, hi, vec_lvsl(0, p));   
}   

template <> inline v128_u8 Load<true>(const uint8_t * p) 
{ 
    return vec_ld(0, p); 
} 

template <bool align> struct Storer; 

template <> struct Storer<true> 
{ 
    template <class T> Storer(T * ptr) 
     :_ptr((uint8_t*)ptr) 
    { 
    } 

    template <class T> inline void First(T value) 
    { 
     vec_st((v128_u8)value, 0, _ptr); 
    } 

    template <class T> inline void Next(T value) 
    { 
     _ptr += 16; 
     vec_st((v128_u8)value, 0, _ptr); 
    } 

    inline void Flush() 
    { 
    } 
private: 
    uint8_t * _ptr; 
}; 

template <> struct Storer<false> 
{ 
    template <class T> inline Storer(T * ptr) 
     :_ptr((uint8_t*)ptr) 
    { 
     _perm = vec_lvsr(0, _ptr); 
     _mask = vec_perm(K8_00, K8_FF, _perm); 
    } 

    template <class T> inline void First(T value) 
    { 
     _last = (v128_u8)value; 
     v128_u8 background = vec_ld(0, _ptr); 
     v128_u8 foreground = vec_perm(_last, _last, _perm); 
     vec_st(vec_sel(background, foreground, _mask), 0, _ptr); 
    } 

    template <class T> inline void Next(T value) 
    { 
     _ptr += 16; 
     vec_st(vec_perm(_last, (v128_u8)value, _perm), 0, _ptr); 
     _last = (v128_u8)value; 
    } 

    inline void Flush() 
    { 
     v128_u8 background = vec_ld(16, _ptr); 
     v128_u8 foreground = vec_perm(_last, _last, _perm); 
     vec_st(vec_sel(foreground, background, _mask), 16, _ptr); 
    } 
private: 
    uint8_t * _ptr; 
    v128_u8 _perm; 
    v128_u8 _mask; 
    v128_u8 _last; 
}; 

Onun bakmak olacaktır kullanarak: Yani bu işlevi uygulamak Simd Library bir kullanışlı fonksiyon ve sınıf vardır sürümü. Bu hoş olmayan bir şekilde elbette ama toleranslı.

Ek avantaj kodun azaltılmasıdır - tüm işlevler (hizalanmış ve hizalanmamış) aynı uygulamaya sahiptir.

+0

Teşekkür ederiz! Harika görünüyor! – Georg