Microarchitecture: HyperThreading(超线程)
線程并行
當代的軟件趨向于運行在多線程模式,或者是并行處理。網絡包傳輸和web服務可以運行以多線程的方式運行以達到更高的性能。甚至是桌面應用也開始增加并行性。Intel架構師已經開始嘗試利用TLP( thread-level parallelism) 線程并行性,用來在較少的晶體管和功耗下就能達到更高的性能。
高端和終端的服務器市場,多核已經被廣泛的使用,已獲得更高的性能。通過增加處理器,應用可以通過在更多的處理器上運行更多的線程已達到更高的性能。這些線程可能屬于同一個應用,也可以屬于不同的應用。多核系統已經被使用多年,高端程序員已經可以熟練的利用多核來達到更高的性能。
近幾年,大家討論了一些提高TLP的技術,也提出了產品。比如CMP(chip multiprocessing),兩個處理器被放到了一個die上。這兩個處理器都各自擁有完全的組件和架構資源。處理器之間可以共享更大的片上cache。 CMP和傳統的多核系統基本無關,你可以在傳統的多核系統上使用CMP芯片。然而,CMP chip 將會比單核chip面積上大的多,因此造價更高。并且這也沒有解決die的面積和功耗問題。
另一種方法就是通過線程切換,允許單核去執行多線程。通過時間片切換,實現多線程切換。然而這將導致多余的執行,但是可以有效地減少訪問memory導致的latency。如果多線程基于event切換,那么當多線程遇到cache miss的情況時,可以有效地減少latency。這個方法對于大量cache miss 和執行類似任務的線程很有效。但是時間片或者是基于event切換都沒有實現提高資源的利用效率,比如分支預測失敗和指令依賴。
最終,可以用過單核,不切換的方式實現多線程。線程可以同時執行,以更高效的利用資源。這個方法可以最大資源的利用效率。在單位晶體管和功耗時,實現了性能的最大化。
Hyper-Threading 技術為intel 架構提出了多線程的方法。這篇文章我們將要討論在Xeon 處理器家族中,Hyper-Threading技術的首次應用。
Hyper-Threading技術架構
Hyper-Threading 在單個物理處理器上實現了多個邏輯處理器。我們為每一個邏輯處理器都做了一份architecture 狀態的拷貝,邏輯處理器之間共享物理執行資源。從軟件到架構的角度,這意味著操作系統或者是用戶的程序可以像在多核處理器上調度多線程一樣,在單核上調度多線程。從微架構的角度,這意味著邏輯處理器將會在共享的執行資源上執行不同線程的指令。
圖2展示了多核系統上,兩個沒有采用hyper-threading技術的物理核心。圖3展示了采用了hyper-threading技術的多核系統。通過在每個物理核心上實現兩份邏輯核心狀態的備份,系統就看起來有四個邏輯核心。
Hyper-Threading 技術首次實現在Xeon家族的雙處理器和多處理器服務器上。通過有效地利用更多的處理器資源,Xeon 處理器產品可以有效地提高性能。Hyper-Threading技術增加了小于5%的芯片面積和功耗,但是提供了更多的性能。
?
?
每一個邏輯處理器都維持一份完整的架構狀態。架構狀態包括寄存器(通用寄存器,控制寄存器和中斷控制寄存器以及狀態寄存器)。從軟件的角度看,一旦架構狀態有多份,那么處理器可以虛擬的看成兩個處理器。存儲架構狀態的寄存器的晶體管的數量是非常小的。邏輯處理器之間基本上共享了所有的資源,比如cache,執行單元,分支預測,控制邏輯以及總線。
每個邏輯處理器都擁有自己的中斷控制器,因此中斷可以發送給指定的邏輯處理器,并且準確的被相應的處理器處理。
Hyper-threading 技術在Intel Xeon 產品中的首次應用
在Xeon產品中實現Hyper-Threading技術時,預先設定了幾個目標。其中一個是在實現Hyper-Threading的同時最小化die的面積。因為邏輯處理器共享了主要的微架構資源,僅僅有少部分結構被復制,因此實現該技術的面積占用了全die面積不到5%。
第二個目標是當一個邏輯處理器阻塞時,另一個邏輯處理器可以繼續工作。一個邏輯處理器可能會因為cache miss,處理branch預測失敗和等待依賴的指令執行完畢而暫時的阻塞一段時間。獨立的前向工作流應當保證在兩個線程同時執行時,沒有邏輯處理器可以占用全部的資源。這是通過劃分或者限制每個thread可以擁有的資源數量實現的。
第三個目標是單線程軟件在hyper-threading處理器上運行時應當擁有和普通處理器一樣的速度。這意味著,如果單線程運行在處理器上,那么它將擁有全部的資源。從更高的角度看,微架構的pipeline如figute4所示,其中緩沖隊列將pipeline分割。Queue要么被對半分,要么被復制,以保證每個線程都可以獨立的前行。
?
接下來的章節我們將會梳理pipeline,討論一下主要的功能,并且闡述資源的共享與復制。
Frond End 前端
流水線的前端負責將指令傳輸給后續的pipe 階段。如圖5-a所示,指令最初從Execution Trace Cache(TC)或者L1 指令cache中獲得。圖5-b表明只有TC miss的時候,cpu才從L2 Cache中取指,譯碼。靠近TC的是微指令ROM(Microcode ROM),存儲為較長,較復雜的IA-32指令存儲譯碼過的微碼。
?
Execution Trace Cache (TC)
TC存儲譯碼過的指令,也稱作微指令。大多數程序中的指令都是從TC中取出并執行的。獨立的兩組指令PC用于追蹤各自的線程的執行。兩個邏輯處理器可以每周期仲裁一次,以獲得TC的所有權。如果兩個邏輯處理器在同一時刻擁有權限,那么將會仲裁給一個,在下個周期仲裁給另一個。比如,如果兩個邏輯處理器都請求trace cache的權限,第一個周期為一個邏輯處理器取指令,那么下一個周期則為另一個處理器作用。如果一個邏輯處理器阻塞了,不能夠使用TC,那么另一個邏輯處理器將可以每個周期都全帶寬的訪問TC。
TC Entry被線程信息所標記,并且可以按照需要動態的分配。TC結構為8路組相連,使用LRU替換算法。共享的特性可以使一個邏輯處理器在需要的情況下,擁有比另一個更多的Entry。
Microcode ROM
當遇到了復雜的指令時,TC發送一個微指令指針給Microcode ROM。Microcode ROM將會控制取微碼,然后將控制權返回給YC。兩個邏輯處理器擁有各自獨立的微指令指針。
邏輯處理器也共享Microcode ROM。訪問Microcode ROM的權限在兩個邏輯處理器之間切換。
ITLB 和 分支預測
如果TC miss,將會從L2 Cache中取指,解碼為微碼后,存入TC中。ITLB接收到來自TC對指令的請求,ITLB將下一條指令的地址(PC)翻譯為物理地址。請求被發送給L2 Cache,并得到來自L2 Cache的響應。這些指令將會存放在streaming buffer,直到他們被譯碼。
在hyper-threading中,ITLB被復制了兩份。每個邏輯處理器有它自己的的ITLB,而且都有自己得一套指令指針,以追蹤程序的PC。取指邏輯負責向L2 Cache發送請求,它會基于先來先處理的準則,對取值邏輯進行仲裁。一般會為兩個邏輯處理器至少處理一個請求。因此,兩個邏輯處理器可以同時有pending的取指。
每個邏輯處理器都有一套64-byte的stream buffer,為指令解碼階段緩存指令。ITLB和streaming buffer都是較小的結構,因此這個結構的復制對die的面積占用較小。
分支預測結構可以是復制的或者共享的。用于預測返回指令地址的Return stack buffer也被復制了,因為這是一個非常小的部件,并且call/return pair的預測根據獨立的線程進行預測會更加準確。BHB(分支歷史緩存)用于在global history array中為每個邏輯處理器查找全局歷史。然而,因為global history array很大,因此這是一個共享結構,其內部項會被邏輯處理器ID號打上tag。
IA-32 指令譯碼
IA-32 指令是譯碼起來是非常笨重的,因為指令是變長的,并且有不同的選擇。譯碼將會花費大量的邏輯和臨時狀態。幸運的是,TC 會命中大部分的uop,因此我們只需要在TC miss的時候譯碼。
譯碼邏輯從stream buffer中取出指令,將其譯碼為uop。當兩個線程同時譯碼時,stream buffer會在線程之間切換,因此線程會共享譯碼邏輯。譯碼邏輯需要為兩個線程保存中間狀態,即使它只為一個邏輯寄存器譯碼。總體上說,在切換到另一個邏輯處理器之前,會有另一個邏輯處理器的幾條指令被譯碼。我們會基于die的大小以及復雜性來確定邏輯處理器切換的顆粒度。當然,如果只有一個邏輯處理器需要譯碼,那么它會占據全部的譯碼帶寬。譯碼指令將會被寫入TC,并forward到uop隊列中。
Uop隊列
Uop來自以下三個來源:
Uop會被放置到uop queue中。這個queue將front-end即前端和亂序執行執行單元解耦。Uop queue根據邏輯處理器分為兩半。切換使得邏輯處理器可以有獨立的forward邏輯,不會因為另一個邏輯處理器的TC miss或者是執行單元的暫停而阻塞。
亂序執行單元
亂序執行單元由分配、寄存器重命名、調度和執行單元組成,如圖6所示。這部分亂序的執行指令。一旦他們的輸入準備好,就立刻執行,而不考慮原本的程序中的指令順序。
?
分配
亂序執行單元有緩沖buffer用于執行重排序,跟蹤和順序操作。分配器從uop queue中取出uop,然后分配執行uop所需要的buffer。緩沖buffer包括 126項重排序buffer, 128個整數和128個浮點物理寄存器,48個load 和 24個store 項buffer。我們拆分了其中的幾個重要buffer,所以每個邏輯處理器可以最多使用其中的一半數目。比如,邏輯處理器最多可以使用63個re-order buffer,24個load buffer和12個store buffer。
如果兩個邏輯處理器在uop queue都有uop要處理,分配器將會每個周期都為邏輯處理器切換。如果邏輯處理器已經使用了它所分配的資源的上限,那么分配器將會向這個邏輯處理器發送一個暫停信號,而后為另一個邏輯處理器分配資源。如果uop queue中只包含一個邏輯處理器的uops,那么分配器將會每個周期都為這個邏輯處理器繼續分配資源,以優化分配帶寬,盡管還需要滿足資源上限條件。
通過限制關鍵buffer的資源占用限制,可以公平的對待每個邏輯處理器并且避免死鎖。
寄存器重命名
寄存器重命名將IA-32寄存器命名為物理寄存器。這將會使8個通用IA-32整數寄存器變為動態可調節的128個物理寄存器。重命名邏輯通過寄存器重命名表格(RAT)以追蹤最新的架構寄存器。這樣新來的指令就可以明確其操作數架構寄存器對應的物理寄存器。
因為邏輯處理器需要維護并追蹤自己的完整的架構狀態,因此我們為每一個邏輯處理器都設置了一個RAT。重命名過程與上述的分配邏輯并行執行。因此分配器和寄存器重命名會同時處理相同的uops。
一旦uops已經完成了分配和寄存器重命名,他們就會被分配到兩組queue中,一組作用域寄存器操作(load and store),另一組負責所有的其他操作。這兩組queue分別叫做存儲指令隊列和通用指令隊列。這兩組隊列也被切分,每個邏輯寄存器最多使用一半。
指令調度
指令調度是亂序執行的關鍵所在。五個uop調度器用于在不同的執行單元之間調度不同類型的指令。每周期可以最多派發6條uops。如果uops的輸入操作數準備好了,并且執行單元已經空出,可以使用,那么調度器將會選擇哪個uops可以開始執行。
存儲指令隊列和通用指令隊列會盡快的將uops發送到五個調度隊列。如果需要的話,會每周期為邏輯處理器切換操作。
每個調度器都有自己的8項到12項的調度隊列。調度器從調度隊列中選擇uops,發送給執行單元。調度器不會基于uops究竟屬于哪一個邏輯處理器來選擇uops。也就是說,調度器無視邏輯處理器。Uops可以僅僅根據輸入操作數和執行單元而被選擇。舉個例子,調度器可以同時分配兩個邏輯處理器額各自兩條uops。為了避免死鎖,并且保證公平,我們隊邏輯處理器在調度隊列中的數目上限進行了設置。這個上限值取決于調度隊列的大小。
執行單元
執行單元和存儲層次也不會區分不同的邏輯處理器。因為源寄存器和目標寄存器已經在同一個物理寄存器池中被重命名,因此uops僅通過讀取物理寄存器文件可以知道其目標寄存器對應的物理寄存器。通過比較物理寄存器的編號就可以將操作結果forward給其他的uops,而不需要明確邏輯寄存器號。在執行之后,uops被存放到重排序緩沖中。重排序緩沖將執行階段和retire階段解耦。重排序緩沖為每個邏輯處理器各分一半。
退休單元
Uop退休邏輯將會按照程序的順序改變架構狀態。退休邏輯會追蹤兩個邏輯處理器中的待退休指令。然后通過在兩個邏輯處理器之間切換,并按照程序的順序提交、改變架構狀態。退休邏輯會為一個邏輯處理器退休uop,然后切換到另一個。如果一個邏輯處理器一直沒有準備好退休uop,那么退休單元會全力退休另一個邏輯處理器。
一旦store退休,store的數據需要被寫入第一級data cache。選擇邏輯會在邏輯處理器之間切換,以將數據存儲到cache中。
Memory 子系統
Memory子系統包括DTLB,L1 data cache , L2 data cache 和L3 data Cache(L3 cache只在Xeon處理器中有)。對memory子系統的訪問也不考慮邏輯處理。存儲子系統只是來了請求,就處理。
DTLB
DTLB將邏輯地址翻譯為物理地址。它是64路全相連。每一項可以映射4K或者4M page大小。盡管DTLB是兩個邏輯處理器中共享的結構,但是每一項都會包含一個處理器ID。每個邏輯處理器都有自己的一個保留寄存器以保證公平性和在DTLB miss時,進行forward。
L1 Data Cache, L2 Cache,L3 Cache
L1 data cache是4路組相連,每個cacheline 64 byte。它是寫直達cache,這意味著寫操作也會直接寫入L2 Cache。L1 Cache 是虛擬地址索引,物理地址做tag。
L2 和 L3 Cache是8路組相連,每個cacheline 128 byte。L2 和L3 cache是物理地址索引。邏輯處理器之間共享cache。
因為邏輯處理器共享cache,因此可能有潛在的cache沖突,這可能會導致更低的性能。但是也可能會存在共享cache中的數據。比如,一個邏輯處理器可能預取另一個處理器需要的指令或者數據。這在服務器應用程序中很常見。在生產者-消費者模型中,一個邏輯處理器可能產生另一個邏輯處理器需要使用的數據。在這類case中,可以挖掘潛在的更高的性能。
BUS
如果cache miss,那么邏輯處理器將會訪問bus logic。Bus logic包括本地的APIC中斷控制器,也包括片外的系統存儲和I/O 空間。總線邏輯也處理來自外部總線對cacheable 地址的snoop請求和本地APIC輸入的終端。
從服務的角度來看,邏輯處理器的請求是根據先來先處理的原則。Queue和Buffer空間是共享的。我們不會給其中的一個邏輯處理器優先權限。
我們也會區分來自不同邏輯處理器的請求。對本地APIC的請求和中斷資源是唯一的,并區分不同的邏輯處理器。總線邏輯也會基于邏輯處理器來處理barrier fence(屏障操作)和memory order操作。
對于debug功能,邏輯處理器的ID號被顯示的發送給處理器的外部總線。其他的總線操作,如cache line evict和預取操作,會根據產生transaction的請求來獲取邏輯處理器的ID號。
單任務和多任務模式
當一個軟件線程要執行時,為了優化性能,提供了兩種模型多任務模型(multi-task MT)和單任務模型(ST)。在MT模式中,有兩個工作的邏輯處理器,其中的一些資源被如前所述的方式切分。ST模式分為兩種,single-task 邏輯處理器0(ST0)和single-task 邏輯處理器1(ST1)。在ST-0或者ST-1模式中,只有一個邏輯處理器處于工作狀態。在MT模式中被切分的資源被單個處理器暢享。IA-32 Intel 架構有一個指令叫做HALT,將會停止處理器的執行,然后使得處理器進入低功耗狀態。HALT是一條特權指令,這意味著只有操作系統或者其他的ring-0級別的程序可以執行這條指令。用戶級別的程序是不可以執行HALT執行的。
如果處理器采用了Hyper-Threading技術,執行HALT指令,處理器將會從MT模式切換到ST-0或者ST-1模式。比如,如果邏輯處理器0執行HALT,那么只有邏輯處理器1處于工作狀態。那么物理寄存器將會處于ST-1模式。先前被切分的資源將會被邏輯處理器1全部助戰。如果邏輯處理器1也執行了HALT操作,那么物理處理器可以進入低功耗狀態。
在ST0或者ST1模式中,中斷發送給已經HALT的處理器將會導致處理器進入MT模式,操作系統負責管理MT模式的切換。
圖7總結了上述的討論。在ST0或者ST1模式資源被完全分配給單個邏輯處理器。在MT模式,資源在兩個邏輯處理器間共享。
操作系統和應用程序
使用了Hyper-Threading 技術的處理器在操作系統和應用程序看來,處理器核心數翻倍。操作系統將會當把邏輯處理器當做物理處理器進行管理,調度程序和線程。然而,為了達到最高的性能,操作系統會實現兩種優化。
第一種是如果僅有一個邏輯處理器active使用HALT指令。使用HALT將會使處理器進入ST0或者ST1模式。不使用這個優化的操作系統將會在一個邏輯處理器idle,另一個邏輯處理器active的處理器上工作。并且idle的邏輯處理器會持續的判斷是否有人物要執行,這個叫做idle loop。Idle loop將消耗執行資源,如果這些執行資源釋放,那么性能將會更高。
另一種優化就是將軟件線程調度到邏輯處理器上。總體上來說,為了更好的性能,操作系統將會在調度線程到相同的物理處理器之前,調度線程到不同的物理處理器上。這個優化將會使得線程盡可能的執行在不同的物理核心上。
性能提升
在單核處理器和多核處理器上,Hyper-threading技術可以提升21%的性能。
?
在網站服務器的workload中,可以獲得16%到28%的性能提升。
?
筆記:
| Sub System | IP Block | Share | Duplicate | Partion |
| 前端 | Trace Cache | √ | ? | ? |
| Microcode ROM | √ | ? | ? | |
| ITLB | ? | √ | ? | |
| 分支預測 | ? | √ | ? | |
| Return stack | ? | √ | ? | |
| 譯碼 | √ | ? | ? | |
| Uop 隊列 | ? | ? | √ | |
| 亂序執行 | 分配 | ? | ? | √ |
| 寄存器重命名 | √ | ? | ? | |
| 指令調度 | √ | ? | ? | |
| 執行單元 | √ | ? | ? | |
| 重排序緩沖區 | ? | ? | √ | |
| 存儲系統 | DTLB | √ | ? | ? |
| Cache | √ | ? | ? |
歡迎關注我的公眾號《處理器與AI芯片》
?
總結
以上是生活随笔為你收集整理的Microarchitecture: HyperThreading(超线程)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: labuladong的算法小抄_学会了回
- 下一篇: bibtex引用参考文献排版格式