您可能會因為技術原因而使您的同事相信編譯器可以為他們內聯,因此此源代碼級的“優化”無濟於事。
希望您誇大了他們說的話這可能是整個3000行方法最可能優化的,否則您的同事可能對性能優化一無所知,只是鎖定了他們閱讀過一次的內容。認為自己知道某事但真的不理解的人有時最難以說服。我曾在堆棧溢出註釋中進行過多次交流,人們拒絕相信它們是錯誤的,但是無法給出有意義的連貫技術解釋。
作為asm優化專家(SO金牌是[x86],[assembly],[performance],[sse]標籤等),我可以告訴您,即使您的同事花了多年的時間進行性能分析和調整,該功能也是“最優化的”幾乎是不可能的(在某些特定的硬件上(具有某些特定的操作系統和編譯器版本))。較大的函數將始終有空間進行較小的調整(或進行較大更改的新思路),這些調整可能使其更快或更小(機器代碼)以相同的速度運行(也許對超線程更友好,可以用更少的指令來完成相同的工作) 。
我認為C#編譯器+ JIT並不糟糕,它無法為您內聯方法調用,尤其是當它們只有一個調用站點時。我不了解C#(主要是C和C ++),但是它具有類似 static inline
的非成員函數之類的功能嗎,編譯器可以內嵌 來發出基準單獨定義,即使該函數很大,也將這樣做嗎?還是GNU C __ attribute __((always_inline))
之類的東西?您的同事可以使用這些工具來感覺他們正在獲得他們認為重要的優化,而不會使源頭變得一團糟。
但更重要的是,僅當簡單基準版本(您以起點為基準,並針對優化版本進行基準測試)比您想要的速度慢時,“優化”才值得在可讀性上權衡強>。如果您沒有比較的起點,就無法判斷您是否實際上在優化任何東西,從而判斷可讀性或機器代碼大小/指令緩存佔用空間與加速之間的權衡。
編寫沒有簡單基準的可讀性差的“優化”版本通常是一個錯誤,除非您已經從經驗中了解到您知道簡單版本將如何編譯並且效率不高足夠。通常,作為單元測試的一部分,您將有一個簡單的版本,用於手動展開/矢量化版本。 (不過,這種手動內聯的情況可能有所不同。它不會使任何邏輯變得更加複雜或“奇怪地”實現。或者是嗎?塊之間是否存在手動優化?)
內聯通常對於小型函數而言,這樣做是值得的,但是從多個調用站點調用一大段代碼僅使用一次指令高速緩存。但是,它確實每次都會付出函數調用的開銷,因此僅對一個函數進行微基準測試就沒有程序的完整上下文,可能會使過度的內聯和展開看起來不錯。通常,我們可以將決定權留給現代的編譯器啟發式算法。它們通常都經過了很好的調整,特別是如果它們可以執行配置文件引導的優化來查找實際上很熱的循環。 (JIT編譯器在運行時運行,因此,如果願意使用它們,它們的確具有概要分析數據。通常從製作未完全優化的版本或首先進行解釋,然後使用概要分析數據推測性地內聯虛擬方法和類似的東西。)
有時優化不會損害可讀性,但在這種情況下,顯然可以。
在C ++中,我經常寫一些 static inline
輔助函數,這些函數將內聯成一個更大的函數,我正在使用SIMD內部函數優化廢話。當我查看由編譯器生成的asm時,機器代碼效率的下降空間為零,而源代碼的可讀性則具有良好的上升空間。這些幫助器功能的可執行文件中沒有獨立定義,因此它們甚至沒有膨脹可執行文件。
如果您想解決這個問題,請詢問您的同事是否查看了JIT編譯器的asm輸出以獲取其方法並對其進行了概要分析,發現這些大的條件塊使編譯器能夠以內聯無法實現的方式進行優化。
了解編譯器+硬件可以有效地工作並不總是一件壞事,如果您在不影響可讀性的情況下讓它告知您的編碼選擇。
很容易被吸引去優化不需要優化的東西。特別是如果您只是想優化一個函數在快速循環中被調用時的速度,而在非緊急情況下將其優化。如果不經常調用,則代碼緩存可能會很冷,因此緊湊會更好。 (更少的緩存代碼行可以從主內存中加載。)
這種參數僅在您可以從此3000行方法中排除任何常見的輔助函數時才有用。將每個塊放在單獨的函數中不會使機器代碼變小。但是,這可能會使要分配給哪個功能的決策邏輯更加本地化,從而導致該I-cache佔用的空間較小。而且從磁盤/ i-TLB佔用空間讀取/加載的4k頁面可能更少。