【发布时间】:2013-08-26 13:10:05
【问题描述】:
任务很简单,将一串整型变量写入内存:
原码:
for (size_t i=0; i<1000*1000*1000; ++i)
{
data[i]=i;
};
并行化代码:
size_t stepsize=len/N;
#pragma omp parallel num_threads(N)
{
int threadIdx=omp_get_thread_num();
size_t istart=stepsize*threadIdx;
size_t iend=threadIdx==N-1?len:istart+stepsize;
#pragma simd
for (size_t i=istart; i<iend; ++i)
x[i]=i;
};
性能糟透了,写1G uint64变量(相当于每秒5GB)需要1.6秒,通过上面代码的简单并行化(open mp parallel),速度提高了一点,但性能仍然很差,在 i7 3970 上使用 4 个线程需要 1.4 秒,使用 6 个线程需要 1.35 秒。
我的设备(i7 3970/64G DDR3-1600)的理论内存带宽是51.2 GB/sec,对于上面的例子,实现的内存带宽只有大约是理论带宽的 1/10,即使应用程序几乎受内存带宽限制。
有人知道如何改进代码吗?
我在 GPU 上编写了很多内存绑定代码,GPU 很容易充分利用 GPU 的设备内存带宽(例如 85% 以上的理论带宽)。
编辑:
代码由 Intel ICC 13.1 编译为 64 位二进制,并启用了最大优化 (O3) 和 AVX 代码路径,以及自动矢量化。
更新:
我尝试了下面的所有代码(感谢 Paul R),没有发生什么特别的事情,我相信编译器完全有能力进行这种 simd/矢量化优化。
至于我为什么要填写那里的数字,长话短说:
它是高性能异构计算算法的一部分,在设备端,该算法效率很高,以至于多GPU集如此之快,以至于我发现性能瓶颈恰好在CPU尝试将多个数字序列写入内存。
当然,知道 CPU 填充数字很糟糕(相比之下,GPU 可以以非常接近的速度填充数字序列(238GB/秒 288GB/秒 strong> GK110 与可怜的 5GB/sec(CPU 上 51.2GB/sec)到 GPU 全局内存的理论带宽),我可以稍微改变我的算法,但让我想知道的是为什么 CPU 在这里填充数字序列时如此糟糕。
至于我的设备的内存带宽,我认为带宽(51.2GB)是正确的,根据我的memcpy()测试,实现的带宽约为理论带宽的80%+ (>40GB/秒)。
【问题讨论】:
-
您是否尝试过优化代码?例如。如果您使用的是
gcc,请使用-O3? -
@unwind Mohammed 这就是编译器所做的事情。如果汇编代码表明编译器在这方面做得不好,那很好,但是在 dubio pro 编译器中 ;-) OP,你能显示生成的汇编吗?
-
@delnan 很有可能。是时候打电话给神秘人了~
-
房间里的大象当然是:为什么你(认为你)需要用递增的整数序列填充内存?!
-
你从哪里得到理论带宽?
标签: c++ c memory optimization