数组大小和复制性能
Array size and copy performance
我相信这个问题以前已经有答案了,但我找不到一个好的解释。
我正在写一个图形程序,其中一部分管道将体素数据复制到OpenCL页面锁定(固定)内存。我发现这个复制过程是一个瓶颈,并对一个简单的std::copy
的性能进行了一些测量。数据是浮动的,我想复制的每个数据块的大小都在64mb左右。
这是我的原始代码,在任何基准测试之前:
std::copy(data, data+numVoxels, pinnedPointer_[_index]);
其中data
是浮点指针,numVoxels
是无符号整型,pinnedPointer_[_index]
是引用固定OpenCL缓冲区的浮点指针。
由于我得到了较慢的性能,我决定尝试复制较小的数据部分,而不是看看我得到了什么样的带宽。我使用boost::cpu_timer来计时。我试着运行了一段时间,平均运行了几百次,得到了类似的结果。下面是相关代码和结果:
boost::timer::cpu_timer t;
unsigned int testNum = numVoxels;
while (testNum > 2) {
t.start();
std::copy(data, data+testNum, pinnedPointer_[_index]);
t.stop();
boost::timer::cpu_times result = t.elapsed();
double time = (double)result.wall / 1.0e9 ;
int size = testNum*sizeof(float);
double GB = (double)size / 1073741842.0;
// Print results
testNum /= 2;
}
Copied 67108864 bytes in 0.032683s, 1.912315 GB/s
Copied 33554432 bytes in 0.017193s, 1.817568 GB/s
Copied 16777216 bytes in 0.008586s, 1.819749 GB/s
Copied 8388608 bytes in 0.004227s, 1.848218 GB/s
Copied 4194304 bytes in 0.001886s, 2.071705 GB/s
Copied 2097152 bytes in 0.000819s, 2.383543 GB/s
Copied 1048576 bytes in 0.000290s, 3.366923 GB/s
Copied 524288 bytes in 0.000063s, 7.776913 GB/s
Copied 262144 bytes in 0.000016s, 15.741867 GB/s
Copied 131072 bytes in 0.000008s, 15.213149 GB/s
Copied 65536 bytes in 0.000004s, 14.374742 GB/s
Copied 32768 bytes in 0.000003s, 10.209962 GB/s
Copied 16384 bytes in 0.000001s, 10.344942 GB/s
Copied 8192 bytes in 0.000001s, 6.476566 GB/s
Copied 4096 bytes in 0.000001s, 4.999603 GB/s
Copied 2048 bytes in 0.000001s, 1.592111 GB/s
Copied 1024 bytes in 0.000001s, 1.600125 GB/s
Copied 512 bytes in 0.000001s, 0.843960 GB/s
Copied 256 bytes in 0.000001s, 0.210990 GB/s
Copied 128 bytes in 0.000001s, 0.098439 GB/s
Copied 64 bytes in 0.000001s, 0.049795 GB/s
Copied 32 bytes in 0.000001s, 0.049837 GB/s
Copied 16 bytes in 0.000001s, 0.023728 GB/s
在复制65536-262144字节的块时有一个明显的带宽峰值,并且带宽比复制整个数组(15 vs 2 GB/s)要高得多。
知道这一点,我决定尝试另一件事并复制整个数组,但使用重复调用std::copy
,其中每个调用只处理数组的一部分。尝试不同的块大小,这些是我的结果:
unsigned int testNum = numVoxels;
unsigned int parts = 1;
while (sizeof(float)*testNum > 256) {
t.start();
for (unsigned int i=0; i<parts; ++i) {
std::copy(data+i*testNum,
data+(i+1)*testNum,
pinnedPointer_[_index]+i*testNum);
}
t.stop();
boost::timer::cpu_times result = t.elapsed();
double time = (double)result.wall / 1.0e9;
int size = testNum*sizeof(float);
double GB = parts*(double)size / 1073741824.0;
// Print results
parts *= 2;
testNum /= 2;
}
Part size 67108864 bytes, copied 0.0625 GB in 0.0331298s, 1.88652 GB/s
Part size 33554432 bytes, copied 0.0625 GB in 0.0339876s, 1.83891 GB/s
Part size 16777216 bytes, copied 0.0625 GB in 0.0342558s, 1.82451 GB/s
Part size 8388608 bytes, copied 0.0625 GB in 0.0334264s, 1.86978 GB/s
Part size 4194304 bytes, copied 0.0625 GB in 0.0287896s, 2.17092 GB/s
Part size 2097152 bytes, copied 0.0625 GB in 0.0289941s, 2.15561 GB/s
Part size 1048576 bytes, copied 0.0625 GB in 0.0240215s, 2.60184 GB/s
Part size 524288 bytes, copied 0.0625 GB in 0.0184499s, 3.38756 GB/s
Part size 262144 bytes, copied 0.0625 GB in 0.0186002s, 3.36018 GB/s
Part size 131072 bytes, copied 0.0625 GB in 0.0185958s, 3.36097 GB/s
Part size 65536 bytes, copied 0.0625 GB in 0.0185735s, 3.365 GB/s
Part size 32768 bytes, copied 0.0625 GB in 0.0186523s, 3.35079 GB/s
Part size 16384 bytes, copied 0.0625 GB in 0.0187756s, 3.32879 GB/s
Part size 8192 bytes, copied 0.0625 GB in 0.0182212s, 3.43007 GB/s
Part size 4096 bytes, copied 0.0625 GB in 0.01825s, 3.42465 GB/s
Part size 2048 bytes, copied 0.0625 GB in 0.0181881s, 3.43631 GB/s
Part size 1024 bytes, copied 0.0625 GB in 0.0180842s, 3.45605 GB/s
Part size 512 bytes, copied 0.0625 GB in 0.0186669s, 3.34817 GB/s
似乎减少块大小实际上有显着的效果,但我仍然无法达到接近15 GB/s。
我运行的是64位Ubuntu, GCC优化没有太大区别。
- 为什么数组大小会以这种方式影响带宽? OpenCL固定内存起作用吗?
- 优化大型数组副本的策略是什么?
我很确定您正在遇到缓存抖动。如果你用你写的数据填满了缓存,下一次,需要一些数据,缓存将不得不从内存中读取这些数据,但首先它需要在缓存中找到一些空间——因为所有的数据(或至少很多数据)都是"脏的",因为它已经被写入,它需要被写到RAM中。接下来,我们向缓存中写入一个新数据位,这将抛出另一个脏数据位(或者我们之前读到的数据位)。
在汇编语言中,我们可以通过使用"非时态"move指令来克服这个问题。SSE指令movntps
为例。这条指令将"避免在缓存中存储东西"。编辑:你也可以通过不混合读和写得到更好的性能-使用一个小的缓冲区[固定大小的数组]说4-16KB,并复制数据到该缓冲区,然后写入该缓冲区到你想要它的新地方。同样,理想情况下使用非时态写,因为即使在这种情况下,这也会提高吞吐量——但是仅仅使用"块"来读然后写,而不是读一个,写一个,会快得多。
像这样:
float temp[2048];
int left_to_do = numVoxels;
int offset = 0;
while(left_to_do)
{
int block = min(left_to_do, sizeof(temp)/sizeof(temp[0]);
std::copy(data+offset, data+offset+block, temp);
std::copy(temp, temp+block, pinnedPointer_[_index+offet]);
offset += block;
left_to_do -= block;
}
试一试,看看它是否能改善情况。它可能不会……
Edit2:我应该解释一下,这是更快的,因为你重用相同的缓存位加载数据到每次,通过不混合读取和写入,我们得到更好的性能从内存本身
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 使用strcpy将char数组的元素复制到另一个数组
- 是否可以初始化不可复制类型的成员变量(或基类)
- OpenMP阵列性能较差
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 复制列表初始化的隐式转换的等级是多少
- 通过默认复制构造函数比较 C++ 字符串是否会影响性能,原因为何?
- 自定义类中的移动与复制性能
- 复制 CTOR 与赋值运算符以初始化对象(性能)
- C++将 2D 阵列的一部分复制到另一个 2D 阵列,性能
- 对于阵列复制,const&的性能更好吗?
- 在将 char 数组复制到字符串期间节省 CPU 周期(提高性能)
- std::copy 和容器的复制构造函数之间是否存在任何性能差异?
- 矢量排序/唯一/擦除与复制到无序集的性能
- 使用fread/fwrite将文件复制到USB的性能
- 数组大小和复制性能
- 指针函数参数在C++中的复制和性能