2016-12-01 69 views
10

简短的问题是,如果我有一个函数需要两个向量。一个是输入,另一个是输出(没有别名)。我只能对其中一个,我应该选择哪一个?未对齐的负载与未对齐的存储

较长的版本是,考虑功能,

void func(size_t n, void *in, void *out) 
{ 
    __m256i *in256 = reinterpret_cast<__m256i *>(in); 
    __m256i *out256 = reinterpret_cast<__m256i *>(out); 
    while (n >= 32) { 
     __m256i data = _mm256_loadu_si256(in256++); 
     // process data 
     _mm256_storeu_si256(out256++, data); 
     n -= 32; 
    } 
    // process the remaining n % 32 bytes; 
} 

如果inout排列了32个字节,那么就没有使用vmovdqu代替vmovdqa的处罚。最糟糕的情况是两者都未对齐,四分之一的加载/存储将跨越缓存线边界。

在这种情况下,我可以通过在进入循环之前首先处理几个元素来将它们中的一个与高速缓存行边界对齐。但是,问题是我应该选择哪一个?未对齐的加载和存储之间,哪一个更糟?

+3

看看一些memcpy的实现;我认为这有一个通常的方式,但我忘记了它是什么。虽然也许这取决于你在做什么。对齐的加载将避免缓存行边界,所以没有加载使用延迟惩罚(如果指针增量是可预测的,则不太相关,因为OOO可以使加载地址远远超出余下的循环)。由于在对象外部读取通常是安全的,但是写入不是,如果可以避免清理循环的完整标量版本,那么这可能会影响决策。 –

+0

我对此进行了一些测试,并确定至少在我测试过的处理器(Pentium 4,Core 2,Sandy Bridge和Haswell)上,对齐输入向量明显快于对齐输出向量。你的旅费可能会改变。我不愿意将此作为答案发布,因为我不再有测试代码,不想再次编写测试代码并再次运行测试,也没有官方参考指向任何类型的文档。所以有一个upvote代替! :-) –

+0

@CodyGray无论如何感谢。我一直在研究这个问题的一些测试。到目前为止,我可以告诉的只是“它取决于” –

回答

0

冒着风险说明这里显而易见:除了“你需要用实际代码和实际数据进行基准测试”之外,没有“正确的答案”。无论哪种变体速度更快取决于您使用的CPU,您在每个软件包上执行的计算量以及其他许多事情。

正如评论中指出的那样,您还应该尝试非临时商店。什么有时也可以帮助加载电流回路内的下列数据包的输入,即:

__m256i next = _mm256_loadu_si256(in256++); 
for(...){ 
    __m256i data = next; // usually 0 cost 
    next = _mm256_loadu_si256(in256++); 
    // do computations and store data 
} 

如果你正在做的计算有不可避免的数据延迟,你也应该考虑计算两个包交错(尽管使用了两倍的寄存器)。