AVX:数据对齐:store crash,storeu,load,loadu 没有
AVX: data alignment: store crash, storeu, load, loadu doesn't
我正在修改 RNNLM 一个神经网络来研究语言模型。但是考虑到我的语料库的大小,它 运行 真的很慢。我试图优化矩阵*向量例程(这是一个占小数据集总时间 63% 的例程(我预计它在大数据集上会更糟))。现在我坚持使用内在函数。
for (b=0; b<(to-from)/8; b++)
{
val = _mm256_setzero_ps();
for (a=from2; a<to2; a++)
{
t1 = _mm256_set1_ps (srcvec.ac[a]);
t2 = _mm256_load_ps(&(srcmatrix[a+(b*8+from+0)*matrix_width].weight));
//val =_mm256_fmadd_ps (t1, t2, t3)
t3 = _mm256_mul_ps(t1,t2);
val = _mm256_add_ps (val, t3);
}
t4 = _mm256_load_ps(&(dest.ac[b*8+from+0]));
t4 = _mm256_add_ps(t4,val);
_mm256_store_ps (&(dest.ac[b*8+from+0]), t4);
}
此示例崩溃于:
_mm256_store_ps (&(dest.ac[b*8+from+0]), t4);
但是如果我改成
_mm256_storeu_ps (&(dest.ac[b*8+from+0]), t4);
(我想你是未对齐的)一切都按预期进行。我的问题是:为什么 load 会工作(而如果数据未对齐,它不应该工作)而存储不会。 (此外两者都在同一个地址上运行)。
dest.ac 已使用
分配
void *_aligned_calloc(size_t nelem, size_t elsize, size_t alignment=64)
{
size_t max_size = (size_t)-1;
// Watch out for overflow
if(elsize == 0 || nelem >= max_size/elsize)
return NULL;
size_t size = nelem * elsize;
void *memory = _mm_malloc(size+64, alignment);
if(memory != NULL)
memset(memory, 0, size);
return memory;
}
并且它至少有 50 个元素长。
(顺便说一句,在 VS2012 中我有一些随机分配的非法指令,所以我使用 linux。)
提前谢谢你,
阿肯图斯
TL:DR:在优化代码中,。商店不会。
您的示例代码不会自行编译,所以我无法轻松检查 _mm256_load_ps
编译成什么指令。
我用 gcc 4.9 做了一个小实验,它根本没有为 _mm256_load_ps
生成 vmovaps
,因为我只使用加载的结果作为另一个的输入操作说明。它使用内存操作数生成该指令。 AVX 指令对其内存操作数没有对齐要求。 (越过缓存行会影响性能,越过页面边界会影响性能,但您的代码仍然有效。)
另一方面,商店会生成 vmov...
指令。由于您使用了需要对齐的版本,因此它会在未对齐的地址上出错。只需使用未对齐的版本;当地址对齐时它会一样快,而当它不对齐时它仍然可以工作。
我没有仔细检查您的代码以查看是否所有访问都应该对齐。我假设不是,从你措辞的方式来看,只是问为什么你没有因为未对齐的负载而出现故障。就像我说的,可能你的代码没有编译成任何 vmovaps
加载指令,否则即使 "aligned" AVX 加载也不会在未对齐的地址上出错。
你 运行 AVX(没有 AVX2 或 FMA?)在 Sandy/Ivybridge CPU 上吗?我认为这就是为什么您的 FMA 内在函数被注释掉的原因。
我正在修改 RNNLM 一个神经网络来研究语言模型。但是考虑到我的语料库的大小,它 运行 真的很慢。我试图优化矩阵*向量例程(这是一个占小数据集总时间 63% 的例程(我预计它在大数据集上会更糟))。现在我坚持使用内在函数。
for (b=0; b<(to-from)/8; b++)
{
val = _mm256_setzero_ps();
for (a=from2; a<to2; a++)
{
t1 = _mm256_set1_ps (srcvec.ac[a]);
t2 = _mm256_load_ps(&(srcmatrix[a+(b*8+from+0)*matrix_width].weight));
//val =_mm256_fmadd_ps (t1, t2, t3)
t3 = _mm256_mul_ps(t1,t2);
val = _mm256_add_ps (val, t3);
}
t4 = _mm256_load_ps(&(dest.ac[b*8+from+0]));
t4 = _mm256_add_ps(t4,val);
_mm256_store_ps (&(dest.ac[b*8+from+0]), t4);
}
此示例崩溃于:
_mm256_store_ps (&(dest.ac[b*8+from+0]), t4);
但是如果我改成
_mm256_storeu_ps (&(dest.ac[b*8+from+0]), t4);
(我想你是未对齐的)一切都按预期进行。我的问题是:为什么 load 会工作(而如果数据未对齐,它不应该工作)而存储不会。 (此外两者都在同一个地址上运行)。
dest.ac 已使用
分配void *_aligned_calloc(size_t nelem, size_t elsize, size_t alignment=64)
{
size_t max_size = (size_t)-1;
// Watch out for overflow
if(elsize == 0 || nelem >= max_size/elsize)
return NULL;
size_t size = nelem * elsize;
void *memory = _mm_malloc(size+64, alignment);
if(memory != NULL)
memset(memory, 0, size);
return memory;
}
并且它至少有 50 个元素长。 (顺便说一句,在 VS2012 中我有一些随机分配的非法指令,所以我使用 linux。)
提前谢谢你, 阿肯图斯
TL:DR:在优化代码中,
您的示例代码不会自行编译,所以我无法轻松检查 _mm256_load_ps
编译成什么指令。
我用 gcc 4.9 做了一个小实验,它根本没有为 _mm256_load_ps
生成 vmovaps
,因为我只使用加载的结果作为另一个的输入操作说明。它使用内存操作数生成该指令。 AVX 指令对其内存操作数没有对齐要求。 (越过缓存行会影响性能,越过页面边界会影响性能,但您的代码仍然有效。)
另一方面,商店会生成 vmov...
指令。由于您使用了需要对齐的版本,因此它会在未对齐的地址上出错。只需使用未对齐的版本;当地址对齐时它会一样快,而当它不对齐时它仍然可以工作。
我没有仔细检查您的代码以查看是否所有访问都应该对齐。我假设不是,从你措辞的方式来看,只是问为什么你没有因为未对齐的负载而出现故障。就像我说的,可能你的代码没有编译成任何 vmovaps
加载指令,否则即使 "aligned" AVX 加载也不会在未对齐的地址上出错。
你 运行 AVX(没有 AVX2 或 FMA?)在 Sandy/Ivybridge CPU 上吗?我认为这就是为什么您的 FMA 内在函数被注释掉的原因。