我确定之前已经回答过这个问题,但我找不到好的解释。
我正在编写一个图形程序,其中一部分管道正在将体素数据复制到 OpenCL 页锁定(固定)内存。我发现这个复制过程是一个瓶颈,并对简单的 std::copy 的性能进行了一些测量。数据是 float 的,我要复制的每个数据 block 的大小约为 64 MB。
这是我的原始代码,在进行任何基准测试之前:
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 字节的 block 时有一个明显的带宽峰值,带宽比复制整个阵列高得多(15 对 2 GB/s)。
知道这一点后,我决定尝试另一种方法并复制整个数组,但使用对 std::copy 的重复调用,其中每次调用只处理数组的一部分。尝试不同的 block 大小,这些是我的结果:
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 优化没有太大区别。
最佳答案
我很确定您遇到了缓存抖动。如果你用你写的数据填充缓存,下一次需要一些数据,缓存将不得不从内存中读取该数据,但首先它需要在缓存中找到一些空间 - 因为所有数据[或者至少其中的很多]是“脏的”,因为它已经被写入,需要被写入RAM。接下来我们将新的数据写入缓存,这会抛出另一位脏数据(或我们之前读取的数据)。
在汇编程序中,我们可以通过使用“非时间”移动指令来克服这个问题。例如 SSE 指令 movntps。该指令将“避免将内容存储在缓存中”。
编辑:您还可以通过不混合读取和写入来获得更好的性能 - 使用 4-16KB 的小缓冲区 [固定大小数组],并将数据复制到该缓冲区,然后将该缓冲区写入您所在的新位置想要它。同样,理想情况下使用非临时写入,因为即使在这种情况下也会提高吞吐量 - 但仅使用“ block ”读取然后写入,而不是读取一个,写入一个,速度会更快。
像这样:
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++ - 数组大小和复制性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16658139/
我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代
我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby数组,我们在StackOverflow上找到一
我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
我正在尝试在Ruby中制作一个cli应用程序,它接受一个给定的数组,然后将其显示为一个列表,我可以使用箭头键浏览它。我觉得我已经在Ruby中看到一个库已经这样做了,但我记不起它的名字了。我正在尝试对soundcloud2000中的代码进行逆向工程做类似的事情,但他的代码与SoundcloudAPI的使用紧密耦合。我知道cursesgem,我正在考虑更抽象的东西。广告有没有人见过可以做到这一点的库或一些概念证明的Ruby代码可以做到这一点? 最佳答案 我不知道这是否是您正在寻找的,但也许您可以使用我的想法。由于我没有关于您要完成的工作
我使用Ember作为我的前端和GrapeAPI来为我的API提供服务。前端发送类似:{"service"=>{"name"=>"Name","duration"=>"30","user"=>nil,"organization"=>"org","category"=>nil,"description"=>"description","disabled"=>true,"color"=>nil,"availabilities"=>[{"day"=>"Saturday","enabled"=>false,"timeSlots"=>[{"startAt"=>"09:00AM","endAt"=>
我正在尝试按0-9和a-z的顺序创建数字和字母列表。我有一组值value_array=['0','1','2','3','4','5','6','7','8','9','a','b','光盘','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','','u','v','w','x','y','z']和一个组合列表的数组,按顺序,这些数字可以产生x个字符,比方说三个list_array=[]和一个当前字母和数字组合的数组(在将它插入列表数组之前我会把它变成一个字符串,]current_combo['0','0','0']