如何優化網站代碼?

發表時間:2020-07-02 09:22作者:網站代碼優化來源:蘇州互旦科技網址:http://www.poppano.com/code-optimization-size-speed.html

盡管網站正常工作似乎是項目上的最后一步,但這在嵌入式系統開發中的網站代碼優化并非總是如此。對我們產品的低成本版本的需求促使硬件設計人員僅提供足夠的內存和處理能力來完成工作。當然,在項目的軟件開發階段,使程序正確運行更為重要。為此,通常周圍會有一個或多個“開發”板,每個板都有額外的內存和/或更快的處理器。這些板用于使軟件正確運行,然后項目的最后階段將成為代碼優化。最后一步的目標是使工作程序在硬件的低成本“生產”版本上運行。


如何優化網站代碼?

提高代碼效率

所有現代C和C ++編譯器都提供了某種程度的代碼優化。但是,由編譯器執行的大多數優化技術都需要在執行速度和代碼大小之間進行權衡。您的程序可以做得更快或更小,但不能同時做。實際上,其中一個領域的改進可能會對另一個領域產生負面影響。由程序員決定哪些改進對她來說最重要。有了這些信息,只要遇到速度與大小的折衷,編譯器的優化階段就可以做出適當的選擇。


由于您無法讓編譯器為您執行兩種優化,因此建議您讓編譯器盡其所能來減小程序的大小。執行速度通常僅在代碼的某些時間緊迫和/或頻繁執行的部分內才很重要。您可以做很多事情來手動提高這些部分的效率。但是,手動控制代碼大小是一件困難的事情,并且編譯器更容易在所有軟件模塊中進行此更改。


到程序運行時,您可能已經知道或有了一個很好的主意,哪些子例程和模塊對提高整體代碼效率至關重要。中斷服務例程,高優先級任務,具有實時期限的計算以及計算密集型或經常調用的功能都是可能的候選對象。一些軟件開發套件中隨附的稱為探查器的工具可用于將您的注意力集中到程序花費大部分(或過多)時間的例程中。


一旦確定了需要提高代碼效率的例程,便可以使用以下一種或多種技術來減少其執行時間。

內聯函數

在C ++中,關鍵字inline可以添加到任何函數聲明中。此關鍵字向編譯器發出請求,以使用內部代碼的副本替換對指定函數的所有調用。這消除了與實際函數調用相關的運行時開銷,并且在頻繁調用內聯函數但僅包含幾行代碼時最有效。


內聯函數提供了一個完美的示例,說明了如何有時將執行速度和代碼大小反向鏈接。內聯代碼的重復添加將與調用函數的次數成正比,從而增加程序的大小。并且,顯然,功能越大,尺寸增加將越顯著。生成的程序運行速度更快,但是現在需要存儲更多的ROM。

表查詢

switch語句是要謹慎使用的一種常見編程技術。構成機器語言實現的每次測試和跳轉都浪費了寶貴的處理器時間,只需簡單地決定下一步應該做什么。為了加快處理速度,請嘗試根據個案的相對發生頻率來排列個案。換句話說,將最可能發生的情況放在最前面,最不可能發生的情況放在最后。這將減少平均執行時間,盡管在最壞的情況下根本無法改善。


如果在每種情況下都有大量工作要做,則用指向函數的指針表替換整個switch語句可能會更有效。例如,以下代碼塊是此改進的候選對象。


enum NodeType { NodeA, NodeB, NodeC };


switch (getNodeType())

{

    case NodeA:

        .

        .

    case NodeB:

        .

        .

    case NodeC:

        .

        .

}


為了加快速度,我們將以下切換語句替換為上面的switch語句。 第一部分是設置:創建函數指針數組。 第二個是switch語句的單行替換,可以更有效地執行。


int processNodeA(void);

int processNodeB(void);

int processNodeC(void);


/*

* Establishment of a table of pointers to functions.

*/

int (*func)()   nodeFunctions[] = { processNodeA, processNodeB, processNodeC };


.

.


/*

* The entire switch statement is replaced by the next line.

*/

status = nodeFunctions[getNodeType()]();

手工編碼的匯編

某些軟件模塊最好用匯編語言編寫。 這為程序員提供了使它們盡可能高效的機會。 盡管大多數C / C ++編譯器產生的機器代碼比普通編程器要好得多,但是對于給定的功能,好的程序員仍然可以比普通編譯器做得更好。 例如,在我職業生涯的早期,我在C語言中實現了數字濾波算法,并將其定位到TI TMS320C30 DSP。 那時我們當時使用的編譯器要么不知道,要么無法利用能夠準確執行我所需的數學運算的特殊指令。 通過用執行相同操作的內聯匯編指令手動替換C程序的一個循環,我將整體計算時間減少了十倍以上。

注冊變量

聲明局部變量時可以使用關鍵字寄存器。這要求編譯器將變量放入通用寄存器中,而不是放在堆棧中。明智地使用該技術,可以為編譯器提供有關最常訪問的變量的提示,并在某種程度上增強函數的性能。函數調用的頻率越高,這種更改就越有可能提高代碼的性能。

全局變量

