從big.LITTE到DynamIQ

作者簡介

蘭新宇,座標成都的一名軟件工程師,從事底層開發多年,對嵌入式,RTOS,Linux和虛擬化技術有一定的瞭解,有知乎專欄“術道經緯”進行相關技術文章的分享,歡迎大家共同探討,一起進步。

一般我們說到多核,大都是指SMP(Symmetric multi-processing),而ARM的big.LITTLE的CPU組合方案則屬於HMP(Heterogeneous multi-processing)系統。

這裏的"big"是指性能更強,同時功耗更高的CPU(大核),而"LITTLE"則是與之相對的性能略弱,但功耗較低的CPU(小核)。

誰不想又要性能好,又要功耗低,但是單獨的一個CPU是沒法滿足這種互相矛盾的需求的,於是一個折中的方案就是:在一個芯片裏同時包含兩種在性能和功耗上存在差異的CPU。

big.LITTLE技術最早的引入是在2011年10月出現的Cortex-A7中(基於ARMv7-A架構),Cortex-A7作爲“小核”,可搭配與之兼容的Cortex-A12/A15/A17使用。

而後推出的基於ARMv8-A架構且互相兼容的Cortex-A53和Cortex-A57,也可以被用來設計爲big.LITTLE的模式。

這裏的兼容包括了指令集(ISA)的兼容,大核和小核都屬於ARM架構,只是在micro-architecture上有所區別(比如A15有6個event counter,而A7只有4個),所以它們可以運行同一個操作系統。

與之區別的另一個概念是AMP(Asymmetric multi-processing),構成AMP的CPU通常架構差異較大,且運行不同的操作系統鏡像(不是一家人,不進一家門)。

多個同構的大核構成了一個big cluster,多個同構的小核構成了一個LITTLE cluster,同一cluster的CPU共享L2 cache。

big cluster和LITTLE cluster共享中斷控制器(比如GIC-400),且通過支持cache一致性的interconnect相連接(比如coreLink CCI-400)。

如果沒有硬件層面的cache一致性,數據在大核和小核之間的傳輸將必須經過共享內存,這會嚴重影響效率。

【Migration

big cluster和LITTLE cluster中的CPU被同一個操作系統所調度,OS中的任務在執行時,可以根據負載的情況,在大小核之間動態地遷移(on the fly),以提高靈活性。

從OS調度的角度,遷移的方案可分爲兩種,其中最早出現也是相對最簡單的是cluster migration。

  • cluster migration

在這種方案中,OS在任何時刻都只能使用其中的一個cluster,當負載變化時,任務將從一個cluster整體切換到另一個cluster上去,也就是說,它是以cluster爲單位進行migration的。早期的三星Exynos 5 Octa (5410)和NVIDIA的Tegra X1使用的就是這種模型。

這種方案的好處是:在任一時刻,OS要麼全在big cores上運行,要麼全在LITTLE cores上運行,雖然整個系統是HMP的,但從OS的角度,具體到每個時刻,操作的對象都是SMP的,因此對於那些默認支持SMP的系統,使用big.LILLTE芯片時,不需要進行太多代碼的修改。

  • CPU migration

但是,以cluster爲遷移單位,粒度實在太大了點,對於任務的負載介於big cluster和LITTLE cluster之間的,並不需要對一個cluster中的所有cores進行遷移。

而且,對一個cluster進行關閉和開啓的latency通常較大,因而所需的"target_residency"也較大,切換的頻率受到限制。

更精細的方案是big cluster和LITTLE cluster中的core能搭配使用,像下圖這樣,低負載時用4個小核,中等負載時用2個大核和2個小核。

這就是以單個core爲遷移單位的CPU migration方案,具體的做法是:一個大核和一個小核進行組隊,形成一個pair。調度器可以使用每一組pair,但在同一時刻,只允許pair中的一個 core運行,負載高時在大核上運行,低就在小核上運行。

從OS的角度,在任一時刻,每個pair看起來都像只有一個core一樣,所以這樣的pair又被稱爲"virtual core"(或pseudo CPU)。

在遷移過程中,"virtual core"中的其中一個核被關閉(outbound),另一個核被同步開啓(inbound),任務的context(上下文信息)從被關閉的core轉移到同一pair中被開啓的core上。

在Linux中,CPU migration的context轉移依靠的是cpufreq框架,切換到哪一個core,以及什麼時候切換,都由底層的cpufreq的驅動決定。

從內核的角度,它看到的是一個cpufreq展現給它的電壓/頻率的列表,從pair中一個core到另一個core的遷移,就好像只是調整了一下CPU的電壓和頻率一樣,所以可以說這個CPU pair的構成對內核來說是「透明」的。

