達夫設備是一個很棒的迂回循環展開法,是由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的原理,看看他是怎么實現加速的。