使用全局變量比將參數傳遞給函數更有效。這樣就無需在函數調用之前將參數壓入堆棧,并在函數完成后將其彈出。實際上,任何子例程的最有效實現都根本沒有參數。但是,使用全局變量的決定也可能對程序產生負面影響。軟件工程界通常不鼓勵使用全局變量,以促進實現模塊化和可重入的目標,這也是重要的考慮因素。

輪詢

中斷服務程序通常用于提高程序效率。但是,在少數情況下,與中斷相關的開銷實際上會導致效率低下。在這些情況下,中斷之間的平均時間與中斷等待時間的數量級相同。在這種情況下,最好使用輪詢與硬件設備進行通信。當然,這也導致了模塊化軟件設計的減少。

定點算法

除非您的目標平臺包含浮點協處理器,否則您將需要為操縱程序中的浮點數據付出非常大的代價。編譯器提供的浮點庫包含一組軟件子例程,這些子例程可模擬浮點協處理器的指令集。相對于它們的整數對應函數,這些函數中的許多函數要花費很長時間才能執行,并且也可能無法重入。


如果僅使用浮點數進行一些計算,則最好僅使用定點算術重新實現計算本身。盡管可能很難看清如何做到這一點,但從理論上講,可以使用定點算術執行任何浮點計算。 (畢竟,這就是浮點軟件庫的工作方式,對嗎?)您的最大優點是,您可能不必僅執行一個或兩個計算就實現整個IEEE 754標準。如果您確實需要那種完整的功能,請堅持使用編譯器的浮點庫,并尋找其他方法來加速程序。

減少代碼大小

就像我之前說的,要減少代碼大小,最好的選擇是讓編譯器為您完成工作。但是,如果生成的程序對于可用的ROM仍然太大,則可以使用多種編程技術來進一步減小程序的大小。在本節中,我們將討論自動和手動代碼大小優化。


當然,墨菲定律規定,第一次啟用編譯器的優化功能時,以前運行的程序會突然失敗。自動優化中最臭名昭著的也許是“消除死代碼”。這種優化消除了編譯器認為冗余或不相關的代碼。例如,將零添加到變量不需要任何運行時計算。但是,如果它們執行了編譯器不知道的某些功能,您可能仍希望編譯器生成這些“不相關”的指令。


例如,給定以下代碼塊,大多數優化編譯器都會刪除第一條語句,因為* pControl的值在被覆蓋之前(在第三行)未使用。


*pControl = DISABLE;

*pData     = 'a';

*pControl = ENABLE;


但是,如果pControl和pData實際上是指向內存映射設備寄存器的指針,該怎么辦?在這種情況下,外圍設備在寫入數據字節之前不會收到DISABLE命令。這可能會嚴重破壞處理器與該外設之間所有將來的交互。為了保護自己免受此類問題的侵害,必須使用關鍵字volatile聲明所有在線程(或線程和ISR)之間共享的內存映射寄存器和全局變量的指針。而且,如果您只想念其中之一,那么在項目的最后幾天,墨菲定律將再次困擾您。我保證


不要誤以為優化程序的行為與未優化程序的行為相同。您必須在每個新的優化級別上完全重新測試軟件,以確保其行為沒有改變。


更糟的是,至少可以說,調試優化的程序具有挑戰性。啟用編譯器的優化功能后,源代碼行與實現該行的處理器指令集之間的相關性就弱得多。這些特定的指令可能已經移動或拆分,或者兩個相似的代碼塊現在可以共享一個通用實現。實際上,高級語言程序的某些行可能已從程序中完全刪除(就像前面的示例一樣)!如此一來,您可能無法在程序的特定行上設置斷點或無法檢查目標變量的值。


自動優化工作完成后,以下是一些提示,可幫助您進一步手動減少代碼的大小。

避免使用標準庫函數

減小程序大小的最佳方法之一是避免使用大型標準庫例程。許多最大的存儲庫之所以昂貴,僅是因為它們試圖處理所有可能的情況。您可以用更少的代碼自己實現功能的子集。例如,眾所周知,標準C庫的sprintf例程很大。此批量的大部分位于其依賴的浮點操作例程中。但是,如果您不需要格式化和顯示浮點值(%f或%d),則可以編寫自己的sprintf整數型版本,并節省幾千字節的代碼空間。實際上,標準C庫的一些實現(想到了Cygnus的newlib)就包括這樣的函數,即sprint。

本機字大小

每個處理器都有一個本機字大小,ANSI C和C ++標準規定數據類型int必須始終映射到該大小。操縱越來越大的數據類型有時可能需要使用其他機器語言指令。通過在程序中盡可能始終使用int,您可能可以從程序中節省寶貴的幾百個字節。

轉到語句

與全局變量一樣,良好的軟件工程實踐也禁止使用goto語句。但在緊要關頭,可以使用goto刪除復雜的控制結構或共享一個經常重復的代碼塊。


除這些技術外,上一節中介紹的一些技術可能會有所幫助,特別是表查找,手工編碼的匯編,寄存器變量和全局變量。其中,使用手工編碼的匯編通常會最大程度地減少代碼大小。

