在高效能電腦上面,透過 CPU 對應的方式來進行程序優化的行為
高效能電腦叢集 (cluster) 經常用在比較需要大量運算的環境中。另外,近期因為雲端虛擬化的應用廣泛,機房內的機器常常也是屬於這種大型高效能電腦。 這種類的電腦經常有多顆 CPU 同時在運作,而大家知道 Intel 的 CPU 通常有 HT 功能,那其實你僅有一個運算單元模擬出兩顆 CPU, 這時候到底系統要怎麼操作才能達到最佳化?這就需要一些基礎技能與特殊操作技巧了!
鳥哥在這裡先說個大前提,免得大家以為在這篇看完後,自己的 Server 就會變得超級強!其實...並不會~
鳥哥的專業背景其實是環境工程,多年前為了了解空氣污染排放與周界空氣品質的相關性,因此開始接觸空氣品質模式, 這是一個美國環保署開發的模式,稱之為 CMAQ (註1)。
因為 CMAQ 是個很大型的數值模式,因此單純使用一顆 CPU 來跑是很不夠力的!所以 CMAQ 原本就被開發為平行化處理, 也就是說,當模式運作時,它將整個大氣空間分為三個維度 (水平的 X 與 Y ,還有垂直的 Z),然後依據 CPU 的核心數, 將這個空間再細分為多個格點 (grid),然後將這些格點平均的分給各個 CPU 去跑。
承上,你會以為 CPU 數量越多,那麼這個模式的運作會越快~其實也不盡然~因為這些空間是有相關性的,所以格點與格點之間需要經常的交換資料~ 而你如果將它看在電腦系統上,那就會發現到每個 CPU 得要經常的交換資料,這些資料主要是在記憶體中,或者是網路上!
嗄!在記憶體中我們還能理解,為何是會在網路上呢?這是因為每部電腦的 CPU 核心數可能沒有這麼多,而你想要將這些 grid 分散到越多 CPU 核心上, 所以就動腦筋將數台電腦串接在一起,透過網路將這些 grid 分配到不同的電腦上,讓這些電腦分別去跑這一個模式。也就是說, 如果你只有一般 PC 而已,那麼多台 PC 串在一起,你也可以使用到超過 10 個以上的 CPU 核心數了!
這樣就產生一個問題,因為 CPU 與記憶體的速度超級快,但是網路的速度卻只有 Gigabit 或 10Gigabit,大約是 125Mbytes/s 或 1250Mbytes/s, 速度遠遠慢於一般 2GHz CPU 至少 16Gbytes/s 的速度,也慢於 DDR3 1333MHz 10Gbytes/s 的速度!所以,當使用網路上的 CPU 核心數 (亦即將一個工作丟給太多不同的電腦運算) 太多時,由於資料交換的問題,反而會導致系統效能的低落,也就是模式運算速度反而變慢了!
如上圖的示意,每個 CPU 假設為一部單獨的伺服器,而我的一個 job 丟給四部系統去跑,但這四部系統是透過速度相對慢的 switch, 這時系統效能就卡在那個 switch 上面!但是也還是要考慮到資料的交換~如果資料交換沒有這麼大,丟給四部來跑可能還是可以增進效能的! 看看底下的討論~
所以說,可以平行化運算時,你還是得要注意到,並不是 CPU 核心數使用的越多越好!你還得要思考:
所以說,到底你要怎麼進行你的平行化模式的運作優化?每一個模式的案例都不一樣!這得要自己追蹤查詢一下!以鳥哥為例, 早期 v4.7 的 CMAQ 版本不能用太多 CPU ,如果超過 8~16 顆以上,效能反而會變差~ 但新版 v5.1 的 CMAQ 版本,CPU 數量可以使用到 30 顆左右,效能可以持續增強哩!光是同一個 CMAQ 的不同版本, 在操作上面就有不一樣的情況發生!
那鳥哥是怎麼知道上述的情況?沒啥特殊的~就是多次進行案例的執行,慢慢歸納出來的結果!這沒辦法由單一幾次的測試就知道啦! 唉~效能調校也是一件相當大的工程!
現在不論個人電腦組裝的伺服器還是一般伺服器等級的電腦,大部分的 CPU 主要是以 Intel 為主,所以底下我們針對 Intel 的 CPU 來說明一下。 再次強調,這篇主要針對的是高效能的系統,跟一般朋友們接觸到的 server 運作環境可能差異很大!因此這篇文件的內容不見得適用於你喔!^_^
Intel 的 CPU 有個很有趣的功能,叫做超執行緒 (Hyper-Threading, HT 註2) 技術!他可以將 4 核心的單一顆 CPU 模擬出 8 個核心! 哇!真的是好棒棒!那到底是怎麼辦到的?強者我同事蔡董大大曾經說過,所謂的 HT 技術,簡單的說,就是單一運算核心有兩組暫存器,每個暫存器可以被視為一個實體的 CPU 核心這樣而已。簡圖是這樣:
其實說到底,這顆 CPU 還是只有四個基本的實體運算單元,但是由於各有兩組暫存器,而 CPU 運算單元讀取的資料就是來自於暫存器,因此兩組暫存器就可以被作業系統判別為兩顆邏輯 CPU 了。 因此我們會說 CPU 的 HT 技術,可以讓你有 4 核 8 緒,就是這個原理。
為啥要講這?來來來~我們前一小節談到鳥哥的 v4.7 CMAQ 模式中,模式的運作並不會吃掉全部的 CPU 資源,由於這個特性, 因此圖 1.2-1 當中那個運算核心就會有段時間保持閒置,這時從另一組的暫存器來的要求,就能夠同時的運作 (因為 CPU 並沒有在忙碌中)! 因此 v4.7 的模式運作中,鳥哥發現 4 核 8 緒真的很有用!可以發揮到 8 個 CPU 的效能!真是感謝 HT 啊!
但是 v5.1 之後就不是這麼回事!因為每個 process 都要使用 100% 的 CPU 實體運算單元,因此 CPU 實體永遠在忙碌!此時另一組暫存器如果加進來, 雖然不至於拖垮整體 CPU 效率,但是就是沒有辦法增加效能!因此使用 4 顆跟使用 8 顆 CPU 的結果,模式效能是差不多的!但如果使用的是 4 顆與 7 顆呢? 效能反而是 4 顆的比較好!很意外吧! ^_^
這也就是說,HT 技術對於不同的使用環境是具有不一樣的情況的!如果是一般 server 的運作,因為 server 的服務大多不會佔用 CPU 核心資源到 100%,因此 HT 一定要開!對於效能肯定有很大的幫助!因為他會讓閒置中的 CPU 核心發揮到完整的運算能力 (其實一般 server 並不會太操 CPU 啦!)。
但如果你是像鳥哥這樣操作大型數值模式時,動不動就需要用到 12~30 顆的實體運算 CPU 核心,那麼 HT 技術的使用反而需要注意! 否則可能容易發生大問題!例如你以為四核八緒的環境下,你只要使用 4 顆 CPU 就好啊!那不是就會用到 4 個運算單元? 但如果你的作業系統不夠聰明,反而是 4 個 process 用在兩個實體運算的環境下,那反而產生兩個閒置的 CPU 耶!效能差一倍!你說要命嘛?
你會問:『鳥哥,那 HT 技術到底要不要開啟啊?』鳥哥回答你,一定要開啟!就鳥哥最近這幾周的經驗來看, 鳥哥開了 HT 技術後,同時跑兩個案例,每個案例佔用 4 顆 CPU (平均分配在每個實體運算單元上),假設 0, 1, 2, 3 為實體, 4, 5, 6, 7 個別為 0, 1, 2, 3 的 HT (其實沒有主副之分,反正原則上都是一組暫存器對應到實體運算單元),那兩個案例就分別佔用 0~3 以及 4~7。 結果呢?兩個案例都能夠使用到原本的 60% ~ 70% 的效能,那兩者相加的情況下,可以到達 120%~140% 的效能!好棒棒! 不過有個重點,那就是『不要一個案例用到超過實體運算單元』的數量!這樣對系統效能比較好!
過去桌機的年代,鳥哥沒有錢~所以買到的 CPU 能超頻就超頻,可以省下好多好多錢!所謂的超頻就是將 CPU 原本的時脈調高的一種技巧!當時很多主機板的 BIOS 都有內建調整 CPU 時脈的功能! Intel 很有趣的是,他讓系統可以自動超頻!CPU 本身就具備超頻的功能!只要作業系統支援就可以!這就是 Intel Turbo Boost 的技術! 對於鳥哥來說,CPU 更高的時脈,代表鳥哥可以節省更多的時間!
不要覺得不怎麼了不起~以鳥哥的一款 E5-2420 v1 CPU (註3)來說,基本時脈為 1.9GHz,但自動超頻最高可達 2.4GHz,如果全部核心都超頻, 那最多也能夠到達 2.2GHz。你以為 1.9 -> 2.2 沒差多少嘛?換算一下百分比, (2.2-1.9)/1.9,可以達到 15.8% 的效能增加耶! 一般的效能調校能夠增加 5~10% 就是很了不起的任務了,turbo boost 隨便就增加了 15% 的效能!能不開嘛?當然要開!對吧!
對於 turbo boost 來說,看 Intel 網頁的說明可能不是很準~因為網頁給的是最大超頻能耐~事實上超頻到多快,還跟整體的功率消耗有關! 越多核心同時超頻的速度越低!同樣以 E5-2620 (6核12緒) 來說,當超頻一個核心時,可以到達 2.4GHz,超頻 2~3 核心可以到 2.3GHz,但超過 4 個以上, 就只能到達 2.2GHz 囉!所以詳細的超頻速度,還是得要實際偵測一下才知道的!
早期電腦的 CPU 就是單核單緒,使用上非常簡單~後來因為多核心 CPU 產生了,於是開始有了可以支援多 CPU 的作業系統, 那就是 SMP (Symmetric Multi Processing)。在這種多處理器的架構下,每個 CPU 的地位都是相同的, 這些 CPU 都連接到同一個共享的主記憶體 (RAM) 上面,也因為如此,因此作業系統的每個 process 都可以在不同的 CPU 上面運作, 而這些 process 也能夠在各個 CPU 之間輪流/交換執行,以期達到 CPU 的負載平衡狀態。
不過,CPU 到記憶體間的距離實在是夠長~導致 CPU 要去主記憶體取得資料時,都會花費很大的時間成本! 強者我同事蔡董大大說過,他們以前在交通大學設計 IC 時,只要能夠將所有的東西都丟進 IC 的話,那速度就是超級快! 不過,這個晶片的空間是有限的,沒辦法包山包海,因此只好讓每個元件獨立了!再透過主機板連接在一塊~ 但是,只要是透過主機板來達成連線,就有速度效能的極限~所以, CPU 只要去記憶體內讀資料,就是會花費不少的時間成本。
因為這樣,因此近來的新型 CPU 設計上,都會在 CPU 晶片裡面放入一些快取記憶體,讓 CPU 常用的資料或指令放置在 CPU 內部的快取記憶體, 這樣 CPU 就可以減少去主記憶體拿資料的時間,以加快系統的效能!相關的 CPU 內的快取記憶體可以下圖來示意:
如上圖所示,CPU 的每個運算單元都有自己的獨立的第一層快取,之後會有跟隔壁的運算單元共享的 L1 與 L2 快取, 之後全部的運算單元會共享第三層快取!如果資料全部都是在第三層快取內,呵呵!那麼 CPU 就不須向主記憶體要資料, 那執行的速度說有多快就有多快!
但是因為單純的 SMP 機制是將所有的 CPU 放在同一個地位上,每個 CPU 運算單元假設都不知道有自己的快取記憶體存在, 而是透過共用主記憶體來操作系統,這樣就讓這些快取記憶體失去基本的功能了!因為所有的資料都會從主記憶體去抓取! 這樣真是太可惜了吧!
所以為了讓系統的效能可以提昇,後來就有所有的非均勻記憶體存取模式 (Non-uniform memory access, 註4)。 NUMA 這個機制最大的特點就是要讓 CPU 盡量讀取自己的非分享的快取記憶體 (集中在 L1/L2 ) ,讓系統效率增加!然後在一段時間後, 在將資料複製到共享的記憶體 (例如第三層快取或主記憶體中)。
除此之外,NUMA 機制也能夠找出實體的運算單元,並且依據運算單元與暫存器之間的關係,來取得 HT 的相關性, 所以 NUMA 能夠將資源平均的放置在不同的實體運算單元上,並且透過非共享的快取記憶體,讓整個效能得到合理的應用!
根據前面提到的,NUMA 其實就是要讓系統的資源得到合理的分配,而我們知道 Intel CPU 的第三層快取通常就是所有的運算單元共享! 而且速度比主記憶體快的多!那現在我們來思考一下,如果你的主機板上面是可以安裝兩顆 CPU 封裝的情況下,或者是可以安裝四顆 CPU 封裝的高階主機板, 那透過 NUMA 機制來考量的話,你就會知道,NUMA 當然會希望讓資料在同一個 CPU 封裝內進行執行,盡量不要讓資料又跑到不同的 CPU 封裝去! 例如底下的圖示案例:
如上圖所示,共可以安裝四顆 CPU 封裝,為了讓效能可以增加,因此 NUMA 就將整個系統的運算資源分為四個節點 (node), 那麼當系統需要進行負載平衡時,大多可以在同一個 node 內進行,感覺上就是在單一 CPU 插槽上面進行資料搬移這樣。 等到過一段比較長的時間,在將資料在各個 node 之間進行同步或複製,以方便程序在這些 node 之間交換。 也就是說,一個插槽可以被視為一個 node,因此單顆 CPU 封裝的主機板,最多就只會有一個 node, 兩顆 CPU 插槽就有兩個 node,以此類推!
不過,就以鳥哥的模式操作行為來說,其實鳥哥的空品資料實在太龐大,L3 快取實在也不夠用~因此, NUMA 對鳥哥來說, 其實是判斷實體核心之間的相關性比較重要!鳥哥是建議啟動 HT 的,那模式的執行又最好不要超過實體運算核心數, 所以該如何判斷實體核心對應的 CPU 編號呢?這就是 NUMA 的重要性!
了解了基本的 CPU 功能 (HT 核心相關行、turbo boost 技術) 以及 NUMA 的架構後,再來總是得要查一下你的系統裡面 CPU 到底這些功能開了沒? 要如何調查?該如何啟動或關閉等等的~來查一查囉!
說實在的,鳥哥好久沒有用過 AMD 的 CPU 了,手邊也沒有相關的比較新的 AMD 的 CPU,所以很抱歉,只能就 Intel 的 CPU 來做個介紹。 上面提到許多 CPU 的功能,其實主要是 HT 技術與 turbo boost 技術,這兩個技術都必須要在 BIOS 裡面啟動才行。 不過在已經開機的系統中,我們還是可以藉由一些工具軟體來查詢的。
最簡單的查詢方式,就是透過 /proc/cpuinfo 搭配 Google 來查詢 CPU 型號的特性。以鳥哥的兩部使用中的設備來說, 如果查看 /proc/cpuinfo 會出現這個情況:
[student@localhost ~]$ cat /proc/cpuinfo processor : 7 vendor_id : GenuineIntel cpu family : 6 model : 58 model name : Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz stepping : 9 microcode : 28 cpu MHz : 1600.000 cache size : 8192 KB physical id : 0 siblings : 8 core id : 3 cpu cores : 4 apicid : 7 initial apicid : 7 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr ..... bogomips : 6784.34 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: |
比較重要的項目有這幾個:
所以由上述的 processor, core id 就能夠對應出來哪兩個 CPU 號碼是使用同一個實體 CPU 運算單元囉。 你也可以簡單的使用底下的指令來查詢實際的對應:
[student@localhost ~]$ cat /proc/cpuinfo | egrep '^processor|^core id' processor : 0 <== 第 0 號 CPU 號碼 core id : 0 <== 第 0 個實體 CPU 核心 processor : 1 core id : 1 processor : 2 core id : 2 processor : 3 core id : 3 processor : 4 <== 第 4 號 CPU 號碼 core id : 0 <== 第 0 個實體 CPU 核心 processor : 5 core id : 1 processor : 6 core id : 2 processor : 7 core id : 3 |
所以使用這個系統為例,鳥哥這個系統共有 4 個實體核心,編號為 0~3,其中 CPU ID 號碼 0, 4 都是對應到同一個 CPU 實體運算單元! 這樣說起來,這個系統確實有啟動 HT 技術,而且我們也找到了實際的 CPU 運算單元囉!理解了吧?
但是在雙插槽的設備中,可能使用上述的指令會出現重複的 core id 喔!因為有兩個插槽之故。所以可能得要變成底下這樣的指令來查詢:
[student@localhost ~]$ cat /proc/cpuinfo | egrep '^processor|^physical|^core id' processor : 0 <== 第 0 號 CPU ID A0 physical id : 0 <== 第 0 號 CPU 插槽 A0 core id : 0 <== 第 0 號 CPU 運算核心 A0 processor : 1 <== 第 1 號 CPU ID B0 physical id : 1 <== 第 1 號 CPU 插槽 B0 core id : 0 <== 第 0 號 CPU 運算核心 B0 processor : 2 physical id : 0 core id : 1 processor : 3 physical id : 1 core id : 1 processor : 4 physical id : 0 core id : 2 processor : 5 physical id : 1 core id : 2 processor : 6 physical id : 0 core id : 3 processor : 7 physical id : 1 core id : 3 processor : 8 physical id : 0 core id : 4 processor : 9 physical id : 1 core id : 4 processor : 10 physical id : 0 core id : 5 processor : 11 physical id : 1 core id : 5 processor : 12 <== 第 12 號 CPU ID A1 physical id : 0 <== 第 0 號 CPU 插槽 A1 core id : 0 <== 第 0 號 CPU 運算核心 A1 processor : 13 <== 第 13 號 CPU ID B1 physical id : 1 <== 第 1 號 CPU 插槽 B1 core id : 0 <== 第 0 號 CPU 運算核心 B1 processor : 14 physical id : 0 core id : 1 processor : 15 physical id : 1 core id : 1 processor : 16 physical id : 0 core id : 2 processor : 17 physical id : 1 core id : 2 processor : 18 physical id : 0 core id : 3 processor : 19 physical id : 1 core id : 3 processor : 20 physical id : 0 core id : 4 processor : 21 physical id : 1 core id : 4 processor : 22 physical id : 0 core id : 5 processor : 23 physical id : 1 core id : 5 |
根據上述的表格資料,我們可以發現到 A0, A1 為相同插槽的相同運算單元,因此 CPU 號碼 0, 12 為同一個插槽的同一個運算單元! 就是互為 HT 技術的兩個同一顆 CPU 核心囉,同理,B0, B1 為另一個插槽的同一個運算核心,所以 1, 13 為另一個插槽的 0 號 CPU 核心, 這樣可以看得懂了嗎?
由於 /proc/cpuinfo 資料量比較多,查詢起來還得要自己判斷核心與編號的對應,很有點討厭。我們可以透過 Linux 系統提供的 numactl 這個指令來呼叫出 CPU 參數喔!不過很多系統預設都沒有安裝 numactl 的,因此你得要自己安裝才行。 安裝超簡單,在 CentOS 6.x 或 7.x 都使用 yum install numactl 即可!裝好之後,你可以使用底下的指令來查詢系統的 CPU 資訊囉!
[student@localhost ~]$ numactl --hardware available: 1 nodes (0) <==只有一個插槽 node 0 cpus: 0 1 2 3 4 5 6 7 <==共有 0~7 個 CPU ID 號碼,對半分兩分 node 0 size: 32632 MB node 0 free: 8247 MB node distances: node 0 0: 10 |
一般來說,cpus 的編號會等份的分成兩個對應部分,因此 0~3 為一組,4~7 為一組,因此 0, 4 為同一個實體核心! 很快就能夠判斷出來。那如果是另一組雙 CPU 插槽的系統呢?那他就會變成這樣:
[student@localhost ~]$ numactl --hardware available: 2 nodes (0-1) <==有 2 個插槽 node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 <==第 0 號 CPU 封裝的 CPU 號碼,對半分兩分 node 0 size: 49106 MB node 0 free: 13742 MB node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 <==第 1 號 CPU 封裝的 CPU 號碼,對半分兩分 node 1 size: 49152 MB node 1 free: 47328 MB node distances: node 0 1 0: 10 20 1: 20 10 |
從上面的資訊來看,第一個 CPU 封裝 (0號) 號碼為 0, 2, 4...到 22 號,對半分兩半,所以 0,12 是同一個核心, 2, 14 是同一個核心, 4, 16 是同一個,以此類推。而 1, 13 則是另一個 CPU 插槽的核心了!這樣是否也很容易判斷呢?
Intel 的 HT 技術算是比較好找出來的資訊,那個 turbo boost 就沒有這麼好找了。 基本上,CentOS 7 預設核心就支援 turbo boost 了,你不用額外進行啥動作。
但是 CenOS 6.x 的版本中,如果你的系統是拿來跑數值模式的,可能你的前輩會跟你說:【千萬不要升級系統】!這也是很無奈的, 因為很多模式的軟體相依問題,會導致升級後你的模式可能會無法運作!所以不要隨便升級系統喔! 因此,雖然新的 CentOS 6.x 預設也支援 turbo boost ,但是舊版的預設就沒有啟動 turbo boost 囉! 因此你得要自己檢查檢查才行。
你的核心得要有相關的模組才能夠支援這個技術的!要如何確認?這樣做就好了!
# 只有 CentOS 6 才需要確認這部分,CentOS 7 預設支援了 [root@localhost ~]# ll /lib/modules/$(uname -r)/kernel/arch/x86/kernel/cpu/cpufreq -rwxr--r--. 1 root root 23328 2016-07-13 02:51 acpi-cpufreq.ko <==這個 -rwxr--r--. 1 root root 40376 2016-07-13 02:51 intel_pstate.ko <==這個 -rwxr--r--. 1 root root 5848 2016-07-13 02:51 mperf.ko -rwxr--r--. 1 root root 12320 2016-07-13 02:51 p4-clockmod.ko -rwxr--r--. 1 root root 18576 2016-07-13 02:51 pcc-cpufreq.ko -rwxr--r--. 1 root root 41576 2016-07-13 02:51 powernow-k8.ko -rwxr--r--. 1 root root 13144 2016-07-13 02:51 speedstep-lib.ko |
上面兩個模組都可以啟用 turbo boost,但是只能啟動一個而已,不可以同時啟動。如果兩個都沒有啟動,那你就可以自由啟動任何一個! 啟動的方式為:【 modprobe acpi-cpufreq 】或【 modprobe intel_pstate 】。要觀察目前啟動的是哪一個模組,可以這樣做:
# CentOS 6 的兩種輸出結果 [root@localhost ~]# lsmod | egrep 'intel_pstate|acpi_cpufreq' acpi_cpufreq 7763 0 freq_table 4936 2 cpufreq_ondemand,acpi_cpufreq mperf 1557 1 acpi_cpufreq [root@localhost ~]# lsmod | egrep 'intel_pstate|acpi_cpufreq' intel_pstate 14628 0 |
上面是兩部不同的系統啟動了不同的模組的情況。基本上,出現上面任何一個畫面都可以視為 turbo boost 已經啟動了! 如果是 CentOS 7 的系統,可能就會變成如下的模樣:
# CentOS 7 的輸出結果 [root@localhost ~]# lsmod | egrep 'intel|acpi' intel_powerclamp 18648 0 intel_rapl 18773 0 acpi_pad 116305 0 acpi_power_meter 18087 0 |
基本上都會出現上述的模組啦!那應該就是與 CPU 時脈自動調整有關的模組。 接下來要來聊聊,那麼這個 CPU 的加速機制中,你需要的是【 CPU 省電模式】 還是【 CPU 效能模式】呢?
在載入了上述的模組後,現在 CPU 的時脈已經可以調整了。不過,某些模組並不會將實際的 CPU 時脈列出在 /proc/cpuinfo 上, 所以你不應該僅查看 /proc/cpuinfo 來確認時脈的。好了,那麼先來看看你目前的 CPU 時脈調整是使用甚麼機制呢? 要查閱 CPU 時脈機制,你應該要安裝如下的軟體才行:
自己使用 yum 去安裝吧!裝好之後你就可以這樣做了:
# 1 先確認一下目前的 CPU 時脈相關設定,i7 3770 CPU [root@localhost ~]# cpupower frequency-info analyzing CPU 0: driver: acpi-cpufreq CPUs which run at the same hardware frequency: 0 1 2 3 4 5 6 7 CPUs which need to have their frequency coordinated by software: 0 maximum transition latency: 10.0 us hardware limits: 1.60 GHz - 3.40 GHz available frequency steps: 3.40 GHz, 3.40 GHz, 3.30 GHz, 3.10 GHz, 3.00 GHz, 2.90 GHz, 2.80 GHz, 2.60 GHz, 2.50 GHz, 2.40 GHz, 2.20 GHz, 2.10 GHz, 2.00 GHz, 1.90 GHz, 1.70 GHz, 1.60 GHz available cpufreq governors: ondemand userspace performance current policy: frequency should be within 1.60 GHz and 3.40 GHz. The governor "ondemand" may decide which speed to use within this range. current CPU frequency: 1.60 GHz (asserted by call to hardware) boost state support: Supported: yes Active: yes |
上面是鳥哥的 i7 3770 CPU 系統上面的輸出情況,系統預設不是使用 intel_pstate 模組,而是使用 acpi-cpufreq 模組, 相當有趣!而這個模組提供了三種 CPU 時脈管理方式,分別是 ondemand, userspace 以及 performance 模式! 目前使用的是 ondemand(用多少算多少)。如果你需要加強系統效能,可能就得要將他改成 performance 模式才對! 另外來看一下,如果是 intel_pstate 模組的結果又是怎樣?
# 1. 另一部雙插槽 CPU 系統的結果 [root@localhost ~]# cpupower frequency-info analyzing CPU 0: driver: intel_pstate CPUs which run at the same hardware frequency: 0 CPUs which need to have their frequency coordinated by software: 0 maximum transition latency: Cannot determine or is not supported. hardware limits: 1.20 GHz - 2.40 GHz available cpufreq governors: performance powersave current policy: frequency should be within 1.20 GHz and 2.40 GHz. The governor "performance" may decide which speed to use within this range. current CPU frequency: 2.20 GHz (asserted by call to hardware) boost state support: Supported: yes Active: yes 2300 MHz max turbo 4 active cores 2300 MHz max turbo 3 active cores 2400 MHz max turbo 2 active cores 2400 MHz max turbo 1 active cores |
輸出的結果差不多,但是可用的時脈機制只有 performance 以及 powersave 兩種,其中 powersave 是比較省電的模式, 所以除非運作的程式會跑很久,否則通常 turbo boost 不會開到太大!所以如果你是真的需要效能的環境, 可能還是得要改成 perforamnce 才對!鳥哥這個系統拿來跑模式,所以已經被鳥哥改成 performance 模式了。 同時訊息也指出,使用 1, 2 顆 CPU 核心時,最大超頻可達 2400MHz,但是 3 顆以上最多只剩下 2300MHz 囉! 這就是 turbo boost 的資訊。
如果你原先的環境是 powersave 想改成 performance 時,怎麼做呢?這樣做即可:
# 2. 更改 CPU 時脈變更機制 [root@localhost ~]# cpupower frequency-set --governor performance |
既然我們說 /proc/cpuinfo 裡面的時脈可能並非真實的時脈,那麼又該如何觀察實際的時脈呢?同樣使用 cpupower 來處理即可! 很簡單的觀測行為!
[root@localhost ~]# cpupower monitor |Nehalem || Mperf || Idle_Stats CPU | C3 | C6 | PC3 | PC6 || C0 | Cx | Freq || C0 | C1-I | C1E- | C3-I | C6-I 0| 0.68| 99.19| 0.00| 0.00|| 0.02| 99.98| 2019|| 0.00| 0.00| 0.02| 0.00| 99.96 4| 0.68| 99.20| 0.00| 0.00|| 0.02| 99.98| 2787|| 0.00| 0.00| 0.00| 0.00| 99.98 1| 36.18| 23.61| 0.00| 0.00|| 2.13| 97.87| 1640|| 0.00| 0.01| 35.43| 25.17| 37.38 5| 36.18| 23.61| 0.00| 0.00|| 0.04| 99.96| 1978|| 0.00| 0.00| 0.00| 0.05| 99.90 2| 0.00| 99.78| 0.00| 0.00|| 0.01| 99.99| 1965|| 0.00| 0.00| 0.00| 0.00| 99.99 6| 0.00| 99.78| 0.00| 0.00|| 0.11| 99.89| 3185|| 0.00| 0.00| 0.04| 0.00| 99.82 3| 0.56| 99.37| 0.00| 0.00|| 0.02| 99.98| 2793|| 0.00| 0.00| 0.00| 0.00| 99.98 7| 0.56| 99.38| 0.00| 0.00|| 0.01| 99.99| 1916|| 0.00| 0.00| 0.00| 0.00| 99.99 [root@localhost ~]# watch -n 2 "cpupower monitor" [root@localhost ~]# watch -n 2 "cpupower monitor -m Mperf" |
單一觀察行為直接輸入 cpupower monitor 即可,如果想要使用類似 top 的功能持續觀察,那就使用 watch -n 2 "cpupoower monitor" 這樣的指令行為來處理即可。
在輸出的資訊中,比較重要的就是在 Mperf 的項目中,那個 C0 代表目前使用的 CPU 資源 (從 0 ~ 100), Cx 則是 CPU 的閒置百分比。另外, Freq 就是目前的實際核心時脈了!其他的項目有興趣的查一下 manual, 否則就直接先略過,光看 Mperf 即可。因此,如果你只想要知道 Mperf 的話,就使用上述的『cpupower monitor -m Mperf』 直接查看 Mperf 即可!
如果覺得上述的指令你都不太喜歡,那麼還可以使用一個名為 i7z 的軟體來觀察喔!不過這個指令 CentOS 官網預設沒有提供! 有興趣的朋友可以到底下的網站來下載自己安裝囉!
如果你安裝好了這個軟體,那麼直接輸入 i7z 就能夠看到類似底下的畫面:
[root@localhost ~]# i7z Cpu speed from cpuinfo 3392.00Mhz cpuinfo might be wrong if cpufreq is enabled. To guess correctly try estimating via tsc Linux's inbuilt cpu_khz code emulated now True Frequency (without accounting Turbo) 3391 MHz CPU Multiplier 34x || Bus clock frequency (BCLK) 99.74 MHz Socket [0] - [physical cores=4, logical cores=8, max online cores ever=4] TURBO ENABLED on 4 Cores, Hyper Threading ON Max Frequency without considering Turbo 3490.74 MHz (99.74 x [35]) Max TURBO Multiplier (if Enabled) with 1/2/3/4 Cores is 39x/39x/38x/37x Real Current Frequency 3861.69 MHz [99.74 x 38.72] (Max of below) Core [core-id] :Actual Freq (Mult.) C0% Halt(C1)% C3 % C6 % C7 % Temp Core 1 [0]: 2275.03 (22.81x) 1 0 1 99.6 0 33 Core 2 [1]: 1674.44 (16.79x) 1 1.69 1 97.1 0 29 Core 3 [2]: 3809.78 (38.20x) 1 0 1 99.8 0 32 Core 4 [3]: 3861.69 (38.72x) 0 0.00312 0 100 0 31 C0 = Processor running without halting C1 = Processor running with halts (States >C0 are power saver) C3 = Cores running with PLL turned off and core cache turned off C6 = Everything in C3 + core state saved to last level cache Above values in table are in percentage over the last 1 sec [core-id] refers to core-id number in /proc/cpuinfo 'Garbage Values' message printed when garbage values are read Ctrl+C to exit |
裡面特別提到 CPU 的時脈 (外頻與倍頻),由於這部系統僅有 4 個實體運算單元,因此就僅列出 4 個相關的資訊。 比較需要注意的是實際時脈、C0%(實際運作的 CPU 百分比),以及 Temp (CPU 的核心溫度),這些資訊對管理員來說, 那就重要了吧!哈哈!所以鳥哥覺得 i7z 還算是很好用的一個工具軟體哩!
現在來測試一下,到底 CPU 有沒有啟動 turbo boost 的技術?以及是否使用到了 HT 的技術這樣。因為我們想要操 CPU, 所以讓 CPU 來算 pi 可能是個不錯的方案~現在請你開啟三個終端機視窗,分別進行:
現在請下達底下的指令,來看看你的系統會出現什麼事情?
[student@localhost ~]$ time echo "scale=3000; 4*a(1)" | bc -lq
|
如果單純使用上述的指令,而且你沒有執行其他額外的指令,那你會發現到,運算的 CPU 似乎會自己找到最佳化的位置, 而且可能會變來變去~不會一直使用同一顆 CPU 運算核心啦!那麼分數與 CPU 時脈會有什麼關係呢? 在鳥哥的 i7 3770 系統中,鳥哥利用上述指令算出來的時間是這樣的:
你會覺得 performance 與 ondemand 差不多,但是實際上觀察 CPU 時脈,會發現閒置時 CPU 的時脈顯示中, performance 的時脈永遠都留在高檔 (2500MHz以上), 但是 ondemand 在 CPU 閒置時,會自動降頻到大約 1600~2000MHz 左右。所以看起來,如果你需要高效能,而且你的環境也不缺電,那麼使用 performance 沒啥問題! 不過如果省電是你的考量,那麼使用預設的 ondemand 可能是最好的選擇喔!
為了達到效能最大化,所以底下鳥哥使用的是 performance 這個 CPU 時脈機制喔!而且建議你不要使用 powersave 這個機制啦!效能太差!
現在讓我們寫一隻腳本來測試系統的效能!因為我們的系統有 4 個實體核心,所以底下我們需要『同時』運作 4 個 pi 的計算~ 這時透過 shell script 會是比較簡單的方式!
[root@localhost ~]# vim cpupi.sh
#!/bin/bash
for i in 0 1 2 3
do
time echo "scale=3000; 4*a(1)" | bc -lq &> /dev/null &
done
|
全部丟進系統去跑,很有趣的是,鳥哥持續運作數次,每次運作的 CPU 都不同,但是都能剛好使用到四個實體的 CPU !這算是好事好事! 只是雖然如此,每次使用的 CPU ID 還是不會相同!算出來的數據跟單一核心不太相同!因為 turbo boost 說驅動四個實體核心時,最高超頻到 3700MHz, 而不是單一核心的 3900MHz,所以四顆算完的分數為 5.24 秒左右~
好了,那如果上述的腳本中,那個『 for i in 0 1 2 3 』後面又多加一個,變成『 for i in 0 1 2 3 4 』,同時跑 5 個計算呢? 算出來的結果會怎樣?你會以為有 3 個很快,有 2 個會變得比較慢 (因為共用核心) 對吧?其實不然喔!鳥哥多次計算的結果,時間分佈在 5.5 ~ 6.8 秒左右, 而且每個 CPU 開始會亂跑!這是因為系統有使用某些特別的機制 (後面介紹) ,因此會讓努力讓 CPU 保持在『隨時都可以平衡』的狀態! 透過這個機制,每個程序的時間都會比較相近 (至少保持平頭式的平等就是了!)。
如果你想要指定某些特定的 CPU 幫你執行程序,那就得要使用 numactl 這個指令了 (透過 yum 安裝 numactl 軟體),讓我們修改一下 cpupi.sh 這隻腳本:
[root@localhost ~]# vim cpupi.sh #!/bin/bash for i in 0 1 2 3 do time echo "scale=3000; 4*a(1)" | numactl -C ${i} bc -lq &> /dev/null & done |
我們先指定 4 個程序來執行,現在你丟進系統跑的時候,每支程序就會固定由某個 CPU 去運作了!算出來的時間也差不多在 5.24 左右! 但如果透過指定的方式來執行 5 個程序,你就會發現到有 3 個程序跑出一模一樣的 5.24 秒,但是有兩個程序跑到了 8.3 ~ 8.4 秒左右! 雖然 CPU 保持在 100% 的運作情況,不過兩個 pi 使用到同一個核心時,並不會是加總 (5.24+5.24=10.5) 的秒數,還是有比較快些!這就是 HT 的能力!
透過上面的測試,你會知道,其實 4 核 8 緒的 CPU 環境中,並不是每個 CPU ID 都是獨立存在的!其實是有兩組共四對運算核心! 如果你對於系統的操作是跟鳥哥一樣,需要大量的運算環境!鳥哥建議還是自己指定 CPU 來運算比較好!讓系統自己計算平衡時, 由於許多的資料會在 CPU 之間搬移,還是會損耗一些時間成本(這在 pi 的計算當中看不太出來)!鳥哥近來在模式的運算上,漸漸傾向於自己指定 CPU ID 囉! 至少資料不會亂跑~在資料交易時,會節省很多寶貴的時間。
你可能會問,既然 HT 技術其實使用的也只是同一個運算核心~那麼有沒有 HT 有差別嘛?這個問題其實我們可以簡單的使用 pi 計算來了解喔! 首先,讓我們來算一個單一核心的 pi 吧!
[root@localhost ~]# vim cpupi.sh #!/bin/bash for i in 3 do time echo "scale=3000; 4*a(1)" | numactl -C ${i} bc -lq &> /dev/null & done |
上述指令算出來的結果大約是在 4.98~5.00 秒之間~這是單一 pi 的計算~好!讓我們來同時放兩個 pi 在同一個 CPU ID 上面! 如同上面的指令,依舊丟在 CPU ID 3 上面吧!
[root@localhost ~]# vim cpupi.sh #!/bin/bash for i in 3 3 do time echo "scale=3000; 4*a(1)" | numactl -C ${i} bc -lq &> /dev/null & done |
你應該會發現到 top 上面出現兩個 50% 使用率的 pi 啊!沒辦法達到 100% 了!而且,算出來的結果大約是 10.03 秒左右~ 差不多就是兩倍 pi 的時間~這樣看是很合理啦!現在將兩個 pi 計算丟在 3 與 7 號的 CPU ID 上面,我們知道 3, 7 這兩個號碼共用同一個運算核心的喔!
[root@localhost ~]# vim cpupi.sh #!/bin/bash for i in 3 7 do time echo "scale=3000; 4*a(1)" | numactl -C ${i} bc -lq &> /dev/null & done |
有趣了!你會發現 3, 7 號的 CPU ID 都是 100% 去跑~跑出來的結果大約是 8.08 秒左右~ 因為共用運算核心,所以雖然是兩個看起來獨立的 CPU,但是就是無法達到 5 秒跑完~但是有趣了!它也不是兩倍時間的 10 秒! 而是 8 秒左右~若以 10 秒為基準,那麼 HT 節省了 20% 的時間耶!怪不得某些文章說,HT 可能會有 10%~30% 之間的效能增長! 這樣簡單的測試,你可以理解 HT 的好處了嘛?
早期的 Linux 因為要讓 CPU 的負載能夠平衡,所以會使用一個稱之為 irqbalance 的機制,讓所有的 process 在 CPU 之間輪流運作! 不過早期的 irqbalance 很笨,不太會區分不同的 CPU ID 是否為同一個實體核心,只會考量 CPU ID 而已。因此有的時候 irqbalance 運作後, 反而會讓許多的程序卡在同一個實體核心中,造成系統效能的低落。
不過就上面的測試來看,現在 CentOS 6.8 以後的系統,irqbalance 似乎變聰明了,會自己判斷實體核心的所在處,盡量讓不同的程序分散到不同的實體核心去跑, 所以看起來效能還算相當不錯。
但就雙 CPU 插槽的系統來看,光是 irqbalance 判斷是否為實體核心還是比較弱一些~如果能夠讓系統自己在 numa 的架構下盡量減少錯誤的記憶體讀取時, 效能會再增加一些的。你當然可以幾使用 numactl 去指定執行的 CPU 核心,不過如果每支程式你都得要指定,那就傷腦筋了! 這時鳥哥建議你啟用 numad 這個程序即可!
不過需要注意的是,如果是單插槽 CPU 的系統架構,那麼使用 irqbalance/numad 應該是差異不大! 有沒有變動都不會差很多。但如果是雙 CPU 插槽,那就真的建議要將 irqbalance 關掉,改成 numad 囉!
如果你一開始下達的指令中,分配給 CPU 的運算錯誤了!那該如何是好?中斷程式?如果這個程式已經運算好一陣子了,重新執行實在很浪費時間! 有沒有辦法在程序運作的情況下,重新變更程序的 CPU ID 呢?可以的!透過 taskset 即可!讓我們來執行一下底下的程式好了!
[root@localhost ~]# vim cpupi.sh #!/bin/bash for i in 0 1 2 3 do time echo "scale=6000; 4*a(1)" | numactl -C 0 bc -lq &> /dev/null & done |
鳥哥故意將運算的時間拉長 (3000 變成 6000,時間增加好幾倍不只兩倍!),然後錯誤的將所有的程序都丟到第 0 號 CPU 去!執行看看! 你會發現到 CPU 0 忙的要死~在 top 內的四個 bc 卻只有 25% 的使用率...
怎麼辦呢?沒關係~你可以先透過『 ps -eF 』找出程序與 CPU ID 的關係,然後再透過 taskset 來處理即可!
# 1. 先找出 CPU 與程序的關係 [root@localhost ~]# ps -eF UID PID PPID C SZ RSS PSR STIME TTY TIME CMD root 19765 19759 21 3252 956 0 13:40 pts/2 00:00:01 bc -lq root 19767 19760 21 3252 956 0 13:40 pts/2 00:00:01 bc -lq root 19769 19761 21 3252 952 0 13:40 pts/2 00:00:01 bc -lq root 19770 19763 21 3252 956 0 13:40 pts/2 00:00:01 bc -lq # 2. 將不同的程序丟到不同的 CPU ID 去! [root@localhost ~]# taskset -cp 1 19767 pid 19767's current affinity list: 0 <== 將 0 號改成 1 號 CPU 去執行囉! pid 19767's new affinity list: 1 [root@localhost ~]# taskset -cp 2 19769 pid 19769's current affinity list: 0 pid 19769's new affinity list: 2 [root@localhost ~]# taskset -cp 3 19770 pid 19770's current affinity list: 0 pid 19770's new affinity list: 3 |
其實比較重要的是 ps -eF 輸出的 PID 與 PSR 這兩個參數,一個是 PID 一個是 CPU ID 號碼~然後透過 taskset 就能夠更改 CPU 的執行囉! 現在你也能夠控制系統 CPU 了!有夠愉快吧!!哈哈!
高效能電腦也經常拿來作為虛擬化的基礎系統,而我們知道虛擬化系統使用的 CPU 當然是透過實體 CPU 啊!而你的虛擬機器的 CPU 通常就是使用 irqbalance 或者是 numad 進行動態調整,因此 VCPU 使用到的實體 CPU 其實是經常變動的。而因為 numad 的關係,通常不會讓你的 VCPU 使用到相同的實體運算核心啦! 所以通常你只要開啟 numad 讓它幫你調整就好~
如果你是效能癖,那啟動虛擬機器時,最好能夠調整一下你的 xml 檔案內的 CPU 設定!最重要的是一行 CPU 使用實體 CPU 的設定值! 『 <cpu mode='host-passthrough'></cpu> 』這樣讓你的虛擬機器能夠直接看到實體機器的 CPU,這樣的效能才會最佳化!
但是,如果你需要讓虛擬機器的 VCPU 與實體機器的 CPU 對應起來~舉例來說,鳥哥這部 i7 3770 的機器上面跑一個虛擬機器,裡面用到了 4 顆 VCPU, 我可以這樣觀察 VCPU 與實體 CPU 的對應喔:
# 1. 觀察一下虛擬機器的 CPU 對應,這裡假設我的虛擬機器名稱為 linux 喔!: [root@localhost ~]# virsh list Id 名稱 狀態 ---------------------------------------------------- 2 linux 執行中 [root@localhost ~]# virsh vcpuinfo linux VCPU: 0 <==虛擬機器的 CPU 號碼 處理器: 2 <==實體機器的 CPU 號碼 狀態: 執行中 處理器時間: 16.4s 處理器的同屬: yyyyyyyy VCPU: 1 處理器: 0 狀態: 執行中 處理器時間: 10.6s 處理器的同屬: yyyyyyyy VCPU: 2 處理器: 4 狀態: 執行中 處理器時間: 0.1s 處理器的同屬: yyyyyyyy VCPU: 3 處理器: 3 狀態: 執行中 處理器時間: 0.1s 處理器的同屬: yyyyyyyy |
結果讓人大吃一驚!實體 CPU 使用到的竟然是 2, 0, 4, 3,我們知道 0, 4 是同一顆 CPU 運算核心啊!所以這樣的結果會讓虛擬機器的效能變差! 雖然上述的結果是會一直變更的~所以有的時候就會正常,有的時候就會不正常~唉啊!頭好疼啊~怎辦啊?沒關係,我們可以透過一個對應的指令來解決這個問題:
# 2. 讓虛擬機器的 CPU 綁定實體 CPU [root@localhost ~]# virsh vcpupin linux 0 0 [root@localhost ~]# virsh vcpupin linux 1 1 [root@localhost ~]# virsh vcpupin linux 2 2 [root@localhost ~]# virsh vcpupin linux 3 3 [root@localhost ~]# virsh vcpuinfo linux VCPU: 0 處理器: 0 狀態: 執行中 處理器時間: 120.6s 處理器的同屬: y------- VCPU: 1 處理器: 1 狀態: 執行中 處理器時間: 337.0s 處理器的同屬: -y------ VCPU: 2 處理器: 2 狀態: 執行中 處理器時間: 0.1s 處理器的同屬: --y----- VCPU: 3 處理器: 3 狀態: 執行中 處理器時間: 0.1s 處理器的同屬: ---y---- |
不過根據鳥哥測試的結果,有時候你還是得要先關閉 numad 然後執行對應後再啟動 numad 這樣才會正確的對應到 VCPU 與 CPU! 經過這樣的簡單的舉動,你的虛擬機器可能會有很大的進步喔!畢竟虛擬機器比較笨,他不會知道是否用到同一個核心~而實體機器有時候很忙, 也沒有辦法理解虛擬機器對應的 CPU 是否有最佳化~所以某些時候為了取得比較好的操作經驗,還是得要處理一下 CPU 的對應比較好!