CPU和GPU共享內存,CPU向內存(顯存)寫數據,GPU再從內存讀數據,兩者應該不能同時讀取內存,這樣的話,數據傳輸的速度是不是嚴重影響CPU和GPU的效率。有沒有其他解決辦法,比如兩條匯流排啥的。但是好像只要統一定址,就避免不了衝突。


是的,它們得排隊。因為內存讀寫要先鎖存了地址線然後從數據線讀寫數據。

不過內存讀寫非常的快,一次讀寫佔用時間也非常短,所以影響是有的,但並不嚴重。

至於數據傳輸的速度是不是影響GPU效率,是的,內存帶寬確實非常影響GPU效率,所以內存帶寬是GPU性能的重要檔次劃分。你看GDDR5內存的顯卡跟GDDR6內存的顯卡,性能就完全不是一個檔次。

但是內存帶寬對CPU的影響相對比較小,因為CPU一般並不需要如此大量的內存讀寫,除非這個CPU集成了GPU。


題主說到了cpu寫數據給gpu讀,那麼這裡的衝突應該是指同地址數據讀寫的衝突。

在驅動等底層軟體編寫正確時,實際運行時是不會衝突的。

cpu給gpu送數據時,在寫完之後再通知gpu可以讀取,gpu讀取時cpu不再向同一塊地址寫數據,這個是共享內存系統中最基本的同步操作。如果同地址衝突了,實際運行時的結果是不確定的。所以才要求軟體要正確使用同步機制來保證。

至於匯流排帶寬上的衝突,這個是gpu,cpu等爭搶帶寬,一般並不影響程序正確性,只是在處理不好qos時影響性能。

某些答案都不知道在說些啥東西。


看現有兩個答案 @木頭龍 @Kerbalism ,和我所理解的知識差別還是蠻大的。不知道哪個正確,我也說說我的理解,權當拋磚引玉,希望有大架構師過來答疑解惑。

如果GPU採用獨立的顯存。那很明顯,不會衝突。但顯存也就只能GPU自己用了,有點浪費,因此採用共享內存的方法。讓CPU管理的內存也分配一些給GPU來用。所以,這種情況下,所有的內存都是CPU體系裡面的,或者說,是CPU定址空間內統一管理的。只不過,在MMU,BIOS或者操作系統層面,划出一部分,給GPU用,告訴CPU不要用。

雖然CPU不訪問這一片了,但既然是統一定址,統一管理,那就是掛在同一個匯流排上的,所以還是會產生匯流排衝突,這時候怎麼辦?仲裁呀,匯流排都有一個仲裁器,多個主設備訪問匯流排了,那就由匯流排仲裁器排隊,排隊策略有優先順序排序,先來先到排序,隨機排序,各種方式。

其實在沒有GPU共享內存的時候,匯流排仲裁器也是很重要的模塊,例如DMA。在匯流排的視角看來,DMA也是匯流排的主設備,和CPU地位一樣的。也要仲裁。

如果你有多個CPU核,也可能需要仲裁器,不過取決於架構設計,這種仲裁器可能在L3 CACHE上,也可能在MEMORY匯流排上。

所以對於架構師來說,GPU共享內存很簡單,只是多了一個Master而已。不只是GPU,NPU,ISP,CODEC,很多設備都算Master,都在共享內存,甚至包括外部設備,例如大家都在說雷電介面有安全隱患,就是因為PCI-express設備可以直接訪問內存空間。

那你說共享內存多了,衝突多了,是不是嚴重影響效率? 理論上,確實會影響,但是影響多大,要從架構上考慮。因為現在的CPU,早就不是古早史前的8051,直接訪問內存了,他會經過I-CACHE,D-CACHE, L2-CACHE, L3-CACHE,多級緩存管理,只有這些緩存全部沒有命中,才會產生缺頁中斷,去外部DDR MEMORY上取一大筆數據,這時候CPU確實得停下來,等數據。但是現在的Cache都很大了,各種分支預測演算法很牛掰,在你CPU可能用到數據的很早之前,就把數據取進Cache了,所以發生缺頁中斷並導致CPU暫停的概率不高。那這時候衝突對CPU的性能影響是不大的。(那有沒有Cache處理不了的呢?有,例如IO操作,或定義為volatile的變數,每次都得去新鮮訪問,性能急劇下降)。

一般主要評價衝突對性能的影響,是從吞吐量考慮的,例如CPU能處理的最大吞吐量是100GB/s,GPU需要的最大吞吐量是100GB/s,那匯流排吞吐量就得大於200GB/s,內存吞吐量也得大於200GB/s,否則肯定會產生擁塞的情況。如果匯流排帶寬不夠了,得搞更寬的匯流排,或者搞多條匯流排,立體矩陣操作,類似於立交橋。如果一個內存不夠了,那就得採用多通道了。並且這時候多通道得統一編碼,例如奇地址在1通道,偶地址在0通道,確保瞬時帶寬也是滿足。而不是低的那一半地址在0通道,高的那一半地址在1通道。

