达夫设备是一个很棒的迂回循环展开法,是由Tom Duff在Lucasfilm时所设计的。它的传统的形态是用来复制多个字节的:
register n = (count + 7) / 8; /* count > 0 assumed */ switch (count % 8) { case 0: do { *to = *from++; case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; } while (--n > 0); }
咋一看,XXX这是什么东西,怎么这么乱,看不懂。这代码的也太难懂了,好吧,既然他这么有名,咱们还是勉强看一看吧。
先看一遍解释:代码的本意是将count个字节从from指向的数组复制到to指向的内存地址(这是个内存映射的输出寄存器,这也是为什么它没有被增加)。他把switch语句和复制八个字节的循环交织在一起,从而解决了剩余字节的处理问题(当count不是8的整数倍时).
既然是复制那么我们就来写一个复制的程序:来看一下这个程序的耗时:
然后我们使用上面的duff device来改写这个程序。如下:
可是这个程序并不能正常的运行,只有第一个位置a[0]的值变成了B剩下所有的仍然是A,这是怎么回事,难道是程序错了????好吧,暂且以我们180的智商认为是程序错了,再看一眼程序,为什么*to = *from ++
中*to的位置永远不变,那不是每一次都是复制给a[0]这个位置了么,这怎么行?好,咱们来改一改。
运行结果没问题。咱们来看一下运行时间。
还真是提速不少,再来看看速度这么快是不是所有的内容都复制到了,,没有缺斤少两,确实是100000个字符。
这么看来duff device确实能够增快循环的运行速度,再回头理解一下代码的本意是将count个字节从from指向的数组复制到to指向的内存地址(这是个内存映射的输出寄存器,这也是为什么它没有被增加)。
这段话的意思,为什么之前to指向的是一个固定的位置????
找了一圈duff device相关的资料也没有找到这段话的解释,那我们就先来了解一下 "内存映射的输出寄存" 是个什么东西。"映射设备寄存器到内存"找到这么一篇博客,那么我猜就不是那个源程序有问题,to指向的地址应该是一个设备寄存器的地址,那么它的地址就是固定不变的了,循环的往这个寄存器的这个地址中写入数据。
稍后再来理解duff device的原理,看看他是怎么实现加速的。