GPU如何助力高性能計(jì)算
CPU執(zhí)行指令的方式就是一個接著另一個地執(zhí)行。CPU中有許多能夠加速串行計(jì)算的技術(shù)。高速緩存、無次序執(zhí)行、超標(biāo)量技術(shù)、分支預(yù)測……均為抽取指令的技術(shù)或一系列指令的串行級并行機(jī)制。CPU對片上高速緩存的設(shè)計(jì)與容量的依賴也非常大。如果程序大小與CPU高速緩存容量不匹配,那么該程序在CPU上的運(yùn)行速度將會很慢。
CPU的主要運(yùn)作原理,不論其外觀,都是執(zhí)行儲存于被稱為程序里的一系列指令。在此討論的是遵循普遍的馮·諾伊曼架構(gòu)設(shè)計(jì)的裝置。程序以一系列數(shù)字儲存在計(jì)算機(jī)記憶體中。差不多所有的馮·諾伊曼-CPU的運(yùn)作原理可分為四個階段:提取(fetch)、解碼(decode)、執(zhí)行(execute)和寫回(writeback)。
第一階段,提取,從程序記憶體中檢索指令(為數(shù)值或一系列數(shù)值)。由程序計(jì)數(shù)器(PC)指定程序記憶體的位置,程序計(jì)數(shù)器保存供識別目前程序位置的數(shù)值。換言之,程序計(jì)數(shù)器記錄了CPU在目前程序里的蹤跡。提取指令之后,PC根據(jù)指令式長度增加記憶體單元[iwordlength]。指令的提取常常必須從相對較慢的記憶體查找,導(dǎo)致CPU等候指令的送入。這個問題主要被論及在現(xiàn)代處理器的高速緩存和管線化架構(gòu)(見下)。
CPU根據(jù)從記憶體提取到的指令來決定其執(zhí)行行為。在解碼階段,指令被拆解為有意義的片斷。根據(jù)CPU的指令集架構(gòu)(ISA)定義將數(shù)值解譯為指令[isa]。一部分的指令數(shù)值為運(yùn)算碼(opcode),其指示要進(jìn)行哪些運(yùn)算。其它的數(shù)值通常供給指令必要的信息,諸如一個加法(addition)運(yùn)算的運(yùn)算目標(biāo)。這樣的運(yùn)算目標(biāo)也許提供一個常數(shù)值(即立即值),或是一個空間的尋址值:寄存器或記憶體地址,以尋址模式?jīng)Q定。在舊的設(shè)計(jì)中,CPU里的指令解碼部分是無法改變的硬體裝置。不過在眾多抽象且復(fù)雜的CPU和ISA中,一個微程序時常用來幫助轉(zhuǎn)換指令為各種形態(tài)的訊號。這些微程序在已成品的CPU中往往可以重寫,方便變更解碼指令。
在提取和解碼階段之后,接著進(jìn)入執(zhí)行階段。該階段中,連接到各種能夠進(jìn)行所需運(yùn)算的CPU部件。例如,要求一個加法運(yùn)算,算數(shù)邏輯單元(ALU,arithmetic logic unit)將會連接到一組輸入和一組輸出。輸入提供了要相加的數(shù)值,而且在輸出將含有總和結(jié)果。ALU內(nèi)含電路系統(tǒng),以于輸出端完成簡單的普通運(yùn)算和邏輯運(yùn)算(比如加法和比特運(yùn)算)。如果加法運(yùn)算產(chǎn)生一個對該CPU處理而言過大的結(jié)果,在標(biāo)志寄存器里,運(yùn)算溢出(arithmetic overflow)標(biāo)志可能會被設(shè)置(參見以下的數(shù)值精度探討)。
最終階段,寫回,以一定格式將執(zhí)行階段的結(jié)果簡單的寫回。運(yùn)算結(jié)果極常被寫進(jìn)CPU內(nèi)部的寄存器,以供隨后指令快速訪問。在其它案例中,運(yùn)算結(jié)果可能寫進(jìn)速度較慢,但容量較大且較便宜的主記憶體。某些類型的指令會操作程序計(jì)數(shù)器,而不直接產(chǎn)生結(jié)果數(shù)據(jù)。這些一般稱作“跳轉(zhuǎn)”(jumps)并在程序中帶來循環(huán)行為、條件性執(zhí)行(透過條件跳轉(zhuǎn))和函數(shù)[jumps]。許多指令也會改變標(biāo)志寄存器的狀態(tài)比特。這些標(biāo)志可用來影響程序行為,緣由于它們時常顯出各種運(yùn)算結(jié)果。例如,以一個“比較”指令判斷兩個值的大小,根據(jù)比較結(jié)果在標(biāo)志寄存器上設(shè)置一個數(shù)值。這個標(biāo)志可借由隨后的跳轉(zhuǎn)指令來決定程序動向。
在執(zhí)行指令并寫回結(jié)果數(shù)據(jù)之后,程序計(jì)數(shù)器的值會遞增,反復(fù)整個過程,下一個指令周期正常的提取下一個順序指令。如果完成的是跳轉(zhuǎn)指令,程序計(jì)數(shù)器將會修改成跳轉(zhuǎn)到的指令地址,且程序繼續(xù)正常執(zhí)行。GPU內(nèi)部的并行計(jì)算架構(gòu)圍繞兩個基本概念而設(shè)計(jì)。首先,程序中的數(shù)據(jù)可分成許多個部分,而為數(shù)眾多的核群可以并行地處理這些數(shù)據(jù)。第二個架構(gòu)方面的設(shè)想是,數(shù)據(jù)將不與高速緩存匹配。例如在圖形計(jì)算或石油天然氣數(shù)據(jù)處理上,數(shù)據(jù)量可能會達(dá)到兆字節(jié)甚至是太字節(jié),用高速緩存來容納如此巨大的數(shù)據(jù)量幾乎是不切實(shí)際的。考慮到這兩點(diǎn)設(shè)想,GPU被設(shè)計(jì)為能夠使用數(shù)以千計(jì)的線程,所有線程均并行地執(zhí)行,能夠訪問巨大容量的本地存儲器。 #p#page_title#e#
GPU設(shè)計(jì)初充為高性能三維圖形應(yīng)用,具有強(qiáng)大的計(jì)算能力和很高的存儲帶寬,而這兩點(diǎn)對于高性能三維圖形應(yīng)用是至關(guān)重要的。以往GPU計(jì)算都是專用于這些應(yīng)用的,但現(xiàn)在新型的GPU(如:GeForce 8800)允許具備一定的用戶可編程性,這就使得GPU能夠面向更通用的計(jì)算。不過,通用計(jì)算功能首先必須被高效地映射到GPU上。
三維圖形計(jì)算被組織進(jìn)一個圖形管道,該管道描述場景輸入和圖像輸出之間的一系列計(jì)算階段。圖形管道的輸入是一個場景,它由許多幾何體(定義為連接頂點(diǎn))以及用來從幾何體計(jì)算場景的圖形指令組成。
GPU對那些頂點(diǎn)進(jìn)行處理,并將之變換為屏幕空間幾何體(screen-space geometry),該幾何體通過光柵化(rasterization)過程依次被劃分為像素片段(pixel-sized fragments)。每一片段與屏幕上的一個像素位置相關(guān)。最后,這些片段被處理并組合到由像素組成的圖像中。
該管道包含大約12級(stage),每級都在一個GPU里執(zhí)行,作為在同一裸片上每級的一個單獨(dú)處理器。管道的典型輸入是幾十個到幾十萬個頂點(diǎn),每一個頂點(diǎn)都可在GPU上并行處理。
因此,復(fù)雜的圖形管道可以按空間劃分,GPU上的各個處理器并行運(yùn)行每一級。這種體系與CPU不同,它使每一個處理器可以專用于執(zhí)行自己的任務(wù),而CPU只有一個處理器。在CPU上實(shí)現(xiàn)圖形管道是按時間來劃分復(fù)雜任務(wù)的:CPU在其處理器上處理管道的第一級,僅當(dāng)?shù)谝患壨瓿蓵r才開始下一級。
從通用編程人員的觀點(diǎn)來看,GPU包含兩個重要的級,都是用戶可編程的,即頂點(diǎn)級(vertex stage)和片段級(fragment stage),前者在每一個頂點(diǎn)輸入端運(yùn)行用戶定義程序,后者在每一個片段上運(yùn)行用戶定義程序。
兩個級具有類似的編程模型。在運(yùn)行長串的輸入(幾十萬個頂點(diǎn)或片段)時兩者都很有效率。不過,每個輸入都是被獨(dú)立處理的,因此一個頂點(diǎn)或片段的計(jì)算不會影響另一個頂點(diǎn)或片段。用這種方法,能夠并行處理許多頂點(diǎn)或片段。
每一個輸入用相同的片段或頂點(diǎn)程序處理。這些程序通常在SIMD(單指令多數(shù)據(jù))情況下運(yùn)行時最有效,這意味著用控制每個計(jì)算的指令序列來并行計(jì)算每個頂點(diǎn)或片段。不過,新近開發(fā)的硬件已開始允許在這些程序中執(zhí)行更為復(fù)雜的控制流程。
那么,片段或頂點(diǎn)程序是什么樣呢?首先,它們都只支持IEEE單精度浮點(diǎn)運(yùn)算。其次,二者都可以從全局存儲器的任意位置讀取,但不能寫入任意全局存儲器。頂點(diǎn)程序的輸出是一個單獨(dú)的頂點(diǎn),而片段程序的輸出則只是這該片段像素位置上的一個片段。
在通用編程人員看來,這些局限性意義重大,能使GPU支持許多功能性單元,這些單元能并行運(yùn)算大量數(shù)據(jù)元的頂點(diǎn)或片段程序。例如,在16個并行片段處理器上,Nvidia GeForce 6800的片段程序的總體運(yùn)算速率超過每秒500億次浮點(diǎn)運(yùn)算。
若頂點(diǎn)和片段程序具有可編程性,就可以在GPU上運(yùn)行通用應(yīng)用。迄今大多數(shù)努力都集中在片段級,因?yàn)樗软旤c(diǎn)程序具有更多的處理器和更高的性能。要使這些應(yīng)用有效,關(guān)鍵在于將必要的計(jì)算映射到片段處理硬件的SIMD并行編程模型上。
在圖形硬件上構(gòu)建通用程序的典型方法之一是:給定一個大的幾何體,如屏幕大小的矩形。該幾何體覆蓋屏幕的主要部分,故產(chǎn)生大量片段。
由該幾何體產(chǎn)生的每個片段都可以被并行處理?,F(xiàn)在的GPU能用相同的指令并行處理16個片段。每一個片段計(jì)算都能從全局存儲器的任一位置讀取(矢量術(shù)語稱為“搜集”),但不能寫入任意全局存儲器(“分散”)。
片段程序的輸出是全局存儲器中的一個圖像,每一片段計(jì)算都對應(yīng)于該圖像中的一個單獨(dú)的像素點(diǎn)。
一些簡單的應(yīng)用可在單個圖形管道循環(huán)中表達(dá)出來,但許多復(fù)雜的應(yīng)用卻不行。這些更復(fù)雜的應(yīng)用要通過利用后繼循環(huán)計(jì)算中的單循環(huán)全局圖像輸出,在圖形管道的多個循環(huán)中才能完成。
與CPU相比,GPU具有更高的計(jì)算速度和存儲器帶寬,在那些能很好地映射到其編程模型的應(yīng)用上,它極具潛力。而編程人員的挑戰(zhàn)則在于,如何有效地將感興趣的應(yīng)用映射到圖形硬件的圖形隱喻(graphics metaphors)和限制性編程模型中。 #p#page_title#e#