gor*_*ill 19 c++ performance sse simd avx
我试图通过SSE和AVX提高复制操作的性能:
#include <immintrin.h>
const int sz = 1024;
float *mas = (float *)_mm_malloc(sz*sizeof(float), 16);
float *tar = (float *)_mm_malloc(sz*sizeof(float), 16);
float a=0;
std::generate(mas, mas+sz, [&](){return ++a;});
const int nn = 1000;//Number of iteration in tester loops
std::chrono::time_point<std::chrono::system_clock> start1, end1, start2, end2, start3, end3;
//std::copy testing
start1 = std::chrono::system_clock::now();
for(int i=0; i<nn; ++i)
std::copy(mas, mas+sz, tar);
end1 = std::chrono::system_clock::now();
float elapsed1 = std::chrono::duration_cast<std::chrono::microseconds>(end1-start1).count();
//SSE-copy testing
start2 = std::chrono::system_clock::now();
for(int i=0; i<nn; ++i)
{
auto _mas = mas;
auto _tar = tar;
for(; _mas!=mas+sz; _mas+=4, _tar+=4)
{
__m128 buffer = _mm_load_ps(_mas);
_mm_store_ps(_tar, buffer);
}
}
end2 = std::chrono::system_clock::now();
float elapsed2 = std::chrono::duration_cast<std::chrono::microseconds>(end2-start2).count();
//AVX-copy testing
start3 = std::chrono::system_clock::now();
for(int i=0; i<nn; ++i)
{
auto _mas = mas;
auto _tar = tar;
for(; _mas!=mas+sz; _mas+=8, _tar+=8)
{
__m256 buffer = _mm256_load_ps(_mas);
_mm256_store_ps(_tar, buffer);
}
}
end3 = std::chrono::system_clock::now();
float elapsed3 = std::chrono::duration_cast<std::chrono::microseconds>(end3-start3).count();
std::cout<<"serial - "<<elapsed1<<", SSE - "<<elapsed2<<", AVX - "<<elapsed3<<"\nSSE gain: "<<elapsed1/elapsed2<<"\nAVX gain: "<<elapsed1/elapsed3;
_mm_free(mas);
_mm_free(tar);
Run Code Online (Sandbox Code Playgroud)
有用.然而,虽然测试器循环中的迭代次数--nn - 增加,但是simd-copy的性能增益降低了:
nn = 10:SSE增益= 3,AVX增益= 6;
nn = 100:SSE增益= 0.75,AVX增益= 1.5;
nn = 1000:SSE增益= 0.55,AVX增益= 1.1;
任何人都可以解释提到性能降低效果的原因是什么,是否可以手动矢量化复制操作?
Ste*_*fan 23
问题在于,您的测试在硬件中迁移一些使基准测试变得困难的因素方面做得很差.为了测试这个,我做了我自己的测试用例.像这样的东西:
for blah blah:
sleep(500ms)
std::copy
sse
axv
Run Code Online (Sandbox Code Playgroud)
输出:
SSE: 1.11753x faster than std::copy
AVX: 1.81342x faster than std::copy
Run Code Online (Sandbox Code Playgroud)
所以在这种情况下,AVX比一堆快std::copy.当我将测试用例改为..时会发生什么
for blah blah:
sleep(500ms)
sse
axv
std::copy
Run Code Online (Sandbox Code Playgroud)
请注意,除了测试的顺序之外,绝对没有任何改变.
SSE: 0.797673x faster than std::copy
AVX: 0.809399x faster than std::copy
Run Code Online (Sandbox Code Playgroud)
哇!怎么可能?CPU需要一段时间才能提升到全速,因此稍后运行的测试具有优势.这个问题现在有3个答案,包括一个"接受"的答案.但只有赞成票数量最少的人才能走上正轨.
这是基准测试很难的原因之一,除非他们已经包含了他们设置的详细信息,否则你永远不应该相信任何人的微基准测试.不只是代码可能出错.省电功能和奇怪的驱动程序可能会完全破坏您的基准.有一次,我通过切换不到1%的笔记本电脑提供的BIOS中的开关来测量性能差异7.
这是一个非常有趣的问题,但我相信到目前为止没有答案是正确的,因为问题本身是如此误导.
标题应更改为"如何达到理论内存I/O带宽?"
无论使用什么指令集,CPU都比RAM快得多,因此纯块存储器复制是100%I/O限制.这就解释了为什么SSE和AVX性能之间几乎没有差别.
对于L1D高速缓存中的小型缓冲区,AVX可以比像Haswell这样的CPU上的SSE复制速度明显快,其中256b加载/存储确实使用256b数据路径到L1D缓存而不是分成两个128b操作.
具有讽刺意味的是,古老的X86指令rep stosq在内存复制方面比SSE和AVX表现更好!
这篇文章解释了如何很好地充分记忆带宽,并且它还有很多参考资料可供进一步探索.
另请参阅SO上的memcpy的增强REP MOVSB,其中@ BeeOnRope的答案讨论了NT存储(以及完成的非RFO存储rep stosb/stosq)与常规存储的关系,以及单核内存带宽通常如何受最大并发/延迟的限制,而不是内存控制器本身.
| 归档时间: |
|
| 查看次数: |
10678 次 |
| 最近记录: |