我沒做過GPU,但以我的理解,共享內存對GPU的影響更大,因為GPU是有大量並行運算單元的,不適合用Cache(和代碼的空間相關性有關),而是適合大量的流水數據操作,因此GPU對內存帶寬要求比CPU高的多,所以共享帶寬,一般是喂不飽GPU的,也不適合用在高端顯卡上。(另外一個很難餵飽的是AI處理器,所以有些都提出存算一體了,內存和處理單元放在一起。不搞匯流排。)

在SoC設計,CPU設計的時候,架構非常非常重要,需要仔細評估,以避免某個地方成為性能瓶頸。但使用場景變化多端,如上網場景,遊戲場景,看電影場景,做渲染場景,差別很大,很難找到一個架構策略適合所有的情形,因此需要採用合適的演算法,通過多個角度,驗證多種Benchmark,在多個指標中權衡,以達到最大效率利用每一個時鐘,PPA達到最佳,這是非常難的一項技術。現在的SoC,除了一堆大小核的CPU,一堆GPU,還有NPU,ISP,CODEC,BB......,個個都是吃內存的主,要搞個好的架構,難度極大,不小心就翻車:跑分很高,使用體驗很差,或者頻率很高,溫度高到可以煎雞蛋,性能還跑不過別人的低端型號(歡迎對號入座:D )。。。

回頭整點架構圖嚇嚇大家。


我也不是完全懂這一方面,但試著講一下我的認知:

顯存掛在顯存控制器上,內存掛在內存控制器上,所有的讀寫操作都要經過相應的控制器

顯存控制器在GPU里,內存控制器以前在北橋上,後來整合進CPU里,MCP的ryzen則是在IO die上。

看見上面的Memory Controller了嘛,這是連接內存的唯一通道。

然後先是CPU寫顯存——CPU是夠不到顯存的。OS層面可以把要傳輸的信息交給驅動,而驅動則利用PCIE之類匯流排的特性去傳輸信息,這時候一般是靠DMA。

然後GPU讀內存——GPU事實上也是夠不到內存的,也得靠DMA。

DMA控制器是一個獨特的單元,可以理解為memcpy函數,你把拷貝的範圍傳給它,它會完成拷貝操作然後發出完成信號

顯然,DMA控制器也是依賴於內存/顯存控制器的

然後可以回答問題了:


會衝突嗎?不會,歸根究底都是x存控制器在訪存,不會兩個設備同時訪問一個內存。理解為需要排隊就行(請求隊列)。

但是如果你說的衝突是指「host和device訪問同一片內存的順序不同導致不符合預期的行為」,那是會的,所以跟多線程一樣需要適當的同步

而驅動這邊也會做一些相應的操作,比如通常會把要傳輸的數據放到non-pagable的頁面以供DMA單元非同步處理。或者有些UMA也允許GPU訪存缺頁,然後GPU會發信號回CPU讓OS去處理缺頁。


會不會影響效率?這個可以從很多角度看。

CPU會不會無時無刻地用滿內存控制器的寬頻?不會的話把空閑的資源分給GPU的DMA也行。當然DMA也分很多形式,實際運行方式/效率/帶寬限制也跟硬體設計很有關係(比如Intel的ringbus/mesh,AMD的IF)。

對於獨顯,顯存不用去用內存不是吃飽了撐的嘛。顯存本來帶寬就高很多,更別說PCIE的帶寬還不如內存。光是多路CPU的NUMA節點問題都能造成訪存效率的區別,CPU、GPU這種外設共享內存當然也會帶來很低的效率。

核顯的話一般是不走PCIE的,但依舊會被內存帶寬卡住脖子。這不能怪衝突,而是本身內存帶寬自己的瓶頸。

所以API一般都允許傳入一些hint,比如這部分內存GPU只讀/CPU不讀不寫等,這樣驅動可以選擇把數據從內存搬到顯存,將「遠程訪問」轉為「本地訪問」

再比如OpenCL2.0引入的SVM,說是「shared virtual memory」,但這並不保證GPU就是在訪問內存,因為SVM依舊有「粗粒度」、「細粒度」的區別[1]

對於粗粒度的SVM,手工的同步依舊是需要的,只不過CPU、GPU可以用同一套內存地址而已。驅動完全可以在同步點後把數據從內存挪到顯存,然後GPU上構建出頁表使得同一個虛擬地址能對應到正確的顯存位置而已。

至於細粒度的SVM,實現起來會麻煩很多,似乎還沒獨顯實現過?

