提高桌面級計算機指令級並行度的方法[轉]
平行計算從其並行的粒度來看,分為指令級、迴圈級、過程級、子程式級、作業級;而從平行計算機的體系結構而言,存在著核內並行、晶核級並行、PCB板級核間並行、機箱級並行、機架級並行、機群(異構)級並行,等多種並行等級。不同的並行粒度與不同的並行等級之間,是有著對應關係的。
其指令級並行,與CPU內部結構有著緊密的關聯,指令級並行包括核內多條指令的並行與多個核之間指令的並行。
從計算機體系結構而言,就是核內並行與晶核級並行。如何提高這兩種並行度,對於CPU結構有著不同的要求;對於並行程式的編制也有不同的要求。
本文根據本人近期所閱讀的書籍,以及從網路上獲取的資料,通過分析目前較新的並行晶片結構,找到提高並行度的關鍵點。並從軟、硬體方向預測為了進一步提升效率,未來並行晶片結構的發展方向,以及編制並行軟體的改變。
一:核內並行
1:指令的流水線操作
事實上從8086開始,就存在有核內並行。
在8086以前的微處理器,對指令的操作都是序列的,即對每一條指令而言,都是先取指令,再分析、執行。具體可表示為:
取指令——【讀運算元】——執行——【寫運算元】——取(下一條)指令一……
方括號內的操作是運算元在記憶體中時所要進行的,當運算元是CPU內部的某個暫存器時,則不需要這一步。顯然,在指令執行期間,匯流排(BUS)是空閒的,這一重要的系統資源沒有得到充分利用。
而8086是由它由兩大部分組成:執行部件(Eu:Execute Unit)和匯流排介面部件(BIU :BUS Interface Unit)。前者負責指令的譯碼和執行,後者負責所有涉及外部匯流排的操作。二者既獨立工作,又相互配合。
而8086在執行部件執行指令期間,匯流排介面部件可利空閒,用匯流排預取後續指令或進行儲存器運算元的讀或寫。這種不同指令在同一時間內處於不同執行狀態的指令並行操作,或者說指令的重疊執行,通常被稱為指令流水線操作。
BIU使用了指令預取佇列機制來實現指令流水線操作。該佇列的容量為6個位元組,即允許預取6個位元組的指令程式碼。每當指令佇列有兩個或兩個以上的位元組空間,且執行部件未向BIU申請讀/寫儲存器運算元時,BIU順序地預取後續指令的程式碼,並填入指令佇列。
指令佇列的工作方式是先進先出(First-in,First-out,FIFO),或者說是管道方式,先預取的指令即排在前面的指令先被取走執行,後面的依次向前推進,騰出的空間再放新預取的指令。
而當執行部件執行指令時發現是一條轉移指令,則匯流排介面部件清除佇列,從新的地址取指令,並立即送給執行部件去執行,然後,從後續的指令序列中預取指令填滿佇列。可見,一遇到轉移指令,就要重新預取指令佇列中的下一條及下下一條指令。顯然,這會明顯影響機器的執行速度。
核內並行,可以極大的減少平均指令執行週期(CPI),如使普通的CISC架構處理器的CPI值從5-8降低到略大於1。
從上述說明可以看出,要提高核內並行度,有做以下幾個方面的提高。
(a)處理轉移指令。
8086乃至80386、80486,在遇到轉移指令時,會放棄所有的指令預取佇列,從而影響效率。直到Pentium出現,引入了分支指令預測技術,才得以克服。
在Pentium微處理器中包含2個預取指令佇列,指令的分支預測是由一個叫做分支預測邏輯和分支目標緩衝器(BTB)的功能部件完成的。2個預取指令佇列不是同時工作,在同一時刻只有一個預取指令佇列處在有效狀態。指令預取器從指令Cache中取出指令以後,將它們順序存放在那個有效的預取指令佇列中,當預測分支指令將會發生轉移時,預取器將跳轉到分支指令的轉移目標地址順序取指,並將當時空閒的第二條指令佇列啟用,把取出的指令順序存放在第二條指令佇列中。
同樣可以看出,不能使用密集的轉移指令,這仍將使分支預取實效。隨著分支預取的進一步擴充套件(如Athlon64可以在16位元組的範圍內記錄3條分支),這一限制正在不斷縮小,但仍舊是可能影響效率的一個方面。
(b)對定址方式的限制。
對流水線進行分析,運算元如果是暫存器,自然不需要訪問記憶體;如果是立即數,也已經進入預取佇列,並進行了譯碼。但如果運算元不是暫存器或立即數,就必須重新從記憶體中讀寫資料。直接定址還可以在譯碼後先期取得;而間址、變址,只能在執行到指令時才進行訪問。
雖說L1、L2乃至L3的快取記憶體越來越大,而且從片外移到了片內,提供了較高的命中率,但其速度仍舊無法同暫存器相比。對資料段記憶體的過多訪問,會降低系統的執行效率。通過增加暫存器數量,減少記憶體訪問來提高效率,促使了在上世紀90年代RISC技術的極大發展。
RISC的load/restore指令只有在訪問記憶體時才使用,所有其它的指令都是在暫存器內對資料進行運算。一條存取數指令從記憶體將資料取出放到暫存器中,在那裡可以對資料進行快速處理,並把它暫存在暫存器裡,以便將來還要使用。在適當的時候,一條存數指令可將這個資料送回到它在記憶體中的地址中去。RISC的設計技術與CISC的設計技術相比,有大量暫存器。由於允許資料在暫存器中保留較長的時間,這樣就減少了存/取指令對記憶體訪問的需要。
RISC中所有指令採用固定長度,定址方式不超過三種,簡化了邏輯和縮短譯碼時間。確保單週期執行指令,由於指令的固定格式保證指令譯碼和取操作能同時進行,從而有利於流水線操作的執行。
精簡的指令更容易被流水線所操作。但由於軟體的相容性,以x86系列為代表的CISC仍佔據著主要的市場。
(c)RISC與CISC的結合。
RISC與CISC各自的優缺點,使其有相互結合的必要。
從使用IA-32結構的Pentium PRO開始,其微體系結構就採用了RISC的設計思想,它將x86指令轉換成多個易執行的微操作(mops),該操作為3運算元格式,對程式設計師透明,而與x86指令相容。
這樣,即利用了RISC技術適宜流水線操作的優點,又兼顧了軟體的相容性。
2:指令的超標量技術
從Pentium開始,在一個核心中出現了多條流水線。如Pentium就包含兩條整型流水線U、V,和一條浮點流水線。這使得CPI首次在理論上可能小於1。
需要說明的是,這並不是現在意義上的多核晶片,這是因為
(a)各條流水線使用了同樣的指令cache、同一條指令預取佇列、同樣的暫存器組,根據指令配對法則,將滿足一定條件的兩條指令同時執行。每條流水線並不能成為完整的核心。
(b)U、V兩條流水線並不相同。U流水線可以執行所有的x86指令,而V流水線只能執行部分的“簡單”指令。而能夠同時執行的兩條指令,也必須都是“簡單”指令,並且沒有暫存器資料相關。所謂的“簡單”指令是指由硬體邏輯、而非微碼實現的單週期指令。
而Pentium PRO中,各條流水線的功能已經相對獨立。在實際操作時,各流水線使用獨立的暫存器,並由分發 / 執行部件(DEU)將運算元無關的mops“亂序”執行。而在執行結束以後,通過退離部件(RU)按原指令流的順序取走已執行完的mops,把物理暫存器還原成邏輯暫存器,把無序的執行按原始指令流輸出結果。
使用RISC設計思想而出現的mops、多物理暫存器結構,都被硬體所遮蔽,對使用者透明;使用者看到的只是一個可以部分並行的x86結構。
3:提高核內並行度的方法
要提高核內並行度,其主要的方法有:
(a)記憶體大小匹配:當不同的指令操作相同的資料時,要避免記憶體大小失配。當一條指令讀寫了一個數據,隨後另一條指令又讀寫這個資料,則要保證資料是對齊的,即保證兩次都以相同的大小讀寫這一記憶體資料;
(b)適當的記憶體拷貝程式:記憶體的複製是在程式中經常使用,而且佔據相當時間週期的操作,要充分利用其記憶體頻寬,使用專用的讀寫指令,如讀:PREFETCH、寫:PREFETCHW等;
(c)分支指令的對齊:指令的預取是按塊進行的,如16B。不要將分支指令與這樣的塊邊界交叉,跨邊界的指令不能進行分支預取。會影響執行的效率;
(d)分支指令的密度:指令分支預取的分支數量是有限的,如果有集中的多條分支出現,就會出現沒有預取的分支;
(e)使用讀取—執行的指令:不要使用分別的指令來進行讀取和執行,而使用直接讀取運算元並執行的方式。以提高cache的命中率;
(f)避免程式碼段與資料段的重疊:避免程式碼的自修改,避免程式碼段被放到資料段,這些都會引起L1 cache的效率降低;
(g)使用正確的資料型別:對於浮點指令避免使用整型運算元,SSE、SSE2指令等使用相對應的資料型別;
上面的方法都可以提高流水線的效率,為整個程式的執行提高也許不到1%的速度。當然要提高指令並行度(ILP),成倍提高執行速度,最關鍵的是:減少相鄰指令的關聯度。這樣多條指令才能亂序執行,做到真正的指令級並行。
從計算機體系結構的概念——“程式設計師所看到的計算機”——而言,讓每一個程式設計師都去了解核內的流水線結構是不現實的。較可行的方法是由優化編譯程式來完成。
上述提高流水線效率的幾點,都可以很方便的由編譯程式來完成。減少使用者程式的指令關聯度可能較難;但是可以對所有的庫函式進行優化,重新編寫出相鄰無關的指令序列,從而提高整體的執行效率。
這裡提到了平行計算的最細粒度——指令級並行。由上所述,要提高核內指令級並行,需要的是提高核內的超流水線、超標量技術,並由目標程式充分利用這些技術;最重要的是利用編譯程式減少相鄰指令的關聯度,亂序執行指令。
二:晶核(DIE)級並行
1:從單核到多核
為了提高CPU的效能,通常做法是提高CPU的時鐘頻率和增加快取容量。不過目前CPU的頻率越來越快,如果再通過提升CPU頻率和增加快取的方法來提高效能,往往會受到製造工藝上的限制以及成本過高的制約。
提高計算機的效能已經從單純的提高速度,轉變為由單核向多核發展,通過提高晶片內的並行處理能力,來提高整體的效能。
大型平行計算機主要有SIMD,PVP,SMP,MPP,DSM,COW六種。多核晶片的模式也將會有類SMP、類MPP、類DSM、類COW等多種形式(SIMD、PVP的結構不利於擴充套件,發展前途不如其他幾種形式)。
(1)類SMP:隨著大規模積體電路技術的發展以及半導體制造工藝的提高,人們已經將大規模並行處理器中的SMP(對稱多處理器)整合到同一晶片內,從而實現單晶片多處理器(CMP),各個處理器並行執行不同的程序。SMP技術已經相當成熟,因此此類的多核處理器晶片,結構設計起來相對容易。
在高階伺服器領域,IBM Power5晶片最多可以包含8個處理器;而AMD K8、Intel Pentium D 9xx等桌面級晶片也是實際意義上雙核心處理器,目前正向四核發展。
與傳統的SMP相比,CMP尺寸更小、功耗更低、速度更快。
目前的多核處理器在核心中只放置了較小數量的快取記憶體,而沒有統一編址的記憶體(記憶體與快取記憶體的關係見下文)。如果快取記憶體的數量極大增加,並且可以統一編址供各個核心對等使用。那麼單單一塊晶片就能夠完成以往一臺SMP平行計算機的工作。
與SMP平行計算機一樣,類SMP多核晶片在核心數量增加時,會出現儲存匯流排的訪問瓶頸,不利於系統的擴充套件。
(2)類MPP:晶片的發展一方面是向多核發展,而另一個方向是向SOC(System on Chip)發展,不僅在晶片中包含控制器、運算器,還包含記憶體及輸入、輸出部件。類MPP實際就是這兩個發展方向的結合。在一塊晶片上整合多個核心,以及記憶體等其他部件。按照片內記憶體與核心連線方式的不同,就產生出類MPP與類DSM兩種不同結構。
如果所有的核心對所有的片內記憶體,可以進行對等存取,那麼這仍舊是不利於擴充套件的SMP結構。類MPP與類DSM都會擁有各自獨立的核內記憶體。
MPP與DSM的區別在於是否存在記憶體的統一編址。而對於MSOC而言,晶片是由一個廠商統一規劃、設計、生產的。應當較容易實現片內記憶體的統一編制。
如果核心不需要訪問到其他的核間記憶體,不進行統一編制,那就是類MPP;而如果核間通訊量大,需要訪問核間記憶體,進行了統一編制,那就是類DSM。
(3)類DSM:此類晶片中包含有多個核心,每個核心中仍可能有多條流水線,甚至於每個核心仍是一臺SMP。如2007年5月新推出的Power6晶片,每個微處理器(MPU)核心都作為2路CMP設計來實現,而在一塊晶片上整合2或4塊MPU。當然Power6從本文定義的結構上來說,還是類SMP,但在核心結構上已經有了類DSM的影子。
每個核心都擁有自己獨立的核內記憶體,或是由CMP核心共享的核內記憶體。該記憶體的存取速度應當接近於目前L1快取。每個核心通過特殊的存取指令,可以訪問到其他核心的核內記憶體。雖然記憶體已經統一編制,但是我仍然建議對於核間記憶體的訪問使用與核內記憶體不同的指令,程式設計師應當瞭解到這兩種記憶體的不同。
核內記憶體應當存放被頻繁訪問的資料。如可以將程式中函式定義的區域性變數放到核內記憶體中。這種方法可以被編譯程式所使用,但是程式設計師無法直接控制。
另在C語言中有register關鍵字。在目前條件下,由於暫存器數量較少,人工干預暫存器的分配反而會影響整體的效率。而如果將register關鍵字對應的變數放入核內記憶體,則能夠極大的提高效率。這就相當於在使用快取記憶體的晶片中,一個變數被固定在L1中,還不需要考慮回寫。
(4)類COW:COW與其他結構的平行計算機相比,最大的不同是使用了通用的網路結構來進行連線。而如果將整個COW結構封裝到一塊晶片中,晶片內各個核心之間的連線必定是專用的。所以在這裡的類COW只是套用了這一概念,實際是指多塊多核晶片之間的互聯。相對與晶片內的連線,PCB板上晶片間的連線網路更加“通用”。
目前的類SMP結構晶片,已經存在有晶片間的互聯。如IBM p5系列小型機,最多可以有64個核心(p5的併發多執行緒能力(SMT)使得從軟體執行角度看,會有128個核心),也就是說會多達有8塊Power5晶片互聯。
這裡談談我對類DSM結構多核晶片互聯的一些預測。
對於每個核心而言,有著核內記憶體,片核心間記憶體,片間記憶體三個層次。這些存在於核心中的記憶體從整臺計算機的角度被統一編制,但是這三個層次記憶體的訪問速度逐級降低。目前意義上的主存,依舊存在,但是從其功能和用途看,更接近於當前意義上的外儲存器。
在當前的計算機中,程式和資料使存放在外設,如硬碟上。需要通過輸入輸出指令將其讀入記憶體才能進行操作,並在需要的時候回寫。而對未來可能的多片類DSM晶片組成的計算機而言,存在有易失性記憶體與非易失性記憶體(如FLASH)。非易失性記憶體取代硬碟作為外設存在;易失性記憶體臨時資料、臨時檔案的存貯(如資料庫的TEMP表空間)。
類MPP、類DSM、類COW都只是本人的一點預測,從目前的文獻以及網路資源上都還沒有發現類似的講法。
2:超標量、超執行緒與多核
雖然CMP相對簡單,但對於注重價格因素的桌面系統而言仍是一項複雜的工作。為此業界提出了一個折中的方案——多執行緒處理器(SMT)。多執行緒處理器對執行緒的排程與傳統意義上由作業系統負責的執行緒排程是有區別的,它完全由處理器硬體負責執行緒間的切換。由於採用了大量的硬體支援,所以執行緒的切換效率更高。執行緒高效排程的目的就是要儘可能減少處理器處於閒置狀態,通過有效的執行緒切換來獲取處理器在相同工作時間內更高的工作效率。而SMT最具吸引力的是它只需小規模改變處理器核心的設計,幾乎不用增加額外的成本就可以獲得顯著的效能提升。此類技術的代表就是超執行緒(HT/Hyper –Threading)。
超執行緒技術是在一顆CPU同時執行多個程式而共同分享一顆CPU內的資源,理論上要像兩顆CPU一樣在同一時間執行兩個執行緒,P4處理器需要多加入一個Logical CPU Pointer(邏輯處理單元),用以資源的分配。因此新一代的P4 HT的晶核(DIE)的面積比以往的P4增大了5%。而其餘部分如ALU(整數運算單元)、FPU(浮點運算單元)、L2 Cache(二級快取)則保持不變,這些部分是被分享的。
雖然採用超執行緒技術能同時執行兩個執行緒,但它並不象兩個真正的CPU那樣,每個CPU都具有獨立的資源。當兩個執行緒都同時需要某一個資源時,其中一個要暫時停止,並讓出資源,直到這些資源閒置後才能繼續。因此超執行緒的效能並不等於兩顆CPU的效能。
HT技術造就了PENTIUM 4的一個輝煌時代的武器,儘管它被評為失敗的技術,但是卻對P4起一定推廣作用。其實引用《現代計算機》雜誌所比喻的HT技術好比是一個能用雙手同時炒菜的廚師,並且一次一次把一碟菜端上桌;而真正的雙核心處理器好比2個廚師炒兩個菜,並同時把兩個菜端上桌。很顯然雙核心處理器效能要更優越。按照技術角度PENTIUM D 8xx系列不是實際意義上的雙核心處理器,只是兩個處理器整合,但是PENTIUM D 9xx就是實際意義上雙核心處理器,而K8從一開始就是實際意義上雙核心處理器。
需要注意的是,含有超執行緒技術的CPU需要晶片組、BIOS、作業系統和應用軟體支援,才能比較理想的發揮該項技術的優勢。
目前支援超執行緒技術的晶片組包括如: Intel 845E以後的晶片組,如845PE/GE/GV、865/875和915/925系列晶片組;VIA的P4X400、P4X533、PT800、PT880、PM800和PM880晶片組;SIS的SIS655、SIS648FX、SIS661FX、SIS655FX、SIS655TX、SIS649和SIS656晶片組;ULI的M1683和M1685晶片組。
作業系統如:Microsoft Windows XP、Microsoft Windows 2003,Linux kernel 2.4.x以後的版本也支援超執行緒技術。
一般來說,只要能夠支援多處理器的軟體均可支援超執行緒技術,但是實際上這樣的軟體並不多,而且偏向於圖形、視訊處理等專業軟體方面。應用軟體有Office 2000、Office XP等。但事實上如果有使用者併發的操作,就能享用到一定的效能提升。
雙芯雖然比超執行緒更復雜,但事實上雙核晶片早以有之。 “雙核”的概念最早是由IBM、HP、Sun等支援RISC架構的高階伺服器廠商提出的,不過由於RISC架構的伺服器價格高、應用面窄,沒有引起廣泛的注意。比如擁有128MB L3快取的雙核心IBM Power4處理器的尺寸為115x115mm,生產成本相當高。
而Intel和AMD公司的桌面產品正從單核多流水線、偽雙核(超執行緒)向著真正的雙核、多核進展。把多核並行從高階帶到了平民階層。而這兩家公司的“真”雙核產品還存在著很多結構上的不同。
AMD Opteron 處理器從一開始設計時就考慮到了新增第二個核心,兩個CPU核心使用相同的系統請求介面SRI、HyperTransport技術和記憶體控制器,相容90納米單核心處理器所使用的940引腳介面。是將兩個核心做在一個晶核上,通過直連架構連線起來,整合度更高。從使用者端的角度來看,AMD的方案能夠使雙核CPU的管腳、功耗等指標跟單核CPU保持一致,從單核升級到雙核,不需要更換電源、晶片組、散熱系統和主機板,只需要重新整理BIOS軟體即可。
而Intel則是將放在不同晶核上的兩個完整的CPU核心封裝在一起,連線到同一個前端總線上。可以說,AMD的解決方案是真正的“雙核”,而英特爾的解決方案則是“雙芯”。可以設想,這樣的兩個核心必然會產生匯流排爭搶,影響效能。不僅如此,還對於未來更多核心的整合埋下了隱患,因為會加劇處理器爭用前端匯流排頻寬,成為提升系統性能的瓶頸,而這是由架構決定的。
因此可以說,AMD的技術架構為實現雙核和多核奠定了堅實的基礎。AMD直連架構(也就是通過超傳輸技術讓CPU核心直接跟外部I/O相連,不通過前端匯流排)和整合記憶體控制器技術,使得每個核心都自己的快取記憶體可資遣用,都有自己的專用車道直通I/O,沒有資源爭搶的問題,實現雙核和多核更容易。而Intel是多個核心共享二級快取、共同使用前端匯流排的,當核心增多,核心的處理能力增強時,肯定要遇到堵塞的問題。
3:現有的高並行度多核晶片
目前已經存在的高並行度多核晶片,不是哪家廠商生產的CPU,而是被稱為GPU的顯示處理晶片。
單就浮點效能而言,現在的處理器已經遠不如顯示處理晶片,比如Intel Pentium 4 3.0 GHz約為6Gflops(每秒十億次浮點操作),四路雙核心Itanium 2也不過45Gflops,而最新的AMD R600可達到475Gflops。
當今最強大的超級計算機是IBM的藍色基因/L,擁有65536個雙核心處理器,也就是131072個處理核心,峰值運算效能367TFlops。如果換算成R600,理論上只需不到800個圖形處理器就能達到藍色基因/L的效能水平。
ATI早先發布的催化劑7.4驅動已經能夠支援斯坦福大學的蛋白質摺疊分散式計算,只要擁有一塊X1000系列顯示卡,接入網際網路,並且安裝了斯坦福大學GUP分散式計算應用程式。那麼就可以在顯示卡空閒時(非3D模式)為科學計算做一份貢獻。由於所有的計算都是由顯示卡來完成,因此它不會佔用您的CPU和記憶體資源,在上網和文書處理時不會受到任何影響,僅僅是佔用少量的網路頻寬,另外要消耗一部分電能。
一家軟體公司Peakstream聲稱,他們已經開發出一套新的軟體平臺,結合普通處理器的處理能力和顯示卡的資源即可打造出超級計算機。只需在已有計算機內簡單地增加顯示卡,Peakstream就能將原有系統的能力提高20倍之多。根據Peakstream提供的資料,該平臺效能與傳統的處理器系統相比,在Monte Carlo Simulation測試中成績可提高16倍,在Kirchhoff Migration中可提高21倍。GPU已經超越CPU成為當今桌面電腦系統裡最強大的部件。
GPU的主要部件包括頂點著色單元、象素著色單元、紋理單元、光柵化引擎。而隨著DirectX10的釋出,nVidia最新的G80(06年11月推出)與AMD(ATI)的R600(07年5月推出)都採用了統一渲染結構,使用較為通用的處理核心來進行頂點運算和象素運算。G80使用了128個並行的流處理器;R600使用了64個流處理器單元,而每個單元中有5個ALU,其中一個還能進行諸如Sin、Cos的複雜運算。
除了核心數量的增多,顯示處理晶片所能夠達到的高效能還有以下一些原因。
(a)流水執行緒度高:CPU中就使用了流水線來提高核內並行度,如Pentium 4就有20級的流水線。但是流水線級數越多,一條指令從開始進入流水線到最後被執行完畢這之間的延遲間隔會相當大。而CPU的設計目標是不僅要有很高的吞吐量,還要求很小的延遲,這是CPU並不採用過多流水線級數的原因之一。另外流水線只有在滿載時,才能發揮出最佳效率來。由於CPU執行的程式碼中有很多分支語句,因此長流水線需要用有效的技術來預測分支,儘量保持流水線在滿負荷狀態。但是一旦預測分支失敗,就會清除流水線中滯留的大量無用指令,如果流水線階段過多的話,再次充滿整個流水線就需要很長的時間,速度反而下降了。所以權衡利弊,CPU不會使用深度流水線。
但是GPU卻採用了幾百級的流水線,比如GeForce 3的流水線有800個階段。這是因為1:顯示可以有相當的延遲,只需要滿足人眼的視覺暫留即可;即便是為了增強互動程度而提高幀速到100,也不過需要在10ms中完成,這對於只有幾ns的時鐘週期來說,根本就是天文數字,完全可以延遲。2:在GPU中執行的Shader程式中,分支語句用的很少(在早期的GPU中,甚至不提供動態的分支語句),流水線可以長時間的保持滿負荷狀態。因此,GPU的流水線深度變大後,利大於弊,大大提升了整體效能。
(b)並行執行緒的切換:GPU的執行速度很快,但是當執行到慢速指令,如從記憶體中獲取紋理資料這樣的指令時(由於記憶體訪問是瓶頸,而且紋理越練越大,此操作比較緩慢),整個流水線便出現長時間停頓。在GPU內部Cache命中率不高,只用Cache解決不了這個問題。所以,為了保持流水線保持忙碌,GPU中使用了多執行緒機制。由硬體完成對這一執行緒的切換,對另一個畫素進行處理。等到慢速指令完成時,可再切換到原先執行緒。
(c)並行資料的無關性: 無論是CPU送給GPU的頂點資料,還是GPU光柵生成器產生的畫素資料都是互不相關的,可以並行地獨立處理。而且頂點資料(xyzw),畫素資料(RGBA)一般都用四元數表示,適合於平行計算。在GPU中專門設定了SIMD指令來處理向量,一次可同時處理四路資料。GPU中的各個執行部件,可以各自獨立的獲取資料,並進行計算,從而提高總體的執行效率。
(d)記憶體訪問的限制:紋理片要麼只能讀取,要麼只能寫入,不允許可讀可寫,從而解決了存貯器訪問的讀寫衝突。GPU這種對記憶體使用的約束也進一步保證了並行處理的順利完成。
4:GPU的並行結構適合於並行科學計算
以R600為例,其64個流處理器單元,每個單元中有5條流水線,從本文涉及的平行計算角度來講,這就比G80多了一級核內並行。這5個ALU既可以一同執行一條5維向量運算,也可以同時執行5條標量運算,甚至是2+2+1、4+1等多種組合形式。而這一分配正是由分支執行單元(Branch Execution Unit)進行亂序分配而實現的,符合本文所述的核內指令級並行情況。
而G80的128個流處理器被分為8組並行的陣列,每組16個流處理器;這16個處理器共享L1快取(這一陣列的核內記憶體),每個處理器中只有一條流水線。這一個陣列就類似於一臺CMT。而8組CMT合併成為一臺類DSM。而執行緒的是通過執行緒處理器(Thread Processor)來進行分配。
隨著快取記憶體的逐步擴大,cache塊表所佔據的容量也將增加,會使快取實際容量的減少,造成浪費。個人認為當L1快取從k級別大小上升到M級別時,就會擁有自己的地址,允許程式設計師自行將所需要的資料、變數放入其中。這主要是針對資料cache,當容量足夠大時,由程式設計師自行定義會比硬體自動預取高效;而對於指令cache,由於指令的順序執行特性,由硬體完成自動預取同樣可以有很高的命中率。這可能會成為哈佛結構cache的一種發展方向。
其實這種擁有地址的高速記憶體,與RISC結構中數量成百上千的暫存器起到了同樣的作用。將快取改為記憶體,其實就是增加了程式設計師對快取的直接干預;並由於取消了快取與主存的對映,避免的回寫問題。
如果高速記憶體進一步擴大,大到能夠放下整個程序執行所需要的程式碼段和資料段。那就達到了晶核級並行的理想狀態。只有程序間的通訊才需要訪問到核外的記憶體,每個執行緒在獨立的核心中執行,由多流水線亂序執行指令,來實現核內並行;核心中的多路CMP共享核內記憶體,執行一個程序中各自的執行緒,執行晶核級並行;各個程序使用各自的CMP,執行核間並行。
這一層次的並行被稱為晶核級並行,是因為與核心與核內記憶體之間的訪問,必須有極其快的速度,從工藝上將,只有將核心與核內記憶體放置在同一晶核上才能實現,所以將這一層次的並行稱為晶核級的並行。
GPU正是使用類似的方式來實現極高的並行度,達到大大超越CPU的運算能力。從上述對兩款最新GPU的表述中,可以發現AMD的晶片結構,其核內並行、核間並行層次清晰,更有利於科學平行計算。
由此,可以看出,要提高晶核級核間指令級並行,需要編寫多執行緒程式,利用晶片的超執行緒、同一晶核內的多核,能夠同時執行多個執行緒的能力,並行執行多個執行緒。
這就需要改變並行程式的編寫習慣。在細粒度上編寫多執行緒程式。如將每一個CMT核心所執行的程序,按照輸入、合法性判斷、計算、輸出等不同功能,分別編制執行緒;這些執行緒形成實際上的流水線,將各自生成的結果交由佇列管理,並由下一執行緒處理。不同的執行緒使用共同的核內記憶體,可以高效的並行執行。
三:晶片與並行作業系統的定製
GPU之所以能夠提供如此強大的平行計算能力,與其所使用的“並行作業系統”——DirectX有著密不可分的關係。
1:硬體裝置無關性
微軟不僅開發了DirectX標準平臺,並且根據硬體製造廠商和遊戲廠商合作共同更新升級DirectX的標準。硬體製造商按照此標準研發製造更好的產品,遊戲開發者根據這套標準開發遊戲。也就是說,無論硬體是否支援某種特效,只要DirectX標準中有,遊戲開發者就可以把它寫到遊戲中,當這個遊戲在硬體上執行,如果此硬體根據DirectX標準把這個效果做到了此硬體驅動程式中,驅動程式駕馭其硬體算出結果,使用者就可以欣賞到此效果。這就是“硬體裝置無關性”,是DirectX真正意義所在。
這句話換一下幾個名詞,就成了。應當提供並行硬體抽象層(PHAL/Parallel Hardware Abstraction Layer),硬體製造商按照此標準研發製造更好的並行晶片、平行計算機,並行軟體開發者根據這套標準開發並行程式。也就是說,無論硬體是否支援功能,只要PHAL標準中有,程式開發者就可以把它寫到程式中,當這個並行程式在硬體上執行,如果此硬體根據PHAL標準把這個功能做到了此硬體驅動程式中,驅動程式駕馭其硬體實行平行計算,使用者就可以享受到並行的優勢。這就是“硬體裝置無關性”,是PHAL真正意義所在。
當平行計算還是大型計算機的專屬時,開發這樣的PHAL屬於得不償失,但是當平行計算已經進入桌面,可以為幾乎所有的應用程式提供服務的時候。把並行處理交給PHAL,就可以解放並行程式的開發人員,使其將精力集中到應用程式本身的演算法,而不是如何並行上。
當圖形加速卡剛出現時,是需要應用程式直接操縱硬體來取得加速效能的。而諸如DirectX、OpenGL等圖形API介面,也是到了一個開發瓶頸階段才出現,並逐漸被遊戲開發人員所採用。
到DirectX7.0為止,DirectX的工作主要是逐步實現圖形卡已有的功能,並提供API以簡化開發。而從8.0開始,DirectX已經領先於圖形卡的設計,每一個版本的DirectX都對應了新的一代顯示核心,標準的定義已經超前於實現。
目前正是平行計算剛剛進入桌面系統的時代,目前的並行能力都需要應用程式來實現。而PHAL將逐步簡化這一過程,並最終成為引領平行計算機結構發展的源動力。
2:並行作業系統、並行編譯系統的結合
DirectX內含的Shader Model提供了對GPU中流處理器的程式設計控制。在程式設計中,需要為每一個頂點(Vertex)或象素(Pixel)編制對應的Shader,該Shader負責對這一物件的顯示。在最新的DirectX10所定義的Shader Model 4.0中最大指令數從512條增加到了64k條;臨時暫存器數量也從原先的32個增加到驚人的4096個;允許同時對128個紋理(Texture)進行操作,對於紋理的尺寸Shader Model4.0也有驚人的提升,8192x8192的最高紋理分辯率比原先最高2048x2048的分辯率要高出4倍。
從計算機結構的角度講,上述內容的含義就是:每一個物件有其所對應的執行緒負責顯示,每個活動執行緒所使用的程式碼cache為64k;資料cache為64k(每個暫存器存放4維向量,每維32bit);L2 cache由於受到紋理壓縮比的影響,不容易計算。這些數以萬計的這些執行緒,在執行時,在GPU內部被硬體排程,實現高度的並行。
這些引數,既是DirectX技術標準的定義,也是各種支援DirectX10圖形處理器的實際配置。
所以說DirectX決不僅僅是一組API,還提供了並行程式編寫語言及其編譯器,並同硬體一同實現並行作業系統。
綜上所述,如果能夠實現PHAL,那麼PHAL也必定是並行編譯系統與並行作業系統的結合。只有這樣才能編寫出“細粒度”的執行緒,以滿足晶核級並行的要求。
四:結束語
整篇文章主要寫了為了提高指令級並行,在未來軟硬體所可能的發展方向。
本來是想把後面的迴圈級、過程級、子程式級、作業級寫個遍的,但是時間有限。
以一己之力來推斷未來並行技術(主要指桌面級計算機的並行技術)的發展,自然謬誤不斷。但從邏輯上,本文所述的各種技術都合理可行。但是否能夠真正實施,需要時間和實踐的檢驗。本人所準備編寫的“推箱子的並行演算法”正是對這些推斷的一點小小證明。
現在看本文,也許嗤之以鼻;十年後看本文,也許一笑了之。
下面再寫一些本人的武斷,要把這些東西全部說清,或許還要十倍的篇幅。
結論:
1:CPU的結構向著類DSM發展
2:核內快取的數量增加——cache塊表過大——成為核內記憶體——其區別在於,可以由人工直接填寫資料,而沒有對映。
3:並行科學計算的程式設計,成為細粒度的多執行緒程式設計。PHAL的出現,使執行緒的分配變的簡單。
4:CPU的製造,可以定製,根據不同需求,可以配備不同的特定部件。
5:一個過程從巨集觀上看,就是一條超長的指令。所以過程級並行是巨集觀的指令級並行。其主要由刀片機內多PCB板間並行來實現。
6:類DSM結構的CPU組成的機群,是平行計算機發展的方向。
7:並行程式的設計語言必須有全新的關鍵字來進行定義。對不同記憶體的讀寫,有不同的指令。
8:不同級別的並行度,是由不同手段的並行解決方法。
轉自:http://ce.sysu.edu.cn/hope2008/Education/ShowArticle.asp?ArticleID=13367