Optimization 用于x86和+;1档(用于移动到前变换)

Optimization 用于x86和+;1档(用于移动到前变换),optimization,low-level,bzip2,archiving,memmove,Optimization,Low Level,Bzip2,Archiving,Memmove,对于fast MTF(),我需要将字符从数组内部移动到数组前面的更快版本: char mtfSymbol[256], front; char i; for(;;) { \\ a very big loop ... i=get_i(); \\ i is in 0..256 but more likely to be smaller. front=mtfSymbol[i]; memmove(mtfSymbol+1, mtfSymbol, i); mtf

对于fast MTF(),我需要将字符从数组内部移动到数组前面的更快版本:

char mtfSymbol[256], front;
char i;

for(;;) { \\ a very big loop 
    ... 
    i=get_i(); \\ i is in 0..256 but more likely to be smaller.

    front=mtfSymbol[i];
    memmove(mtfSymbol+1, mtfSymbol, i);
    mtfSymbol[0]=front;
}
cachegrind显示,对于memmove,这里存在很多分支预测失误

对于其他版本的代码(在第一个示例中不是memmove,而是这个)

存在大量字节读/写、条件分支和分支预测失误

我不是很大,因为它是用于“良好”输入的MTF——BWT(Burrows–Wheeler变换)后的文本文件


编译器是gcc.

如果你预先分配的缓冲区比你需要的要大,把你的初始数组放在中间(或者在最后,如果你永远不需要这样扩展),那么你可以追加项(达到极限)。通过更改数组开头的地址,而不是移动所有元素


显然,您需要跟踪您移动的距离,这样,如果您确实从现有分配的开始位置跌落,您可以重新分配,但这应该比移动所有数组项更快。

您还可以使用专用数据结构而不是数组来加速前向转换。 可以使用链表列表构建快速实现,以避免数组元素完全移动


对于逆变换,结果表明数组与链表一样快。

有任何理由相信提供的
memmove
可以改进吗?不知道你所说的MTF或BWT是什么意思,你能避免做这些动作吗?@David Thornley,这是一个移动的有限案例。最常见的是移动256阵列的一小部分。位移是固定的,且为a+1。此外,此代码是热点,因为它对5 GByte文件中的每个字符都完全运行。感谢您的澄清。MTF通常在符号以时间一致的方式出现时应用,因此无论输入是什么,输出都将是“小”值(否则,使用MTF没有意义)。这意味着大多数时候,一个非常接近开始的元素需要移动到前面。您应该能够对前4-8个位置的特殊情况进行硬编码,这些位置基本上旋转寄存器并将结果位模式写回。使用standard
memmove
,其余的都很好,因为很难做得更好,而且这种情况也不会经常发生。Damon,你的评论是最好的答案。请给我一个答案,这样我就可以投票了!你知道MTF吗?i小于256,所以数组中有一部分要移动,第i个元素将移动到前面,第i个元素之后的长部分必须保持在原位。那么你的建议会在osgx:军事处理设施上产生“洞”吗?手动变速器油?接下来还有什么?最有可能看起来像微软的磁带格式,但也有其他的可能性。至少BWT不会导致维基百科的消歧页面。@大卫·索恩利,很抱歉,这是“移到前面”转换,用于归档程序,例如bzip2+1,即使这不能满足OP的需要。尽管如此,对于一般的“在数组前面插入”问题,这通常仍然是一种很好的方法(如果您以前没有听说过的话,也没有人们想象的那么明显!)。如果我没记错的话,
deque
的一些实现曾经是这样工作的。这是一个学术上正确的解决方案,但我怀疑它在实际代码中是否表现良好(可能在Java中,但在C++中肯定不是)。尽管算法复杂度更好,但除了非常大的对象,列表比向量(或原始数组)慢3-4倍。此外,当使用MTF时,只有频繁出现字符时,这才有意义,也就是说,移动的距离通常很短。因此,专门用于短动作的自定义
memmove
将表现良好。我同意整体评论。但是,Java无法直接访问优化(低级)指令,因此列表是最快的选项(至少在Intel CPU上)。我对其他语言没有这样的要求。由于MTF通常在BWT之后使用,因此大多数字符的索引较低是很常见的。“通常在BWT之后使用,大多数字符的索引较低是很常见的”是的,这就是我要说的:-)在这样的上下文中使用MTF也是有意义的。但是,需要移动的内存量必然很小(通常为3-5个字节,很少达到8-10个字节),因此专门的
mmove
将非常快。在一个列表中操作两个指针的开销更高,这不包括使用数据时较慢的总体访问和缓存影响。Java虚拟机无疑隐藏了这一事实(如您的示例中所示),但OP的问题是关于C的。换言之,Java很好地展示了学术上正确的解决方案,但它实际上无助于在C中找到高性能的解决方案(因为Java是一个完全不知道CPU如何工作或内存如何工作的虚拟机,因此在Java中,一切都一样慢)。实际上,如果想要性能,使用列表几乎总是错误的解决方案,即使它看起来是正确的解决方案(甚至是“自然”有趣的基准:你是对的,最初的请求是关于C的,在这种情况下,向量应该是比列表更好的解决方案。
do
{
   mtfSymbol[i] = mtfSymbol[i-1];
} while ( --i );