如何在保存现有数据和使用与CPU寄存器大小匹配的缓冲区的情况下,将内存中的一些字节从一个位置移动到另一个位置?
更精确的公式:
我正在用FreePascal编写一些代码(为了好玩)。现在我需要一个函数,它能把一些字节移到另一个地方。内置函数系统。移动这样做很粗鲁-当移动和重写数据时,它不关心在目标地址中保存数据。当然,我可以使用缓冲区来保存数据,然后使用移动函数从缓冲区恢复数据。但是当移动大量数据时,需要很大的缓冲区。我想避免它,并使用与CPU寄存器大小匹配的缓冲区。在
我需要的例子是假设我们总是从较低的位置移动到较高的位置(Pos1<;Pos2)。 将3个字节从位置2移到位置7:
我可以使用字节大小的缓冲区(→表示写入,↔ 平均交换值):
7 → Buffer
2 → 7
Buffer ↔ 4
Buffer ↔ 9
Buffer ↔ 6
Buffer ↔ 3
Buffer ↔ 8
Buffer ↔ 5
Buffer ↔ 2
更大的例子:将3个字节从位置3移到位置15
现在的算法如下所示:
^{pr2}$在前面的例子中有一个大步骤-我们使用一个操作序列移动所有的步骤,但是这里有3个大步骤。在
以我不理解的方式——这样大的步骤的数量似乎等于(Pos2-Pos1)的GCD(最大公约数)和长度。在
我编写了一些python代码,似乎为给定的移动请求提供了正确的操作序列
# -*- coding: utf-8 -*-
def func1(Pos1, Pos2, Length):
Delta = Pos2 - Pos1;
j = Pos2;
p1 = Pos1;
p2 = Pos2;
Step = 0;
SubStep = 0;
while (Step < Delta + Length):
Step = Step + 1;
SubStep = SubStep + 1;
print(" %d → Buffer"%j);
print(" %d → %d"%(p1,j));
while 1:
Step = Step + 1;
if (j + Delta < Pos2 + Length):
j = j + Delta;
else:
j = j - Length;
print(" Buffer ↔ %d"%(j));
if (j == p1):
p1 = p1 + 1;
p2 = p2 + 1;
j = p2;
break;
return SubStep;
假设这是正确的,有一个巨大的问题——这个算法处理的字节操作速度很慢,而且由于我有amd64——我想让它在每次操作中使用8字节。在
我要怎么做?在
我自己的问题中所描述的问题似乎可以用两种简单的方法来解决(看问题图片):
1)你有橙色和绿色的块,你需要交换它们-把橙色块放在缓冲区(因为它比较小),移动绿色块,然后他们从缓冲区取橙色块。在
取舍:简单,明显,快速和小的块
问题:如果橙色和绿色块的大小相同-您将需要最大的缓冲区,并且可能需要大量内存
2)使用方法。您将能够使用不大于两个块大小(橙色和绿色)的GCD的缓冲区。所以,最好使用两个缓冲区:一个是CPU寄存器大小(我的amd64是8个字节)和一个字节大小的缓冲区。因此,首先使用(GCD div 8)(对于64位系统)步骤移动(或移位)寄存器大小的缓冲区,然后用字节大小的缓冲区结束。在
权衡:不需要大缓冲
问题:如果两个块大小的GCD小于寄存器大小-我们会变得非常慢(因为在这种情况下只有字节大小的移位操作可用)。一点也不明显。在
我做了两个函数来测试这两个解决方案
对于测试,我创建了一个缓冲区,将下半部分移动到上半部分(交换缓冲区数据的一半)-这是解决方案1的最坏情况。在
我用相同的缓冲区大小重复每个移动测试以得到平均结果。在
所以我从512字节的缓冲区开始,将256字节从0位移到256位,重复移动1048576次,然后使缓冲区变大2倍,减少重复2次,…,以536870912字节的缓冲区结束,只重复1次(总共21次大的迭代)
这样可以获得良好的GCD(GCD>;寄存器大小)。为了模拟解决方案2的最坏情况,当(GCD=1)时,我只将移动长度减少1,所以在第一次迭代中,它将255个字节从位置0移动到位置256。在
我很失望-我最喜欢的解决方案2的自写函数很慢,即使使用(GCD>;8),当(GCD=1)时,它也非常慢。在
Fig. 1 此图显示结果。OX-缓冲区大小,OY-时间(更少=更好)。实心黑圆圈和粗线-解决方案1。底部白色圆圈和细线是GCD良好(GCD>;8,最佳情况)的解决方案2,顶行-GCD差(GCD=1,最坏情况)。灰色填充-解决方案2的中间部分。在
说明:解决方案1使用汇编程序中由专业程序员编写的“Move”函数,以性能取胜很难。在
几周后,我发现编译器并没有给出最佳的汇编代码。通过一些额外的优化(-O3-或)结果会变得更好一些 Fig. 2
结论: 我已经测试了这两个函数,得到了相同的结果,但当我做那个图形时却没有,所以它可能都是错误的。在
当你移动的内存块很小时,解决方案1似乎很好。但是它有一些瓶颈,并且不是很线性(因此很难预测执行时间)。在
当您被限制分配更多内存时,解决方案2似乎适合移动大量内存。它是一个非常线性的,并且可以通过执行时间来预测。但可能非常慢。在
相关问题 更多 >
编程相关推荐