許 菁,黃 震,韓向清,付 林
(中國船舶集團有限公司第八研究院,南京 211153)
在雷達信號處理或數(shù)據(jù)處理中,當使用PPC的RapidIO進行數(shù)據(jù)傳輸時,通常采用門鈴來實現(xiàn)數(shù)據(jù)傳輸完成后的消息中斷。對于這樣的門鈴中斷函數(shù),需要盡可能快地完成數(shù)據(jù)轉(zhuǎn)移,以避免多次傳輸導致來不及處理的數(shù)據(jù)丟失。一般在進行大量不確定數(shù)量數(shù)據(jù)傳輸時,會在數(shù)據(jù)頭中設計一個字段來描述當次傳輸?shù)臄?shù)量?,F(xiàn)有處理方法會通過內(nèi)存復制函數(shù)(memcpy)將數(shù)據(jù)頭復制一個副本,然后對副本中的長度字段進行讀取。
本文對現(xiàn)有處理方法進行優(yōu)化,以減少使用內(nèi)存復制函數(shù)(memcpy)的應用,提高輸出讀取的效率。
在PowerPC的RapidIO數(shù)據(jù)傳輸時,需要進行內(nèi)存地址映射,讀取傳輸?shù)臄?shù)據(jù)是通過直接訪問內(nèi)存地址實現(xiàn)的。
編譯器實現(xiàn)直接(或間接)地址訪問讀取數(shù)據(jù),可以表達為
MOV AX,[Address]
(1)
而對結(jié)構體的字段訪問表達為
MOV AX,[Address + offset]
(2)
式中,Address為結(jié)構體的首地址;offset為字段相對首地址的偏移量。
采用內(nèi)存復制函數(shù)(memcpy)復制數(shù)據(jù)頭的副本,實際上是對式(1)、跳轉(zhuǎn)語句(jnz)以及計數(shù)器的多次調(diào)用,它主體的匯編表達將如下所示:
10:MOV CX,Count
20:MOVEAX,[Address]
30:MOV [DST],EAX
40:INC Address
(3)
50:INC DST
60:DEC CX
70:JNZ 20
同時,采用內(nèi)存復制函數(shù)(memcpy)還將帶來函數(shù)開銷,如寄存器保存、函數(shù)堆棧等操作,這將涉及ESP、EBP等棧寄存器和EAX、ECX、EDX等調(diào)用者寄存器及EBX、ESI、EDI等被調(diào)用者寄存器的操作和保存。
首先,調(diào)用內(nèi)存復制函數(shù)(memcpy)時,需要先將EAX、ECX、EDX等調(diào)用者寄存器進行保存:
10:PUSH EAX
20:PUSH EBX
30:PUSH ECX
其次,需要將輸入給內(nèi)存復制函數(shù)(memcpy)的參數(shù),入棧后推送給內(nèi)存復制函數(shù)(memcpy):
10:MOV EAX,[Address1]
20:PUSH EAX
30:MOV EAX,[Address2]
40:PUSH EAX
然后,內(nèi)存復制函數(shù)(memcpy)執(zhí)行式(3)所示的函數(shù)主體;
再者,內(nèi)存復制函數(shù)(memcpy)將執(zhí)行結(jié)果入棧:
10:MOV EAX,[Address3]
20:PUSH EAX
最后,調(diào)用函數(shù)將棧中結(jié)果出棧,并還原保存的寄存器:
10:POP EAX
20:MOV[Address4],EAX
30:POP EAX
40:POP EAX
50:PUSH ECX
60:PUSH EBX
70:PUSH EAX
上述開銷將占用大量的CPU時間,對于門鈴響應來說會造成較長時間的延遲,如果在此時間內(nèi)有新的接口操作和門鈴響應,就會造成數(shù)據(jù)的丟失。
從式(1)、(2)的描述可以看出,盡管C語言程序的寫法不一致,但是實際上對內(nèi)存的訪問方法是統(tǒng)一的。因此,只要通過強制類型的轉(zhuǎn)換實現(xiàn)對應數(shù)據(jù)字段的訪問,就可以達到同樣的目的。方法如下式所示:
int datalen=(([datastruct]*)address)->[lenfield]
(4)
式中,[datastruct]為待轉(zhuǎn)換結(jié)構體類型描述字;[datastruct]*為該類型的指針;address為數(shù)據(jù)首地址;[lenfield]為描述數(shù)據(jù)長度的字段名。
式(4)實現(xiàn)了一個地址描述變量到結(jié)構體類型指針的轉(zhuǎn)換以及對結(jié)構體字段的訪問,從表達上看,是一個相對復雜的過程,可能也將占用一定的CPU開銷。但是從編譯器的表達上看,則恰恰相反,由于這個類型指針的轉(zhuǎn)換過程及對結(jié)構體字段的訪問的表達將在編譯階段完成,實際的有效運行指令將極為簡單,示意如下式所示:
10:MOV EAX,[Address + offset]
20:MOV [DST],EAX
(5)
可以看出:對地址描述變量到結(jié)構體類型指針的轉(zhuǎn)換以及對結(jié)構體字段的訪問,通過編譯過程就僅僅表達為首地址和偏移量的表達,兩個過程被濃縮成一條指令,大大減少了實際有效運行指令數(shù),將極大地提高運行效率。
在驗證程序中,設計百萬次同樣操作的循環(huán),分別采用內(nèi)存復制函數(shù)(memcpy)和本文設計方法來讀取一個字段,最終得到的數(shù)據(jù)如表1所示。
表1 運行時間比較
可以看出:本文方法所需的運行時間遠遠優(yōu)于內(nèi)存復制函數(shù)(memcpy),運行效率提高了一個數(shù)量級,將極大節(jié)省CPU的運行開銷,減少門鈴響應函數(shù)的響應時間,降低由于內(nèi)存搬移時間過長而導致新一次數(shù)據(jù)覆蓋上一次有效數(shù)據(jù)的幾率。
本文研究了采用地址描述變量到結(jié)構體類型指針轉(zhuǎn)換以及對結(jié)構體字段訪問替代內(nèi)存復制函數(shù)(memcpy)的方法。經(jīng)試驗測試,該方法可有效提高運行效率,降低數(shù)據(jù)傳輸中數(shù)據(jù)被覆蓋而導致丟失的幾率,可以在基于PowerPC的雷達信號、數(shù)據(jù)處理軟件中推廣,具有一定的實用價值。