2011-02-25 87 views
8

在我的项目中,我实现了基本类CVector。 该类包含指向原始浮点数组的float *指针。 使用标准malloc()函数动态分配此数组。使用SSE加速计算 - 存储,加载和对齐

现在我必须加快使用这些向量的一些计算。不幸的是,因为使用_mm_malloc()未分配内存,所以未对齐。

据我所知我有两种选择:

void sub(float* v1, float* v2, float* v3, int size) 
{ 
    __m128* p_v1 = (__m128*)v1; 
    __m128* p_v2 = (__m128*)v2; 
    __m128 res; 

    for(int i = 0; i < size/4; ++i) 
    { 
     res = _mm_sub_ps(*p_v1,*p_v2); 
     _mm_store_ps(v3,res); 
     ++p_v1; 
     ++p_v2; 
     v3 += 4; 
    } 
} 

2)第二个选项是:

1),其将存储器分配给使用_mm_malloc()并且例如使用这样的代码重写代码使用_mm_loadu_ps()指令从未对齐的内存中加载__m128,然后将其用于计算。

void sub(float* v1, float* v2, float* v3, int size) 
{ 
    __m128 p_v1; 
    __m128 p_v2; 
    __m128 res; 

    for(int i = 0; i < size/4; ++i) 
    { 
     p_v1 = _mm_loadu_ps(v1); 
     p_v2 = _mm_loadu_ps(v2); 
     res = _mm_sub_ps(p_v1,p_v2);  
     _mm_store_ps(v3,res); 
     v1 += 4; 
     v2 += 4; 
     v3 += 4; 
    } 
} 

所以我的问题是哪个选项会更好或更快?

回答

15

读取未对齐的SSE值非常昂贵。检查英特尔手册第4卷第2.2.5.1章。核心类型有所不同,i7有额外的硬件,使其成本更低。但是读取跨越cpu缓存行边界的值仍然比读取对齐值慢4.5倍。在以前的架构上,这是倍。

这是巨大的,让内存对齐,以避免perf命中。从未听说_mm_malloc,使用Microsoft CRT中的_aligned_malloc()从堆中获取正确对齐的内存。

+6

很好的答案。我期待只能在这里找到“剖析你的代码”的答案...... – Inverse 2011-02-25 17:38:24

+0

现代架构上的代价并不高。 – Quonux 2017-06-28 01:08:53

1

看看bullet physics。它已被用于少数电影和众所周知的游戏(GTA4等)。你可以看看他们超级优化的矢量,矩阵和其他数学类,或者只是用它们来代替。它在zlib许可下发布,因此您可以随意使用它。不要重新发明轮子。 Bullet,nvidia physx,havok和其他物理图书馆都经过了非常精明的测试和优化。