




版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第第頁(yè)兼顧內(nèi)存和速度的C語(yǔ)言代碼優(yōu)化的方法在本篇文章中,我(指原)收集了很多經(jīng)驗(yàn)和方法。應(yīng)用這些經(jīng)驗(yàn)和方法,可以幫助我們從執(zhí)行速度和內(nèi)存使用等方面來(lái)優(yōu)化(C語(yǔ)言)代碼。
簡(jiǎn)介
在最近的一個(gè)項(xiàng)目中,我們需要開(kāi)發(fā)一個(gè)運(yùn)行在移動(dòng)設(shè)備上但不保證圖像高質(zhì)量的輕量級(jí)JPEG庫(kù)。期間,我總結(jié)了一些讓程序運(yùn)行更快的方法。在本篇文章中,我收集了一些經(jīng)驗(yàn)和方法。
應(yīng)用這些經(jīng)驗(yàn)和方法,可以幫助我們從執(zhí)行速度和內(nèi)存使用等方面來(lái)優(yōu)化C語(yǔ)言代碼。
盡管在C代碼優(yōu)化方面有很多的指南,但是關(guān)于編譯和你使用的(編程)機(jī)器方面的優(yōu)化知識(shí)卻很少。
通常,為了讓你的程序運(yùn)行的更快,程序的代碼量可能需要增加。代碼量的增加又可能會(huì)對(duì)程序的復(fù)雜度和可讀性帶來(lái)不利的影響。這對(duì)于在(手機(jī))、PDA等對(duì)于內(nèi)存使用有很多限制的小型設(shè)備上編寫(xiě)程序時(shí)是不被允許的。
因此,在代碼優(yōu)化時(shí),我們的座右銘應(yīng)該是確保內(nèi)存使用和執(zhí)行速度兩方面都得到優(yōu)化。
聲明
實(shí)際上,在我的項(xiàng)目中,我使用了很多優(yōu)化(ARM)編程的方法(該項(xiàng)目是基于ARM平臺(tái)的),也使用了很多互聯(lián)網(wǎng)上面的方法。但并不是所有文章提到的方法都能起到很好的作用。所以,我對(duì)有用的和高效的方法進(jìn)行了總結(jié)收集。同時(shí),我還修改了其中的一些方法,使他們適用于所有的編程環(huán)境,而不是局限于ARM環(huán)境。
哪里需要使用這些方法?
沒(méi)有這一點(diǎn),所有的討論都無(wú)從談起。程序優(yōu)化最重要的就是找出待優(yōu)化的地方,也就是找出程序的哪些部分或者哪些模塊運(yùn)行緩慢亦或消耗大量的內(nèi)存。只有程序的各部分經(jīng)過(guò)了優(yōu)化,程序才能執(zhí)行的更快。
程序中運(yùn)行最多的部分,特別是那些被程序內(nèi)部循環(huán)重復(fù)調(diào)用的方法最該被優(yōu)化。
對(duì)于一個(gè)有經(jīng)驗(yàn)的碼農(nóng),發(fā)現(xiàn)程序中最需要被優(yōu)化的部分往往很簡(jiǎn)單。此外,還有很多工具可以幫助我們找出需要優(yōu)化的部分。我使用過(guò)Visual(C++)內(nèi)置的性能工具profiler來(lái)找出程序中消耗最多內(nèi)存的地方。
另一個(gè)我使用過(guò)的工具是(英特爾)的Vtune,它也能很好的(檢測(cè))出程序中運(yùn)行最慢的部分。根據(jù)我的經(jīng)驗(yàn),內(nèi)部或嵌套循環(huán),調(diào)用第三方庫(kù)的方法通常是導(dǎo)致程序運(yùn)行緩慢的最主要的起因。
整形數(shù)
如果我們確定整數(shù)非負(fù),就應(yīng)該使用unsignedint而不是int。有些(處理器)處理無(wú)符號(hào)unsigned整形數(shù)的效率遠(yuǎn)遠(yuǎn)高于有符號(hào)signed整形數(shù)(這是一種很好的做法,也有利于代碼具體類(lèi)型的自解釋)。
因此,在一個(gè)緊密循環(huán)中,聲明一個(gè)int整形變量的最好方法是:
記住,整形in的運(yùn)算速度高浮點(diǎn)型float,并且可以被處理器直接完成運(yùn)算,而不需要借助于FPU(浮點(diǎn)運(yùn)算單元)或者浮點(diǎn)型運(yùn)算庫(kù)。
盡管這不保證編譯器一定會(huì)使用到(寄存器)存儲(chǔ)變量,也不能保證處理器處理能更高效處理unsigned整型,但這對(duì)于所有的編譯器是通用的。
例如在一個(gè)計(jì)算包中,如果需要結(jié)果精確到小數(shù)點(diǎn)后兩位,我們可以將其乘以100,然后盡可能晚的把它轉(zhuǎn)換為浮點(diǎn)型數(shù)字。
除法和取余數(shù)
在標(biāo)準(zhǔn)處理器中,對(duì)于分子和分母,一個(gè)32位的除法需要使用20至140次循環(huán)操作。除法函數(shù)消耗的時(shí)間包括一個(gè)常量時(shí)間加上每一位除法消耗的時(shí)間。
對(duì)于ARM處理器,這個(gè)版本需要20+4.3N次循環(huán)。這是一個(gè)消耗很大的操作,應(yīng)該盡可能的避免執(zhí)行。有時(shí),可以通過(guò)乘法表達(dá)式來(lái)替代除法。
例如,假如我們知道b是正數(shù)并且b*c是個(gè)整數(shù),那么(a/b)>c可以改寫(xiě)為a>(c*b)。如果確定操作數(shù)是無(wú)符號(hào)unsigned的,使用無(wú)符號(hào)unsigned除法更好一些,因?yàn)樗扔蟹?hào)signed除法效率高。
合并除法和取余數(shù)
在一些場(chǎng)景中,同時(shí)需要除法(x/y)和取余數(shù)(x%y)操作。這種情況下,編譯器可以通過(guò)調(diào)用一次除法操作返回除法的結(jié)果和余數(shù)。如果既需要除法的結(jié)果又需要余數(shù),我們可以將它們寫(xiě)在一起,如下所示:
通過(guò)2的冪次進(jìn)行除法和取余數(shù)
如果除法中的除數(shù)是2的冪次,我們可以更好的優(yōu)化除法。編譯器使用移位操作來(lái)執(zhí)行除法。因此,我們需要盡可能的設(shè)置除數(shù)為2的冪次(例如64而不是66)。并且依然記住,無(wú)符號(hào)unsigned整數(shù)除法執(zhí)行效率高于有符號(hào)signed整形出發(fā)。
上面兩種除法都避免直接調(diào)用除法函數(shù),并且無(wú)符號(hào)unsigned的除法使用更少的計(jì)算機(jī)指令。由于需要移位到0和負(fù)數(shù),有符號(hào)signed的除法需要更多的時(shí)間執(zhí)行。
取模的一種替代方法
我們使用取余數(shù)操作符來(lái)提供算數(shù)取模。但有時(shí)可以結(jié)合使用if語(yǔ)句進(jìn)行取模操作??紤]如下兩個(gè)例子:
優(yōu)先使用if語(yǔ)句,而不是取余數(shù)運(yùn)算符,因?yàn)閕f語(yǔ)句的執(zhí)行速度更快。這里注意新版本函數(shù)只有在我們知道輸入的count結(jié)余0至59時(shí)在能正確的工作。
使用數(shù)組下標(biāo)
如果你想給一個(gè)變量設(shè)置一個(gè)代表某種意思的字符值,你可能會(huì)這樣做:
或者這樣做:
一種更簡(jiǎn)潔、更快的方法是使用數(shù)組下標(biāo)獲取字符數(shù)組的值。如下:
全局變量
全局變量絕不會(huì)位于寄存器中。使用指針或者函數(shù)調(diào)用,可以直接修改全局變量的值。因此,編譯器不能將全局變量的值緩存在寄存器中,但這在使用全局變量時(shí)便需要額外的(常常是不必要的)讀取和存儲(chǔ)。所以,在重要的循環(huán)中我們不建議使用全局變量。
如果函數(shù)過(guò)多的使用全局變量,比較好的做法是拷貝全局變量的值到局部變量,這樣它才可以存放在寄存器。這種方法僅僅適用于全局變量不會(huì)被我們調(diào)用的任意函數(shù)使用。例子如下:
注意,(te)st1必須在每次增加操作時(shí)加載并存儲(chǔ)全局變量er(rs)的值,而test2存儲(chǔ)localerrs于寄存器并且只需要一個(gè)計(jì)算機(jī)指令。
使用別名
考慮如下的例子:
盡管*data的值可能從未被改變,但編譯器并不知道anyfunc函數(shù)不會(huì)修改它,所以程序必須在每次使用它的時(shí)候從內(nèi)存中讀取它。如果我們知道變量的值不會(huì)被改變,那么就應(yīng)該使用如下的編碼:
這為編譯器優(yōu)化代碼提供了條件。
變量的生命周期分割
由于處理器中寄存器是固定長(zhǎng)度的,程序中數(shù)字型變量在寄存器中的存儲(chǔ)是有一定限制的。
有些編譯器支持“生命周期分割”(live-rangesplitting),也就是說(shuō)在程序的不同部分,變量可以被分配到不同的寄存器或者內(nèi)存中。
變量的生命周期開(kāi)始于對(duì)它進(jìn)行的最后一次賦值,結(jié)束于下次賦值前的最后一次使用。在生命周期內(nèi),變量的值是有效的,也就是說(shuō)變量是活著的。不同生命周期之間,變量的值是不被需要的,也就是說(shuō)變量是死掉的。
這樣,寄存器就可以被其余變量使用,從而允許編譯器分配更多的變量使用寄存器。
需要使用寄存器分配的變量數(shù)目需要超過(guò)函數(shù)中不同變量生命周期的個(gè)數(shù)。如果不同變量生命周期的個(gè)數(shù)超過(guò)了寄存器的數(shù)目,那么一些變量必須臨時(shí)存儲(chǔ)于內(nèi)存。這個(gè)過(guò)程就稱(chēng)之為分割。
編譯器首先分割最近使用的變量,用以降低分割帶來(lái)的消耗。禁止變量生命周期分割的方法如下:
限定變量的使用數(shù)量:這個(gè)可以通過(guò)保持函數(shù)中的表達(dá)式簡(jiǎn)單、小巧、不使用太多的變量實(shí)現(xiàn)。將較大的函數(shù)拆分為小而簡(jiǎn)單的函數(shù)也會(huì)達(dá)到很好的效果。
對(duì)經(jīng)常使用到的變量采用寄存器存儲(chǔ):這樣允許我們告訴編譯器該變量是需要經(jīng)常使用的,所以需要優(yōu)先存儲(chǔ)于寄存器中。然而,在某種情況下,這樣的變量依然可能會(huì)被分割出寄存器。
變量類(lèi)型
C編譯器支持基本類(lèi)型:char、short、int、long(包括有符號(hào)signed和無(wú)符號(hào)unsigned)、float和double。使用正確的變量類(lèi)型至關(guān)重要,因?yàn)檫@可以減少代碼和數(shù)據(jù)的大小并大幅增加程序的性能。
局部變量
我們應(yīng)該盡可能的不使用char和short類(lèi)型的局部變量。對(duì)于char和short類(lèi)型,編譯器需要在每次賦值的時(shí)候?qū)⒕植孔兞繙p少到8或者16位。這對(duì)于有符號(hào)變量稱(chēng)之為有符號(hào)擴(kuò)展,對(duì)于無(wú)符號(hào)變量稱(chēng)之為零擴(kuò)展。
這些擴(kuò)展可以通過(guò)寄存器左移24或者16位,然后根據(jù)有無(wú)符號(hào)標(biāo)志右移相同的位數(shù)實(shí)現(xiàn),這會(huì)消耗兩次計(jì)算機(jī)指令操作(無(wú)符號(hào)char類(lèi)型的零擴(kuò)展僅需要消耗一次計(jì)算機(jī)指令)。
可以通過(guò)使用int和unsignedint類(lèi)型的局部變量來(lái)避免這樣的移位操作。這對(duì)于先加載數(shù)據(jù)到局部變量,然后處理局部變量數(shù)據(jù)值這樣的操作非常重要。無(wú)論輸入輸出數(shù)據(jù)是8位或者16位,將它們考慮為32位是值得的。
考慮下面的三個(gè)函數(shù):
盡管結(jié)果均相同,但是第一個(gè)程序片段運(yùn)行速度高于后兩者。
指針
我們應(yīng)該盡可能的使用引用值的方式傳遞結(jié)構(gòu)數(shù)據(jù),也就是說(shuō)使用指針,否則傳遞的數(shù)據(jù)會(huì)被拷貝到棧中,從而降低程序的性能。我曾見(jiàn)過(guò)一個(gè)程序采用傳值的方式傳遞非常大的結(jié)構(gòu)數(shù)據(jù),然后這可以通過(guò)一個(gè)簡(jiǎn)單的指針更好的完成。
函數(shù)通過(guò)參數(shù)接受結(jié)構(gòu)數(shù)據(jù)的指針,如果我們確定不改變數(shù)據(jù)的值,我們需要將指針指向的內(nèi)容定義為常量。例如:
這個(gè)示例告訴編譯器函數(shù)不會(huì)改變外部參數(shù)的值(使用const修飾),并且不用在每次訪(fǎng)問(wèn)時(shí)都進(jìn)行讀取。同時(shí),確保編譯器限制任何對(duì)只讀結(jié)構(gòu)的修改操作從而給予結(jié)構(gòu)數(shù)據(jù)額外的保護(hù)。
指針鏈
指針鏈經(jīng)常被用于訪(fǎng)問(wèn)結(jié)構(gòu)數(shù)據(jù)。例如,常用的代碼如下:
然而,這種的代碼在每次操作時(shí)必須重復(fù)調(diào)用p->pos,因?yàn)榫幾g器不知道p->pos->x與p->pos是相同的。一種更好的方法是緩存p->pos到一個(gè)局部變量:
另一種方法是在Object結(jié)構(gòu)中直接包含Point3類(lèi)型的數(shù)據(jù),這能完全消除對(duì)Point3使用指針操作。
條件執(zhí)行
條件執(zhí)行語(yǔ)句大多在if語(yǔ)句中使用,也在使用關(guān)系運(yùn)算符(等)或者布爾值表達(dá)式(無(wú)符號(hào)關(guān)系運(yùn)算x==0,x!=0(或者x>0)。
C代碼中每次關(guān)系運(yùn)算符的調(diào)用,編譯器都會(huì)發(fā)出一個(gè)比較指令。如果操作符是上面提到的,編譯器便會(huì)優(yōu)化掉比較指令。例如:
盡可能的使用上面的判斷方式,這可以在關(guān)鍵循環(huán)中減少比較指令的調(diào)用,進(jìn)而減少代碼體積并提高代碼性能。C語(yǔ)言沒(méi)有借位和溢出位的概念,因此,如果不借助(匯編),不可能直接使用借位標(biāo)志C和溢出位標(biāo)志V。但編譯器支持借位(無(wú)符號(hào)溢出),例如:
懶檢測(cè)開(kāi)發(fā)
在if(a>10程序執(zhí)行的大部分時(shí)間發(fā)生在循環(huán)中,因此十分值得在循環(huán)執(zhí)行時(shí)間上下一番功夫。
循環(huán)終止
如果不加注意,循環(huán)終止條件的編寫(xiě)會(huì)導(dǎo)致額外的負(fù)擔(dān)。我們應(yīng)該使用計(jì)數(shù)到零的循環(huán)和簡(jiǎn)單的循環(huán)終止條件。簡(jiǎn)單的終止條件消耗更少的時(shí)間??聪旅嬗?jì)算n!的兩個(gè)程序。第一個(gè)實(shí)現(xiàn)使用遞增的循環(huán),第二個(gè)實(shí)現(xiàn)使用遞減循環(huán)。
第二個(gè)程序的fact2_func執(zhí)行效率高于第一個(gè)。
更快的f(or)()循環(huán)
這是一個(gè)簡(jiǎn)單而高效的概念。通常,我們編寫(xiě)for循環(huán)代碼如下:
i從0循環(huán)到9。如果我們不介意循環(huán)計(jì)數(shù)的順序,我們可以這樣寫(xiě):
這樣快的原因是因?yàn)樗芨斓奶幚韎的值–測(cè)試條件是:i是非零的嗎?如果這樣,遞減i的值。對(duì)于上面的代碼,處理器需要計(jì)算“計(jì)算i減去10,其值非負(fù)嗎?如果非負(fù),i遞增并繼續(xù)”。
簡(jiǎn)單的循環(huán)卻有很大的不同。這樣,i從9遞減到0,這樣的循環(huán)執(zhí)行速度更快。
這里的語(yǔ)法有點(diǎn)奇怪,但確實(shí)合法的。循環(huán)中的第三條語(yǔ)句是可選的(無(wú)限循環(huán)可以寫(xiě)為for(;;))。如下代碼擁有同樣的效果:
或者更進(jìn)一步的:
這里我們需要記住的是循環(huán)必須終止于0(因此,如果在50到80之間循環(huán),這不會(huì)起作用),并且循環(huán)計(jì)數(shù)器是遞減的。使用遞增循環(huán)計(jì)數(shù)器的代碼不享有這種優(yōu)化。
合并循環(huán)
如果一個(gè)循環(huán)能解決問(wèn)題堅(jiān)決不用二個(gè)。但如果你需要在循環(huán)中做很多工作,這坑你并不適合處理器的指令緩存。這種情況下,兩個(gè)分開(kāi)的循環(huán)可能會(huì)比單個(gè)循環(huán)執(zhí)行的更快。下面是一個(gè)例子:
函數(shù)循環(huán)
調(diào)用函數(shù)時(shí)總是會(huì)有一定的性能消耗。不僅程序指針需要改變,而且使用的變量需要壓棧并分配新變量。為提升程序的性能,在函數(shù)這點(diǎn)上有很多可以?xún)?yōu)化的。在保持(程序代碼)可讀性的同時(shí)也需要代碼的大小是可控的。
如果在循環(huán)中一個(gè)函數(shù)經(jīng)常被調(diào)用,那么就將循環(huán)納入到函數(shù)中,這樣可以減少重復(fù)的函數(shù)調(diào)用。代碼如下:
應(yīng)改為:
循環(huán)展開(kāi)
簡(jiǎn)單的循環(huán)可以展開(kāi)以獲取更好的性能,但需要付出代碼體積增加的代價(jià)。循環(huán)展開(kāi)后,循環(huán)計(jì)數(shù)應(yīng)該越來(lái)越小從而執(zhí)行更少的代碼分支。如果循環(huán)迭代次數(shù)只有幾次,那么可以完全展開(kāi)循環(huán),以便消除循壞帶來(lái)的負(fù)擔(dān)。
這會(huì)帶來(lái)很大的不同。循環(huán)展開(kāi)可以帶非??捎^的節(jié)省性能,原因是代碼不用每次循環(huán)需要檢查和增加i的值。例如:
編譯器通常會(huì)像上面那樣展開(kāi)簡(jiǎn)單的,迭代次數(shù)固定的循環(huán)。但是像下面的代碼:
下面的代碼(Example1)明顯比使用循環(huán)的方式寫(xiě)的更長(zhǎng),但卻更有效率。block-sie的值設(shè)置為8僅僅適用于測(cè)試的目的,只要我們重復(fù)執(zhí)行“l(fā)oop-contents”相同的次數(shù),都會(huì)有很好的效果。
在這個(gè)例子中,循環(huán)條件每8次迭代才會(huì)被檢查,而不是每次都進(jìn)行檢查。由于不知道迭代的次數(shù),一般不會(huì)被展開(kāi)。因此,盡可能的展開(kāi)循環(huán)可以讓我們獲得更好的執(zhí)行速度。
統(tǒng)計(jì)非零位的數(shù)量
通過(guò)不斷的左移,提取并統(tǒng)計(jì)最低位,示例程序1高效的檢查一個(gè)數(shù)組中有幾個(gè)非零位。示例程序2被循環(huán)展開(kāi)四次,然后通過(guò)將四次移位合并成一次來(lái)優(yōu)化代碼。經(jīng)常展開(kāi)循環(huán),可以提供很多優(yōu)化的機(jī)會(huì)。
盡早的斷開(kāi)循環(huán)
通常,循環(huán)并不需要全部都執(zhí)行。例如,如果我們?cè)趶臄?shù)組中查找一個(gè)特殊的值,一經(jīng)找到,我們應(yīng)該盡可能早的斷開(kāi)循環(huán)。例如:如下循環(huán)從10000個(gè)整數(shù)中查找是否存在-99。
上面的代碼可以正常工作,但是需要循環(huán)全部執(zhí)行完畢,而不論是否我們已經(jīng)查找到。更好的方法是一旦找到我們查找的數(shù)字就終止繼續(xù)查詢(xún)。
假如待查數(shù)據(jù)位于第23個(gè)位置上,程序便會(huì)執(zhí)行23次,從而節(jié)省9977次循環(huán)。
函數(shù)設(shè)計(jì)
設(shè)計(jì)小而簡(jiǎn)單的函數(shù)是個(gè)很好的習(xí)慣。這允許寄存器可以執(zhí)行一些諸如寄存器變量申請(qǐng)的優(yōu)化,是非常高效的。
函數(shù)調(diào)用的性能消耗
函數(shù)調(diào)用對(duì)于處理器的性能消耗是很小的,只占有函數(shù)執(zhí)行工作中性能消耗的一小部分。參數(shù)傳入函數(shù)變量寄存器中有一定的限制。這些參數(shù)必須是整型兼容的(char,shorts,ints和floats都占用一個(gè)字)或者小于四個(gè)字大小(包括占用2個(gè)字的doubles和longlongs)。
如果參數(shù)限制個(gè)數(shù)為4,那么第五個(gè)和之后的字就會(huì)存儲(chǔ)在棧上。這便在調(diào)用函數(shù)是需要從棧上加載參數(shù)從而增加存儲(chǔ)和讀取的消耗。
看下面的代碼:
函數(shù)g2中的第五個(gè)和第六個(gè)參數(shù)存儲(chǔ)于棧上并在函數(shù)f2中進(jìn)行加載,會(huì)多消耗2個(gè)參數(shù)的存儲(chǔ)。
減少函數(shù)參數(shù)傳遞消耗
減少函數(shù)參數(shù)傳遞消耗的方法有:
盡量保證函數(shù)使用少于四個(gè)參數(shù)。這樣就不會(huì)使用棧來(lái)存儲(chǔ)參數(shù)值。
如果函數(shù)需要多于四個(gè)的參數(shù),盡量確保使用后面參數(shù)的價(jià)值高于讓其存儲(chǔ)于棧所付出的代價(jià)。
通過(guò)指針傳遞參數(shù)的引用而不是傳遞參數(shù)結(jié)構(gòu)體本身。
將參數(shù)放入一個(gè)結(jié)構(gòu)體并通過(guò)指針傳入函數(shù),這樣可以減少參數(shù)的數(shù)量并提高可讀性。
盡量少用占用兩個(gè)字大小的long類(lèi)型參數(shù)。對(duì)于需要浮點(diǎn)類(lèi)型的程序,double也因?yàn)檎加脙蓚€(gè)字大小而應(yīng)盡量少用。
避免函數(shù)參數(shù)既存在于寄存器又存在于棧中(稱(chēng)之為參數(shù)拆分)?,F(xiàn)在的編譯器對(duì)這種情況處理的不夠高效:所有的寄存器變量也會(huì)放入到棧中。
避免變參。變參函數(shù)將參數(shù)全部放入棧。
葉子函數(shù)
不調(diào)用任何函數(shù)的函數(shù)稱(chēng)之為葉子函數(shù)。在以下應(yīng)用中,近一半的函數(shù)調(diào)用是調(diào)用葉子函數(shù)。由于不需要執(zhí)行寄存器變量的存儲(chǔ)和讀取,葉子函數(shù)在任何平臺(tái)都很高效。
寄存器變量讀取的性能消耗,相比于使用四五個(gè)寄存器變量的葉子函數(shù)所做的工作帶來(lái)的系能消耗是非常小的。所以盡可能的將經(jīng)常調(diào)用的函數(shù)寫(xiě)成葉子函數(shù)。
函數(shù)調(diào)用的次數(shù)可以通過(guò)一些工具檢查。下面是一些將一個(gè)函數(shù)編譯為葉子函數(shù)的方法:
避免調(diào)用其他函數(shù):包括那些轉(zhuǎn)而調(diào)用C庫(kù)的函數(shù)(比如除法或者浮點(diǎn)數(shù)操作函數(shù))。
對(duì)于簡(jiǎn)短的函數(shù)使用__inline修飾()。
內(nèi)聯(lián)函數(shù)
內(nèi)聯(lián)函數(shù)禁用所有的編譯選項(xiàng)。使用__inline修飾函數(shù)導(dǎo)致函數(shù)在調(diào)用處直接替換為函數(shù)體。這樣代碼調(diào)用函數(shù)更快,但增加代碼的大小,特別在函數(shù)本身比較大而且經(jīng)常調(diào)用的情況下。
使用內(nèi)聯(lián)函數(shù)的好處如下:
沒(méi)有函數(shù)調(diào)用負(fù)擔(dān)。函數(shù)調(diào)用處直接替換為函數(shù)體,因此沒(méi)有諸如讀取寄存器變量等性能消耗。
更小的參數(shù)傳遞消耗。由于不需要拷貝變量,傳遞參數(shù)的消耗更小。如果參數(shù)是常量,編譯器可以提供更好的優(yōu)化。
內(nèi)聯(lián)函數(shù)的缺陷是如果調(diào)用的地方很多,代碼的體積會(huì)變得很大。這主要取決于函數(shù)本身的大小和調(diào)用的次數(shù)。
僅對(duì)重要的函數(shù)使用inline是明智的。如果使用得當(dāng),內(nèi)聯(lián)函數(shù)甚至可以減少代碼的體積:函數(shù)調(diào)用會(huì)產(chǎn)生一些計(jì)算機(jī)指令,但是使用內(nèi)聯(lián)的優(yōu)化版本可能產(chǎn)生更少的計(jì)算機(jī)指令。
使用查找表
函數(shù)通常可以設(shè)計(jì)成查找表,這樣可以顯著提升性能。查找表的精確度比通常的計(jì)算低,但對(duì)于一般的程序并沒(méi)什么差異。
許多(信號(hào))處理程序(例如,調(diào)制解調(diào)器解調(diào)軟件)使用很多非常消耗計(jì)算性能的sin和cos函數(shù)。對(duì)于實(shí)時(shí)系統(tǒng),精確性不是特別重要,sin、cos查找表可能更合適。當(dāng)使用查找表時(shí),盡可能將相似的操作放入查找表,這樣比使用多個(gè)查找表更快,更能節(jié)省存儲(chǔ)空間。
浮點(diǎn)運(yùn)算
盡管浮點(diǎn)運(yùn)算對(duì)于所有的處理器都很耗時(shí),但對(duì)于實(shí)現(xiàn)信號(hào)處理軟件時(shí)我們?nèi)匀恍枰褂?。在編?xiě)浮點(diǎn)操作程序時(shí),記住如下幾點(diǎn):
浮點(diǎn)除法很慢。浮點(diǎn)除法比加法或者乘法慢兩倍。通過(guò)使用常量將除法轉(zhuǎn)換為乘法(例如,x=x/3.0可以替換為x=x*(1.0/3.0))。常量的除法在編譯期間計(jì)算。
使用float代替double。Float類(lèi)型的變量消耗更好的內(nèi)存和寄存器,并由于精度低而更加高效。如果精度夠用,盡可能使用float。
避免使用先驗(yàn)函數(shù)。先驗(yàn)函數(shù),例如sin、exp和log是通過(guò)一系列的乘法和加法實(shí)現(xiàn)的(使用了精度擴(kuò)展)。這些操作比通常的乘法至少慢十倍。
簡(jiǎn)化浮點(diǎn)運(yùn)算表達(dá)式。編譯器并不能將應(yīng)用于整型操作的優(yōu)化手段應(yīng)用于浮點(diǎn)操作。例如,3*(x/3)可以?xún)?yōu)化為x,而浮點(diǎn)運(yùn)算就會(huì)損失精度。因此,如果知道結(jié)果正確,進(jìn)行必要手工浮點(diǎn)優(yōu)化是有必要的。
然而,浮點(diǎn)運(yùn)算的表現(xiàn)可能不能滿(mǎn)足特定軟件對(duì)性能的需求。這種情況下,
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年漢中市漢臺(tái)區(qū)河?xùn)|店鎮(zhèn)中心衛(wèi)生院招聘考試真題
- 突起路標(biāo)行業(yè)行業(yè)發(fā)展趨勢(shì)及投資戰(zhàn)略研究分析報(bào)告
- 2024年福建片仔癀化妝品商貿(mào)有限公司社會(huì)招聘考試真題
- 2025年度個(gè)人車(chē)位使用權(quán)轉(zhuǎn)讓與車(chē)位車(chē)位使用權(quán)終止及補(bǔ)償協(xié)議
- 2025年度電子設(shè)備維修工程師勞動(dòng)合同范本
- 港口集裝箱裝卸安全協(xié)議
- 2025年度房產(chǎn)代理傭金收取誠(chéng)意金合同
- 2025年度交通事故損害賠償及保險(xiǎn)理賠諒解協(xié)議
- 2025年中國(guó)錐體蠟燭機(jī)行業(yè)市場(chǎng)發(fā)展前景及發(fā)展趨勢(shì)與投資戰(zhàn)略研究報(bào)告
- 2025年度醫(yī)院食堂營(yíng)養(yǎng)膳食承包管理協(xié)議
- 部編人教版語(yǔ)文小學(xué)六年級(jí)下冊(cè)第四單元主講教材解讀(集體備課)
- (2024年)師德師風(fēng)學(xué)習(xí)內(nèi)容教師師德師風(fēng)培訓(xùn)內(nèi)容通用多篇
- GB/T 3452.3-2005液壓氣動(dòng)用O形橡膠密封圈溝槽尺寸
- EN779-2012一般通風(fēng)過(guò)濾器——過(guò)濾性能測(cè)定(中文版)
- 形位公差測(cè)量方法
- 車(chē)轍防治指導(dǎo)意見(jiàn)(確定稿)
- 一個(gè)近乎完美的微信引流招生方案
- 門(mén)診特殊病種審批表
- T_CEC 102.1-2016 電動(dòng)汽車(chē)充換電服務(wù)信息交換 第1部分_總則_(高清-最新版)
- 國(guó)際形式發(fā)票模板
- 山西省會(huì)計(jì)師事務(wù)所服務(wù)收費(fèi)標(biāo)準(zhǔn)(匯編)
評(píng)論
0/150
提交評(píng)論