減少內存使用

在某些情況下,可能是RAM而不是ROM是限制應用程序的因素。在這些情況下,您將希望減少對全局數據,堆棧和堆的依賴。這些都是程序員比編譯器更好的優化。


由于ROM通常比RAM便宜(按字節為單位),因此減少全局數據量的一種可接受的策略可能是將恒定數據移入ROM。如果您使用關鍵字const聲明所有常量數據,則編譯器可以自動完成此操作。大多數C / C ++編譯器將它們遇到的所有恒定全局數據放入一個特殊的數據段中,該數據段對于定位器而言可識別為ROM。如果有很多字符串或面向表的數據在運行時不會更改,則此技術最有價值。


如果一旦程序運行就固定了一些數據,但不一定是恒定的,則可以將恒定數據段放在混合存儲設備中。然后,可以通過網絡或指派進行更改的技術人員更新此存儲設備。此類數據的一個示例是將在其中部署產品的每個區域的銷售稅率。如果稅率發生變化,則可以更新存儲設備,但與此同時可以節省額外的RAM。


減少堆棧大小還可以降低程序的RAM需求。準確確定需要多少堆棧的一種方法是用特殊的數據模式填充為堆棧保留的整個存儲區域。然后,在軟件運行了一段時間(最好是在正常和壓力條件下)之后,請使用調試器檢查修改后的堆棧。堆棧存儲區中仍然包含特殊數據模式的那部分從未被覆蓋過。因此可以安全地將堆棧區域的大小減小該數量。


如果使用實時操作系統,請特別注意堆??臻g。大多數操作系統為每個任務創建一個單獨的堆棧。這些堆棧用于在該任務的上下文中發生的函數調用和中斷服務例程。您可以按照上述方式確定每個任務堆棧所需的堆棧量。您也可以嘗試減少任務數量,或切換到具有單獨“中斷堆?!钡牟僮飨到y以執行所有中斷服務例程。后者可以顯著減少每個任務的堆棧大小要求。


堆的大小限制為在分配了所有全局數據和堆??臻g之后剩余的RAM數量。如果堆太小,則程序將無法在需要時分配內存。因此,始終要在取消引用之前將malloc或new的結果與NULL進行比較。如果您嘗試了所有這些建議,而程序仍然需要太多內存,那么您可能別無選擇,只能徹底消除堆。不幸的是,這只有在使用C的情況下才有可能。 new和delete運算符是C ++語言的內置功能,而不是標準庫(如malloc和free)的一部分。

限制C ++的影響

我決定寫這本書時面臨的最大問題之一是是否在討論中包括C ++。盡管我熟悉C ++,但是我幾乎用C和匯編語言編寫了所有嵌入式軟件。另外,在嵌入式軟件社區中,關于C ++是否值得性能損失的爭論很多。通常認為C ++程序會產生較大的可執行文件,其運行速度比完全用C編寫的程序要慢。但是,C ++對程序員也有很多好處。我想在書中談談其中的一些好處。因此,我最終決定在討論中包括C ++,但在示例中僅使用性能損失最小的那些功能。


我相信許多網站建設者在自己的嵌入式系統編程中將面臨同樣的問題。熟練掌握網站代碼優化,確保網站流暢運行是很重要的。

文章列表
2019-07-08
蘇州谷歌競價發現,許多外貿公司的網站都負責外包公司。對于其他批次的公司,他們依靠自己的探索方法。但他們經常遇到無法解決的問題。以下是Google Bidding教程方法的詳細說明。
2019-07-08
蘇州外貿推廣渠道有哪些?本次就關于B2B推廣,我總結了五種方法分享給大家,僅此幫助那些從事google推廣碰壁的人...
2019-07-09
蘇州谷歌代理現已是長三角負責google推廣的重要渠道之一,對于新入行的企業來講首先要知道其到底是做什么?自己可能...
2019-07-09
對于蘇州外貿網站建設的人來說,由于隨著全球電子商務的發展,許多外貿公司希望將品牌推向世界,并將建立一個外貿網站。那...
2019-07-10
做過的網站優化的人都會碰到網站收錄下降、網站被K或者是不收錄等情況,令人頭疼不已。本次就由蘇州seo外貿推廣教你6...
2019-07-10
從今天海外網站發展趨勢來講,如果外貿企業還想單靠網站在Google、bing和Yahoo等搜索引擎賺取流量和訂單,...
2019-07-11
由于外貿近年來遭受的損失,如何度過這場危機已成為最關鍵的問題。搞好外貿是一種在主要社交媒體上推廣網站排名和公司產品...
2019-07-11
首先要知道Google作為全球第一大搜索引擎,每天吸引的流量是無比龐大的。既然是外貿企業如果放棄這個推廣平臺,實在...
2019-07-12
蘇州google代理商就網站中最重要TKD教程中,今天抽取title標簽單獨講,后續也會把K和D逐一為大家分析。t
2019-07-12
蘇州谷歌代理商告訴你做優化首先要懂一些代碼,但是現在很多剛從事這類工作的人不是太懂代碼,只知道把標題、關鍵詞、描述...