最佳化 C++/最佳化生命週期
高效應用程式的構建應遵循以下開發過程
- 設計。首先,演算法和資料結構的設計要符合應用程式邏輯,並且具有合理的效率,但無需考慮最佳化。在設計廣泛使用的資料結構時,其最佳實現並不明顯(例如,爭論陣列或連結串列哪個更好),可以定義一個抽象結構,在最佳化階段可以更改其實現。
- 實現。其次,編寫實現設計算法的程式碼,遵循指南以避免低效操作並封裝可能需要最佳化的操作。
- 功能測試。然後測試生成的軟體,以提高其沒有嚴重缺陷的可能性。
- 最佳化(又名調整)。在完成正確工作的應用程式的開發後,最佳化階段開始,包括以下子階段
- 效能測試。檢測效能不足的命令。這些命令在處理典型資料時,需要的資源(CPU 時間、儲存空間等)超過了可用資源。
- 分析(又名效能分析)。對於每個效能不足的命令,使用分析器確定哪些程式碼部分是該命令的所謂瓶頸。瓶頸是程式碼中花費大量時間或分配大量記憶體空間的部分。
- 演算法最佳化。對於每個瓶頸,應用很大程度上獨立於程式語言並且完全獨立於平臺的最佳化技術。這類技術可以在算法理論教科書中找到。這種最佳化涉及嘗試減少執行的機器週期數量。特別地,它涉及減少對昂貴例程的呼叫次數,或將昂貴的操作轉換為等效但成本更低的操作。例如,選擇快速排序排序演算法而不是選擇排序演算法。如果這使程式足夠快,則最佳化階段完成。
- 平臺無關最佳化。對於每個瓶頸,應用依賴於程式語言及其標準庫,但獨立於軟體和硬體平臺的最佳化技術。例如,使用整數運算而不是浮點運算,或從標準庫中選擇更合適的容器類。如果這使程式足夠快,則最佳化階段完成。
- 軟體平臺依賴最佳化。對於每個瓶頸,應用依賴於程式語言和軟體平臺,但獨立於硬體平臺的最佳化技術。例如,利用編譯器選項、pragma 編譯器指令、語言擴充套件、非標準庫、對作業系統的直接呼叫。如果這使程式足夠快,則最佳化階段完成。
- 硬體平臺依賴最佳化。對於每個瓶頸,應用依賴於硬體平臺的最佳化技術。這可能涉及使用特定於處理器系列的機器指令,或使用在某些處理器型別上特別有利的高階功能,這些功能通常可用。
這個開發過程遵循兩個標準
- 收益遞減原則。首先應用那些只需很少努力就能產生很大效果的最佳化,因為這可以最大程度地減少達到效能目標所需的時間。
- 可移植性遞減原則。最好首先應用適用於多個平臺的最佳化,因為它們在平臺改變時仍然適用,並且更容易被其他程式設計師理解。
在軟體必須使用多個編譯器和多個作業系統,但只使用一種處理器架構的罕見情況下,應交換階段 4.5 和 4.6。
這個階段序列並非指單向序列,即一旦達到一個階段,就不會再使用前一個階段。實際上,每個階段都可能成功或失敗。如果一個階段成功,則應用下一階段,而如果一個階段失敗,則重複前一個階段,這就像一種回溯演算法。
此外,在每次最佳化嘗試後,應執行部分效能測試,以檢查嘗試是否有用,如果有用,則檢查是否需要更多最佳化。
最後,在完成最佳化後,必須重複功能測試和完整的效能測試,以確保軟體的新最佳化版本在功能上仍然正確並且具有合適的效能。
本書僅涉及上述三個階段
- 階段 2,特別是在“編寫高效程式碼”一章中,使用 C++ 語言。
- “通用最佳化技術”一章中,使用 C++ 的示例介紹了階段 4.3 的一些通用技術。
- 階段 4.4,特別是在“程式碼最佳化”一章中,使用 C++ 語言。
透過物件,是指分配的記憶體區域。特別是,與基本型別變數(如bool、double、unsigned long或指標)關聯的資料片段是一個物件,因為它與類的例項關聯的資料結構。每個變數都關聯一個物件,其大小由sizeof C++ 運算子給出,但物件可能沒有與之關聯的變數,或與之關聯的多個變數。例如,指標是一個物件,但它可以指向另一個物件;這個被指向的物件與任何變數都沒有關聯。另一方面,在以下程式碼中,變數a和變數b都與同一個物件關聯
int a;
int& b = a;
陣列、結構體和類例項是物件,如果它們不為空,則包含子物件。因此,它們將被稱為聚合物件。
當前一個物件的銷燬導致後一個物件的銷燬時,我們說一個物件擁有另一個物件。例如,一個非空的vector物件通常包含一個指向包含所有元素的緩衝區的指標;vector的銷燬會導致該緩衝區的銷燬,因此我們說這個緩衝區被vector物件擁有。
某些最佳化僅對短資料序列有用,而另一些對長資料序列有用。稍後將使用以下分類來對物件大小進行分類
- 微小:不超過 8 位元組。它適合一個或兩個 32 位暫存器,或一個 64 位暫存器。
- 小:超過 8 位元組,但不超過 64 位元組。它不適合處理器暫存器,但適合處理器資料快取行,並且可以使用從起始地址偏移的非常緊湊的機器指令完全引用它。
- 中等:超過 64 位元組,但不超過 4096 位元組。它不適合處理器資料快取行,也不能完全用緊湊的機器指令引用,但它適合處理器一級資料快取,適合虛擬記憶體頁面,並且適合大規模儲存塊叢集。
- 大:超過 4096 位元組。它不適合處理器一級資料快取,不適合單個虛擬記憶體頁面,也不適合單個大規模儲存塊叢集。
例如,只有當double陣列包含一個元素時才被認為是微小的,如果它有 2 到 8 個元素,則被認為是小的,如果它有 9 到 512 個數字,則被認為是中等的,如果它有超過 512 個數字,則被認為是大的。
由於存在非常不同的硬體架構,給出的數字僅是一種指示。雖然,這些數字相當現實,可以作為開發軟體以覆蓋主要架構以相當高效的方式的嚴肅標準。