核顯的話,Intel的GTI掛在ringbus上,所以可以靠ringbus提供的snoop支持,GPU相當於一個物理核心。AMD這邊的話這是靠IF的同步支持,GPU相當於一個CCX。

對應的數據同步就轉化成了緩存同步/NUMA節點同步問題了。

參考

  1. ^SVM https://software.intel.com/content/www/us/en/develop/articles/opencl-20-shared-virtual-memory-overview.html


很顯然,GPU的執行周期起碼要比CPU慢1 - 2幀,一些傳統的圖形API比如DX11,將這個過程封裝了起來,但是基本原理並不改變,現代一點的API早就把CPU傳數據到GPU和GPU自己用數據這兩個步驟暴露出來了,因此從編程的設計模式上就可以規避訪問衝突問題,保證CPU正在寫入的顯存空間和GPU正在使用的完全不是一個地方。這個步驟可以劃分為: 上傳-&>複製-&>使用,上傳過程是可以在GPU執行的前一幀由CPU + DMA完成,屬於非同步操作,而複製則是GPU自己的工作,可以使用Copy Engine完成,通過標記GPU Multi-Engine之間的依賴關係,確保在主執行隊列用到數據之前就已經複製完成,算是半非同步,到最後一套操作下來大部分都是非同步的而且一般這些非同步操作也很難構成性能短板,因此對實際性能並沒有什麼影響。

不僅上傳數據,下載數據或者說回讀數據,也是經過同樣的步驟,而且也是可以完全非同步的,部分遊戲引擎,尤其是對商業化重視程度遠超對技術本身研究的某些商業引擎,在這方面僅僅做到了「能跑的起來」的程度,甚至離能用還差很遠,但是這顯然不是硬體和驅動設計者的鍋。


以我粗淺的理解寫兩句。

前面有回答提到內存的bank多所以沒事的,不對。DDR的介面就不是全雙工的,跟裡面bank的讀寫是不是可以並行沒關係。雙埠乃至多埠SRAM確實有,但是也和DDR不一樣。

其實這個問題應該是PCIe設備訪問共享內存的問題,如果不是顯卡而是別的設備也一樣。效率上,讀寫的突髮長度夠大時,帶寬應該是可以利用的比較好的。

具體是不是帶寬限制了應用的性能呢?首先還是看計算和訪存的比例。具體到帶寬上也得分析,一般來說PCIe的帶寬還是比內存帶寬差點的,但是也在一個量級了,兩者都可能成為瓶頸。沒做過具體分析所以不好說。


你隨便找一個單雙通道內存的遊戲測試,幾乎都能看到雙通道有一定提升,雖然一般不會太多,5%~10%左右。

所以,衝突是肯定有的,但也沒有你想像得嚴重。雙通道內存就是某種程度上緩解這個問題的一個方案。

一個比較嚴重的特例是AMD的APU,因為APU拿內存當顯存用,AMD的核顯性能又比較強,數據讀寫頻繁,和容易就和CPU發生衝突。


當然不會衝突啊...

存儲器多埠這種操作也不是什麼新技術了...

一般來說存儲器,無論是DRAM還是SRAM,都會分成好幾個bank,每個bank是一個單獨的存儲裝置,各自存儲各自的數據,但是每個bank只有一個埠進行讀寫。

各個bank之間的一般是插著編址的。(以下我都用十進位)

比如說我們有4個bank,那麼我們給bank0編址,地址除以16餘0、1、2、3(也就是只存儲地址是0-3、16-19、32-35、...的數據)

bank1的數據的地址除以16餘4、5、6、7(也就是只存儲地址是4-7、20-23、36-39、...的數據)

以此類推,bank2餘數是8、9、10、11;bank3餘數是12、13、14、15。

這樣的話,假設GPU和CPU取數據,一次只取4個位元組,那麼大部分時候是不會衝突的。比如說CPU要讀36-39這些數據,那麼讀bank0就可以了;同時GPU要讀12-15這些數據,那麼讀bank3就可以了,互不干擾。

如果恰好他們同時要訪問同一個bank,那麼就會出現衝突。而這種情況的幾率只有1/(4*4)=1/16。

如果你多分幾個bank,那麼這個幾率可以進一步下降,bank越多,衝突幾率就越小。

當然,現實中的GPU和CPU不會一次只取4個位元組。所以一般編址不是除以16,而是除以256什麼的,甚至更大。


答案是不一定。

根據你問題的描述,這兩個操作分別是:

  1. cpu寫顯存
  2. gpu讀內存

要說明這個問題,首先需要知道PCIe互連匯流排的系統結構。

上圖是一個基於PCIe匯流排的處理器系統,圖中最核心的就是一個叫做RC(Root Complex,根複合體)的結構,在X86的實現中,它被叫做北橋。從圖中我們可以看出,RC的作用主要就是:

