gpt4 book ai didi

c++ - 将整数序列写入全局内存的快速(est)方法?

转载 作者:IT王子 更新时间:2023-10-28 23:32:32 26 4
gpt4 key购买 nike

任务很简单,将一串整型变量写入内存:

原码:

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;
};

性能很糟糕,通过简单的并行化(open mp parallel ) 上面的代码,速度有一点提升,但性能还是很差,在 i7 3970 上用 4 个线程耗时 1.4 秒,用 6 个线程耗时 1.35。

我的设备(i7 3970/64G DDR3-1600)的理论内存带宽是51.2 GB/sec,对于上面的例子,实现的内存带宽只有大约是理论带宽的 1/10,即使应用程序几乎受内存带宽限制。

有人知道如何改进代码吗?

我在 GPU 上编写了很多内存绑定(bind)代码,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/sec)。

最佳答案

假设这是 x86,并且您的可用 DRAM 带宽尚未饱和,您可以尝试使用 SSE2 或 AVX2 一次写入 2 或 4 个元素:

SSE2:

#include "emmintrin.h"

const __m128i v2 = _mm_set1_epi64x(2);
__m128i v = _mm_set_epi64x(1, 0);

for (size_t i=0; i<1000*1000*1000; i += 2)
{
_mm_stream_si128((__m128i *)&data[i], v);
v = _mm_add_epi64(v, v2);
}

AVX2:

#include "immintrin.h"

const __m256i v4 = _mm256_set1_epi64x(4);
__m256i v = _mm256_set_epi64x(3, 2, 1, 0);

for (size_t i=0; i<1000*1000*1000; i += 4)
{
_mm256_stream_si256((__m256i *)&data[i], v);
v = _mm256_add_epi64(v, v4);
}

请注意,data 需要适当对齐(16 字节或 32 字节边界)。

AVX2 仅适用于 Intel Haswell 及更高版本,但 SSE2 近来非常普遍。


FWIW 我将一个带有标量循环的测试工具放在一起,上面的 SSE 和 AVX 循环用 clang 编译它,并在 Haswell MacBook Air (1600MHz LPDDR3 DRAM) 上对其进行了测试。我得到了以下结果:

# sequence_scalar: t = 0.870903 s = 8.76033 GB / s
# sequence_SSE: t = 0.429768 s = 17.7524 GB / s
# sequence_AVX: t = 0.431182 s = 17.6941 GB / s

我还在一台具有 3.6 GHz Haswell 的 Linux 台式电脑上进行了尝试,使用 gcc 4.7.2 进行编译,得到以下结果:

# sequence_scalar: t = 0.816692 s = 9.34183 GB / s
# sequence_SSE: t = 0.39286 s = 19.4201 GB / s
# sequence_AVX: t = 0.392545 s = 19.4357 GB / s

所以看起来 SIMD 实现比 64 位标量代码提高了 2 倍或更多(尽管 256 位 SIMD 似乎没有比 128 位 SIMD 带来任何改进),并且典型的吞吐量应该比 64 位标量代码快得多5 GB/秒。

我的猜测是 OP 的系统或基准测试代码有问题,导致吞吐量明显降低。

关于c++ - 将整数序列写入全局内存的快速(est)方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18403568/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com