我們這些軟件工程師都熱衷于為我們遇到的問題找出完美的解決方案。但奇怪的是,我們會發現在這個特定的領域,沒有一個完美的解決方案。聰明的技巧可能會節省一些功率,但是這個領域是由其他更簡單的因素支配的。就象房間里有幾頭很大的大象,我們必須要先小心翼翼地獵取我們可以看到的大象,然后再花精力去獵捕體型小的動物。
在考量某個系統的功耗時,重要的是要弄清楚我們實際測量的對象是什么。我們說的“節省功耗”可能意味著幾個方面。它意味著“功率”還是“能量”。實際上,我們既需要功率也需要能量。大多數手持便攜式設備均具有以下兩個不同的預算:功率預算——它管理著瞬間功耗、避免過熱或產生熱應力,而能量預算則管理著長期使用的能量總數。而軟件則需要滿足短期的功率預算和長期的能量預算。
很明顯,我們可以把任何設備的功耗降低到接近零,只要不讓它做任何操作或任何有意義的操作即可!不得已的是,實現有用的功能就需要耗費能量。因此,我們只能在有意義的操作和節能二者中不斷采取折衷方案。為了實現所需的功能,我們必須耗能;但我們必須盡量確保以節能的方式來實現這些功能。
功耗時間積 有關該主題的學術材料中常用的更好度量方式是采用“功耗時間積”。盡管既沒有標準單位也沒有具體方法,但是這種度量方式將能耗和性能度量結合到了一起。增加能耗或降低性能會增加功耗時間積的值,因此我們的目標是找出最低的可接受的功耗時間積的值,換句話說,最低的能耗要與允許的時間內所需任務的執行保持一致。
能量去哪兒了? 所有計算器械均會執行兩個基本功能。這兩個功能都是必需的,沒有這兩個功能就不能完成任何有意義的任務。
我們首先想到的自然是計算或數據處理。通常,計算是對機器寄存器中保存的值實施的操作。為了盡可能高效地實施計算任務,我們需要在最短的時間內執行最少的指令。最重要的是,高效計算允許以下二選一:要么我們可以早點完成計算去睡覺,要么我們調慢時鐘且仍然在規定時間內完成計算任務。
這里經常被人忽視的是數據通信(數據移動)。在大多數架構中(A R M采用加載/存儲架構,也不例外),數據移動是必需的。如果不將信息從一個位置移動到另一個位置且經常返回原來的位置,用戶就無法處理任何信息。例如,內存中的值需要移動到寄存器中進行處理,然后把結果寫回到內存中。
但是哪個耗用的能量更多呢?最大的償付在哪兒?
圖1顯示了普遍存在的事實,與程序有關的內存存取操作中有大約60%是指令抓取,另外40%才是數據存取。
圖1:內存存取分布
圖2:內存存取能耗
圖2顯示了A R M進行的一些研究。如果執行一條指令的能耗是1,那么,緊耦合存儲器(TCM)存取的能耗約為1/25,緩存存取的能耗大約為1/6。而外部R A M存取的能耗則是指令執行能耗的7倍。
換言之,對于每次外部R A M存取所用的能耗,我們可以執行7條指令,40次緩存存取或大約170次TCM存取。
計算廉價但通信昂貴
因此,似乎數據移動要比數據處理更昂貴。因此,第一頭大象就是數據效率。
我們可以為內存存取的能耗管理提出兩個規則。
近距離 - 從能量角度講,內存越靠近核心,訪問內存的相對能耗越低。
少存取 - 減少內存存取次數比減少指令數量更加重要。
充分利用片上存儲器
從我們的能量圖可以清楚地看出,TCM是到目前為止系統具有的最高效存儲器類型。不是所有的系統均具有A R M稱為TCM的存儲器(通過專用和優化的接口連接到內核),但是大部分系統至少具有某種片上快速存儲器類型。為了便于討論,我們指的是常見的片上存儲器(SPM)。假定S PM單次存取能耗大約是外部R A M存取能耗的1/170,充分利用這種SPM存儲器應該是首選。
圖3:SPM的能量優勢
圖3中的圖表顯示了簡單的“多類”基準,甚至128個字節的S PM區域都可以減少大約一半的功耗。1k字節的存儲器最大可減少70%的功耗。本次研究(Mar wedel, 2004)中采用的方法是從外部R AM到S PM動態重定位代碼和數據片段。甚至在按需移動各項開銷方面,不僅降低了能耗,性能也提高了大約60%。
很顯然,我們在某個點上正在損失回報。這種情況下,S PM超過1k時,性能提升幅度變緩,系統總能耗也會稍微升高。在這里,我們實際上在承擔這種特定應用無法使用的S P M能耗,因為這種應用程序本身并不夠大。
您還可以注意到,在結合了所使用的分配算法時,這種特定的應用無法使用小于64字節的S P M區域,因為沒有足夠小的可用片段與之相配。本次研究中還展示了一個更加成熟的算法,可以在最佳狀況下節省能耗可以超過80%。
永遠做緩存友好的事
分析緩存優點有時可能比分析S PM優點更加復雜。一方面,緩存基本上是自我管理的。另一方面,緩存不是對單個存儲位置進行操作,而是對固定大小的“線路”進行操作。因此,訪問單個可緩存的存儲位置可能加載整條線路,從而造成突發的內存存取。如果該附加的數據從未被訪問過,則所消耗的能量就浪費了。
另一個不利之處是緩存所需的其他邏輯成本(就硅片面積和功耗而言)。
圖4:緩存的能量優勢
圖4摘自普林斯頓(Brooks,2000)一份論文,顯示了針對某簡單應用基準的三套數據。針對不同的緩存大小,這些條塊分別代表性能IP C(單位周期指令數)、功耗和功耗時間積(ED P)。總的來說,性能會隨著緩存大小的增加而提升。但是,系統的功耗也會增加,因為增大緩存單元會相應增加功耗。功耗時間積允許我們在性能和緩存大小之間取得平衡。在這個例子里,存在一個最佳點,即緩存大小為64k時,此時的功耗時間積最小。
最大限度減少數據內存存取
A RM架構的一個特性是其常量是不確定的,特別是,不可能用單條指令把一個任意32位常量放到一個寄存器中。實際上,所有內存存取必須按寄存器中的地址操作,這就意味著程序需要把這些地址和其他常量頻繁地放到寄存器中,而這一點很難做到。解決此問題的標準方法是把常量作為文字數據嵌入到代碼段中,在運行時使用PC相關的加載進行加載。
因此,這種最大限度減少常量影響的方法很實用。確保在編譯時這些常量是已知的,如果可能,最好能把這些常量嵌入到單條ARM指令中。為了存取全局變量,盡可能減少加載基址指針的需求。這就需要確保全局變量在運行時都在內存中,這樣才能使用單個指針存取多個變量。實現這個目標最簡單的方式是將全局變量放到一個結構中。
盡管A R M的堆棧訪問相對高效(堆棧訪問可較好地加載和存儲多條指令),但是程序員還可以通過很多方式來減少堆棧訪問:減少活動變量、避免占用本地變量地址、可能時充分利用尾部調用優化、將傳遞到函數的參數數量減少到四個以下、允許編譯器主動內聯函數等。
遞歸情形和避免遞歸情形的做法更加復雜。通常編譯器可以對歸函數很好地進行尾部優化。實際上將所有數據存儲到堆棧中可以比其他做法獲得更好的局部性。或許建議可能最好表達為“除非其他做法讓數據局部性更糟或您確信編譯器可以對遞歸調用進行尾部優化,否則不要使用遞歸算法”。應編寫異常處理程序,增加尾部連鎖的機會,進而避免堆棧環境內不必要的保存和恢復。
現在我們把注意力轉到這個問題的第二頭大象,即指令執行。
最大限度減少指令數目
事實上,減少指令執行次數本質上與性能優化是相同的,執行的指令數越少,能耗就越低。另外,還要增加一些明顯的指針。
首先,正確地配置工具。在編譯器和鏈接器完全了解目標平臺,甚至無法實施一些基本的優化。
編寫代碼時要保持敏銳,才能避免不必要的操作。對于A R M架構,32位數據類型是高效的:一般8位和16位數據類型,盡管占用的存儲空間較少,但是處理效率也較低。在v6和v7架構中,打包和接包指令以及S IM D操作一定程序上對此有些幫助,但是要注意,在主程序中無法從C訪問這些指令。
編寫循環時要當心
可以按照以下一些簡單的規則來編寫循環:使用無符號的整數計數器,向下倒數,并把是否等于零作為終止條件。這可以讓循環更短,速度更快,使用的寄存器更少。還要記住,要采用矢量化來編寫循環。即使在嘗試展開和矢量化最簡單的循環時,有關控制結構和數據聲明的一些簡單規則都可以讓編譯器的作業變得更簡單。
圖5:循環展開
圖5顯示了與一個特定循環優化有關的一些數據,這個循環優化就是循環展開(Brooks,2000)。按照預期,隨著展開因子的增加,執行時間和指令數目會減少。我們看到了減少循環開銷和減少地址計算的效果。功率結果更加有趣,但不太明顯。因為預測器可用來訓練其行為的分支更少且針對循環結束失敗的最終錯誤預測比例大增,所以隨著循環進一步展開,分支預測器的準確性出現下降。但是,因為順序取指的連續數據流不經常被中斷,所以取指階段的效率可以提升。組合的結果是減少了每條指令的凈能耗。
因此盡管執行時間基本上低于展開因子4,但是因為功耗持續降低,所以所有重要的功耗時間積也隨之降低。因此有能耗意識的編譯器或開發人員與只考慮執行時間的編譯器或開發人員相比,會更傾向于展開循環。
精度滿足需求即可
還必須考慮輸出要求的精度。即使有浮點硬件可用,定點實現的計算通常比浮點實現的計算更有效率。如果您正在渲染一個供屏幕查看的圖像,可能并不需要完全符合標準,您只需要渲染出可以接受的圖像。
對標準M P E G- 4解碼函數進行遞進優化的一項研究(S h i n,2002)已經表明,把軟浮點切換為定點二進制可以把能耗降低72%。精度損失意味著該結果不再符合標準,但是在所研究的系統上仍然足以滿足渲染用途。
關于Thumb
T humb指令集專門設計用于改進代碼密度,還可以提升窄內存系統的性能。但是,在代碼密度確實改進的同時,指令數也同時增加了。這是因為,與A R M指令相比,減少了個別Thumb指令的功能。因此Thumb重新編譯會造成能耗增加,這看起來是合理的,而我們看到的事實也的確是這樣。
上述研究表明,如果代碼大小減少4%,指令執行數增加38%,而能耗增加28%。為了找到第三頭大象,我們需要走出處理器及其內存的領域,著眼于范圍更大的系統。我們這些天使用的系統已經被我們的硬件設計同事組合到了一起,這個系統提供了大量節能選項。
更廣系統中的節能
顯而易見,沒有使用的組件應盡可能置于低功耗狀態。這也是所有敏銳的設計系統不可分割的組成部分,這些組件應包括內存和緩存系統、甚至是處理器本身。在多核系統中,我們必須考慮在處理要求相對低時中止一個或多個內核運行的可能性。
首先,一個很小但值得考慮的問題是:處理外設時,要始終嘗試使用中斷機制,而不是輪詢機制。輪詢循環只會耗用能量而無任何目的。幾乎所有架構均包括了某種等待中斷的指令,可以把這種情況下的系統置于待機狀態。對于A R M系統,內核通常帶有時鐘門控,只保留靜態漏電。
通過設計中斷架構來增加拖尾連鎖,一般可以避免不必要的睡眠喚醒循環。ARM Cortex-M3架構可以自動實現這一點。
對于個別計算單元,選擇一種關機方案是很容易的。對于可以預測需要與否的單元,在不需要時通過應用程序或操作系統就可以停止運行這些單元。對于不可預測需要與否的單元,可以通過按需通電啟動系統,也可以在空閑超過某段時間之后再自動斷電。子系統斷電的時標可以通過以下兩方面來得出:通電但處于空閑狀態時的功耗以及睡眠喚醒循環的能耗。從根本上講,這取決于應用場合。但是,動力循環代碼的簡單循環計數將是最明顯的起點。
測量數據表明,N e o n引擎相比C o r tex-A9等內核的運行功率要高大約10%。但是,對于傳統的信號處理算法,其性能提升了40% - 150%。在任務期間啟用NeON而在不需要時切斷Neon的好處很明顯。很常見的是,不但N e o n引擎可以在任務完成時切斷,而且整個處理器系統可以節省更多功耗。
通常一個比較難的選擇是啟用計算組件提前完成計算(且因此切斷時間更長)還是完成計算時及時降低處理器速度以減少功耗。圖6顯示了每次迭代的能耗數據,這是簡單的基準(Domeika, 2009)。采用不同的指令緩存和浮點協處理器組合,對于兩個時鐘速度,每個時鐘速度均要運行此基準四次。有兩個清晰的重點。首先,盡管指令緩存和浮點單元均減少了能耗,但是浮點單元比指令緩存的表現更優異。
圖6:系統組件電源利用
其次,對于所有配置而言,每次迭代的能耗從本質上講是相同的,與時鐘速度無關。因此,為了更快地完成任務而啟用所有功能并全速運行要比調慢時鐘速度更加高效。
多重處理
眾所周知,與調高單核的功率相比,采用多核可以獲得更高的性能和更好的能效。使用多核系統時,我們必須考慮在不需要時選擇中止一個或多個內核。A R M的研究表明,S M PLinux系統中單核循環的成本是50000個周期(大部分周期用于清除一級緩存),這意味著此操作將在幾百毫秒內完成,而不是更短的時間內完成,否則其能耗成本將超過其具有的優勢。
ARM是主動研究型架構,其包含兩個內核,一個高性能的內核用于全功能操作,一個較小的配套內核則以較低的性能完成低功率操作。需要較高的處理功率時,系統運行較大的內核。任務完成時,系統可以把所有信息傳遞給小內核并關閉大內核。需要逆向信息移動時,再切換回大內核。如果這兩個內核相連成為相關系統,則切換的能耗成本可降到最低。
關于操作系統
不巧的是,在操作系統上運行時,應用程序員無法這樣靈活處理。緩存配置、S PM使用與否、組件的電源周期等很大程度上都是操作系統架構和設備驅動程序來專門決定的。但是,應用程序員仍然有很多東西需要考慮。
研究已經表明,設計不良的進程間通信(I P C)會大大增加系統的能耗。一個簡單的技術稱為“矢量化”進程間通信,這種技術批量處理小的消息并把大量小的消息作為一個大的消息來發送,這樣通常可以減少上下文的切換開銷。另外,減少進程數量可明顯降低進程間通信的需求。需要頻繁通信的進程可以合并成一個進程。
在嵌入式Linux中運行的最近研究(Tan, 2003)表明,分析和合理設計進程間通信2 可以潛在改進能耗多達60%。
結論
盡管我已經強調了許多領域仍然屬于學術研究范圍,但我們現在還是可以做許多工作。結果相對比較簡單:減少外部內存存取,減少指令執行,并在不使用某些單元時關掉它們。
在做出這個結論的同時,我想起了2 0 0 9年中期在一次培訓課上與客戶的一次談話。這些客戶關心如何在包含了N e o n的C or tex-A8平臺上實現信號處理算法且想要知道個別指令的確切能耗。我解釋說,實際上很多這種信息是未知的,而且不管在什么情況下,很難使用當前的工具得出這些信息。回顧上文,我們已經認識到在捕獵大象的這個長期任務中,這些信息都是無關緊要的。實際上,客戶要捕獵的大象與房間中的其他大象相比,非常的小。不管是經過分析還是持續跟蹤數據,都可以得出更好的建議,那就是估算每次實現中涉及的數據存取次數和類型。這樣,再結合指令計數,可以做出更加明智的選擇。與內存存取布置不良相比,個別指令的功耗幾乎無關緊要。
我們這些軟件開發人員要繼續對學術和工具供應商施加壓力,讓他們在下一代工具中構建出這些功能。這不容易但將會實現。
最后,我必須提醒大家所有這些取決于您所用的系統、平臺、應用程序、操作系統、電池和用戶。就像俗話說的“優勢各有不同”。
評論