1)與CPU通過FSB(Front Side bus,前端匯流排,在這裡是指CPU與RC連接的一類匯流排)連接;

2)內置內存控制器,用於連接DRAM;

3)內置FSB-PCIe橋,連接PICe設備。

根據上面這幅圖我們可以知道,問題中給出的兩個數據通路分別是:

1)CPU寫顯存實際上是數據由FSB通過虛擬PCI橋到FSB-PCIe橋,從而將數據寫到位於顯卡的顯存上;

2)GPU讀內存實際上是數據由FSB-PCIe橋到Memory控制器再到Host Memory的過程。

在上述兩個過程中,PCI匯流排1 和 PCI匯流排0 被讀寫過程都使用到了,對於讀內存和寫顯存都需要佔用PCI匯流排1中向顯卡寫數據的通道,但是PCIe匯流排本身是包交換的結構,有沒有衝突需要看你怎麼定義衝突(因為包交換都需要放到FIFO裡面,流式的處理)以及這兩個讀寫事務發起的時間(因為如果事務發起時間相同的話,明顯GPU讀的寫回過程會較晚提交到FSB-PCIe橋上);而PCI匯流排0就比較複雜了,它本身只是一個虛擬的PCI匯流排,實際的電氣連接還是使用FSB,因此,訪問是否衝突完全取決於FSB具體是什麼樣的結構,所以答案是不一定。


其他回答中提到了顯存共享存儲的問題,實際上,這是一個關於計算機系統中不同地址空間的問題,而這些地址空間,都是由RC進行管理的。

在PCIe匯流排系統中,地址空間包含這樣幾種:CPU地址空間,PCI地址空間,DRAM地址空間。

CPU地址空間,就是所有內容對CPU來說都是可見的,而該地址空間中存儲的內容包括了Host Memory中的數據,PCI匯流排掛在的設備上的BAR空間等。

PCI地址空間是PCI端設備的地址空間,可以說顯存就是位於顯卡的PCI地址空間。它對於PCI端設備是完全可見的,但對於處理器來說,只有部分內容可見(位於BAR空間中的),而且只能通過RC進行地址空間轉換以後才能訪問(在X86架構下,這兩個地址空間的地址相同,所以給人們的感覺就像是沒有地址空間的轉換)。

DRAM地址空間是指DRAM控制器所能訪問的地址空間的集合,在一些系統中,CPU域並不能完全包含DRAM域,就是說,DRAM中還有些地址是CPU不能訪問的。

從上面的說明中我們可以知道,顯存屬於PCI域,而我們一般說的內存屬於CPU域,指向的物理實體可能會有所重疊,但本身是完全不同的兩個地址空間。


你在問題中提出」統一定址,就避免不了衝突「的說法,實際上現在的FSB匯流排連接很多都已經不是電路交換,而是包交換了(如QPI),可以說你提出的這個問題,人們已經從另一個角度最大限度的解決了。


不會衝突。

CPU和GPU都通過內存控制器(MCU)訪問內存。他們可以同時訪問內存控制器,然後再到內存。

對於內存控制器來說是CPU還是GPU來訪問他沒有區別。就好比是多個CPU核心在訪問MCU一樣,並不會有什麼衝突。

至於速度,按照我的理解,CPU到內存 帶寬一般不是瓶頸(CPU本身的速度沒有那麼快,不需要很高的帶寬,但是需要很快的響應)。但是GPU到內存的瓶頸一直是帶寬,顯卡上帶寬就不夠。好在總的來說核顯性能都沒有獨顯那麼高,對帶寬的需求也沒獨顯那麼高。


阻塞問題是工作站上深度學習訓練的一個問題,目前的內存架構確實在不少情況下會成為瓶頸之一。所以我想是不是可以GPU直連高速SSD,形成流水線可以對不少場景有比較強的加速。


Arm系統上,軟體保證不了,有硬體鎖保證,不僅cpu,gpu,還有別的加速器,比如dma控制器,訪問內存會衝突,簡單的,只有一個源,複雜的,根據地址,看是否衝突。

就這樣,還有衝突的,反正內存被改寫了,很麻煩,要查幾天了。得解決掉。

x86不清楚,應該也有。


第一,顯存並不總是共享的。比如4g顯存,有時候只有2M是共享的。

共享意思就是把顯存映射到物理地址空間上,按32位顏色來算,1920x1080解析度算,需要1920x1080x4=7.9M。

而現在顯卡都是幾個G的,那大部分顯存是cpu訪問不了的。

而且CPU訪問顯存很慢,一般只寫,不讀,如果需要讀取,就用一塊內存做緩存,寫的時候顯存跟內存緩存一起寫,讀的時候從緩存讀取。

而GPU訪問顯存有自己的訪問方式,不需要通過CPU匯流排。


推薦閱讀:
相关文章