這套機制被稱爲IKS(In-kernel Switcher),由Linaro實現(參考ELC: In-kernel switcher for big.LITTLE),被NVIDIA的Tegra 3所採用。

【GTS

不管是cluster migration,還是CPU migration,在某一個時刻,都只有一半的CPU cores可以處在運行狀態(假設系統中大核和小核的數目相等),這對CPU資源是一種浪費。所以,一種可以充分利用各個物理核的GTS(Global Task Scheduling)方案應運而生。

在GTS模型中,高優先級或者計算密集型的任務被分配到“大核”上,其他的,比如一些background tasks,則在“小核”上運行。所有的大核和小核被統一調度,可以同時運行。

三星的Exynos 5 Octa系列自5420開始,包括5422和5430,以及蘋果公司的A11,都採用的是GTS。

【負載和遷移】

何時遷移

遷移的依據是負載的變化,那具體的標準是怎樣的呢?當正在LITTLE core上運行的任務的平均負載超過了"up migration threshold",就將被調度器遷移到big core上繼續運行;而當big core上的任務負載低於了"down migration threshold",就將被遷移到LITTLE core上。負載處在這兩個threshold之間時,不做操作。

任務喚醒

當任務從睡眠狀態被喚醒的時候,還沒有產生負載,那如何判斷它應該被放到大核還是小核上執行呢?

默認的做法是根據這個任務過去的負載情況,最簡單的依據就是該任務在上次進入睡眠前所處的core。爲此,需要由調度器去記錄一個任務既往的負載信息。

如下圖所示的這種場景,第一次喚醒時將在big core上執行("Task state"代表狀態是運行還是睡眠,分別對應"Core residency"中的實線和虛線,"B"代表大核,"L"代表小核)。

而第二次喚醒時則會調度到LITTLE core上執行。

cache line的大小問題

Cortex-A系列的ARM芯片通常是配合Linux系統使用的,而Linux在針對多核應用的設計上主要面向的是SMP,這就會帶來一些問題。

其中之一就是:任務在大核和小核之間切換,但大核和小核的cache line的大小通常是不一致的(比如大核是64字節,小核是 32字節),在某些情況下這可能引發未知的bug。

這裏(https://www.mono-project.com/news/2016/09/12/arm64-icache/)給出了一個典型的案例,起因是應用會被SIGKILL信號終結,但發生時的地址看起來好像是完全隨機的,而後他們觀察到這些觸發異常的地址全都分佈在0x40-0x7for0xc0-0xff的範圍內,於是猜想是因爲每次cache flush的時候,只處理了每128字節中的64字節,之後如果訪問到另外的64字節的區域,就會出錯。

最終,他們通過打印cache line的具體內容,並查閱這個big.LITTLE芯片的手冊,驗證了確實是由於他們所調用的函數默認是針對cache line大小一致的SMP的,而該芯片的大小核的cache line是不同的。

DynamIQ

DynamIQ的方案於2017年5月出現,它是基於big.LITTLE進行擴展和設計的,可視作是big.LITTLE技術的演進。

同原生的big.LITTLE不同的是,因爲它採用了ARMv8.2中一些獨有的特性,因此與之前的ARM架構不能完全兼容,所以開始階段只用在較新的Cortex-A75和Cortex-A55處理器上。

混搭風

在DynamIQ中,“大核”和“小核”的概念依然存在,但構成一個cluster的cores可以屬於不同的micro-architecture,因此其可擴展性比big.LITTLE要強。DynamIQ允許至多32個clusters,每個cluster支持最多8個cores,具體的配置可以配成"0+8", "1+7", "2+2+4"等等。

DSU和L3

每個core有自己獨立的L2 cache,同一cluster的所有core共享DSU(DynamIQ Shared Unit)單元中的L3 cache。任務在大小核之間的遷移可以在同一cluster內完成,不需要跨越不同的clusters,而且遷移過程中數據的傳遞可以藉助L3 cache,而不是CCI,減少了總線競爭,因此更加高效。

L3 cache的大小從0KB到4MB不等,因爲一個cluster中的CPU數目可能較多,爲了減少維護cache一致性造成的cache thrashing問題,L3可被劃分爲至多4個groups,且這種劃分可以在軟件運行期間動態進行。

此外,當L3的使用率不高時,還可以group爲單位,通過power-gating技術關閉L3中的部分存儲空間,也節省其消耗的功率,這已經被Energy Aware Scheduling所支持。

(END)

Linux閱碼場原創精華文章彙總

更多精彩,盡在"Linux閱碼場",掃描下方二維碼關注

覺得好別忘了點一下“在看”鼓勵哦~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章