1. 程式人生 > >看上去很美--超執行緒

看上去很美--超執行緒

現在的大端(位元組序)微處理器擁有雙核或者更多核已經不是一個新聞了。 多執行緒應用利用多核的的優勢,能同時執行多個執行緒。 如果你在一個四核的處理器上執行一個四執行緒的程式,你的程式很可能獲得四倍的效能。有些處理器則通過在一個核上同時執行多個執行緒的方式更進一步的利用多執行緒的優勢。 這就是Inter所謂的“超執行緒”。 例如: Intel 酷睿I7處理器擁有4個核卻能讓8個執行緒同時執行--每兩個執行緒公用一個核。 顯而易見的是同一時刻能同時執行的執行緒越多, 單位時間內你能完成的工作就越多。 但有一個問題,其實執行在同一個核上的兩個執行緒在競爭同樣的資源。如果這兩個執行緒都只得到了一半的資源, 那麼超執行緒帶來的收益就為0.  兩個執行緒以一半的速度執行帶來的收益不會比一個執行緒全速執行帶來的收益多。

為了觀測超執行緒其中一個執行緒到底能跑多快,我曾對超執行緒做個一些實驗。 以下是超執行緒之間共享的資源列表:
1. 快取
2. 程式碼分支預測資源
3. 指令讀入和解碼資源
4. 執行單元
如果以上任意資源成為了執行緒執行速度的限制因素, 那麼超執行緒將毫無優勢, 反正則超執行緒大有用武之地。 具體而言, 在如下的情況下超執行緒是很好的選擇。
1. 記憶體資料過於分散, 以至於不管執行緒是使用全部cache還是一般的cache, cache命中率都很低。 這樣的話, 超執行緒能使一個執行緒在等待沒有命中cache的資料調入的同時讓另一個執行緒繼續使用執行單元 。
2. 不管執行緒是使用全部或部分的程式碼分支預測資源, 都有大量的分支預測錯誤。 這樣的話, 超執行緒能在一個執行緒在等待指令讀入的過程中讓另一個現實使用執行單元。
3. 程式碼中有大量長依賴鏈(long dependency chains 是啥?)阻止了執行單元的高效利用。

在以上情況下, 超執行緒將獲得小於100%的收益。 超執行緒的不會是效能翻倍, 而只是讓效能有所增長, 比如25%。 另一方面, 如果諸如指令讀取, 記憶體讀取或者乘法單元,成了程式執行速度的瓶頸, 那麼超執行緒將不會提高效能。實際在, 在最壞的情況下, 由於執行緒間資源的競爭, 超執行緒甚至會降低程式的效能。只需要google一下, 你就會找到大量禁止超執行緒,程式效能不降反升的案例。

我在兩種處理器上對超執行緒進行了測試--Intel 酷睿I7和Intel Atom。 I7擁有四核, 處理器相當強大。每一個核的執行單元都效能強大,以至於很少有一個執行緒能耗盡其所有潛力。 看上去讓一個核同時執行兩個執行緒是個不錯的注意。 可惜的是,I7的指令讀取單元沒那麼強大, 即使在單執行緒情況下也可能成為程式的瓶頸。 開啟超執行緒後, I7能同時跑8個執行緒, 在特定的用例下, 效能提高顯著。 但是,到底有多少程式能使8個執行緒同時跑滿呢?
Intel Atom 相比而言就沒那麼強大了, 這種處理器一般用在小筆記本和嵌入式環境中。 他只擁有兩個核, 最多能讓四個執行緒同時執行。他的執行單元遠沒有I7那麼大,聽起來讓兩個執行緒共享這個本來就捉襟見肘的執行單元不是一個怪誕的主意。 這個主意的原因是Atom缺少大處理器所擁有的out-of-order capabilities 。 當執行單元在等待不在cache中的資料讀入或者其他的長延時事件時,除非有另一個執行緒可以繼續調入工作, 否則執行單元被白白浪費。

關於以上處理器的詳盡介紹,請移步我的處理器架構手冊www.agner.org/optimize/#manuals.

明顯, 讓程式設計師直接去判斷超執行緒對一個特定的程式是否有收益不是一件容易的事情。 判斷這個問題得最穩妥的方法是進行測試。 理論上,開啟和關閉超執行緒的對比測試應該在不同的處理器和不同的資料集上分別進行。這對開發者而言確實是一個沉重的負擔, 估計沒有幾個程式要願意花這麼多時間和財力在測試超執行緒對他的程式的影響上。

如果說超執行緒並沒有看上去那麼美好, 這就引發了第二個問題--怎麼關閉超執行緒? 教會使用者如何才BIOS啟動程式中關閉超執行緒不是一個明智的選擇, 小白使用者們可能根本不會, 也不是所有的BIOS都支援設定,而且關掉超執行緒還可能對該計算機上跑著的其他程式造成不好影響。 程式設計師需要將“避免超執行緒”這個功能放到他的程式中去。 首先程式需要判斷它執行所在的計算機是否開啟了多執行緒。 最新的Windows版本提供了獲取該資訊的系統呼叫(what?),而在linux環境中你就只能去讀配置檔案了。 如果檢測到開啟了超執行緒,那麼只將自己的程式繫結到編號是偶數的邏輯核上去,這樣能避免執行緒來競爭同一個物理核上的資源。
不幸的是, 你阻止不了作業系統利用這些空閒的邏輯核來做一些事情。讓處理器嚴格的使一個執行緒的優先順序高於另一個執行緒是不可能的(why), 有時候作業系統會讓兩個優先順序差別明顯的執行緒跑在同一個處理器上,這時候低優先順序的執行緒會偷走高優先順序執行緒的資源(甚至造成優先順序反轉)。 這一點即使在最新的WINDOW7系統上我也發現了。不讓不同優先順序的執行緒跑在同一個核上是作業系統應該完成的功能(不懂), 可惜作業系統的設計者們目前還沒有完全解決這一的問題。

程式設計師所需要的是一個系統呼叫, 這個系統呼叫能告訴作業系統我不想讓每一個核上跑超過一個執行緒並且我也不想和別的任何程式分享我所佔用任意一個核。 可是據我所知這樣的系統呼叫迄今為止沒有作業系統有提供。

除了Intel外別的處理器廠商也使用超執行緒。 事實上有傳聞AMD將在他們未來的處理器上增加超執行緒的功能。超執行緒確實能讓處理器跑出更漂亮的測試資料, 這是說服小白使用者們選擇他們處理器的一大賣點。 但是處理器設計者們也要考慮到沒有多少使用者能準確的運用超執行緒。 這個技術將抉擇的重擔轉移到了軟體開發者和作業系統設計者身上。我很懷疑如果將處理器上用於實現超執行緒的矽空間用於實現別的功能,是不是反而會使一個更好的選擇?