每個程式設計師都應該瞭解的記憶體知識(二)
http://web.itivy.com/article-347-1.html
接下來的章節會涉及更多的有關訪問DRAM儲存器的實際操作的細節。我們不會提到更多有關訪問SRAM的具體內容,它通常是直接定址。這裡是由於速度和有限的SRAM儲存器的尺寸。SRAM現在應用在CPU的快取記憶體和晶片,它們的連線件很小而且完全能在CPU設計師的掌控之下。我們以後會討論到CPU快取記憶體這個主題,但我們所需要知道的是SRAM儲存單元是有確定的最大速度,這取決於花在SRAM上的艱難的嘗試。這速度與CPU核心相比略慢一到兩個數量級。
2.2 DRAM訪問細節
在上文介紹DRAM的時候,我們已經看到DRAM晶片為了節約資源,對地址進行了複用。而且,訪問DRAM單元是需要一些時間的,因為電容器的放電並不是瞬時的。此外,我們還看到,DRAM需要不停地重新整理。在這一節裡,我們將把這些因素拼合起來,看看它們是如何決定DRAM的訪問過程。
我們將主要關注在當前的科技上,不會再去討論非同步DRAM以及它的各種變體。如果對它感興趣,可以去參考[highperfdram]及[arstechtwo]。我們也不會討論Rambus DRAM(RDRAM),雖然它並不過時,但在系統記憶體領域應用不廣。我們將主要介紹同步DRAM(SDRAM)及其後繼者雙倍速DRAM(DDR)。
同步DRAM,顧名思義,是參照一個時間源工作的。由記憶體控制器提供一個時鐘,時鐘的頻率決定了前端匯流排(FSB)的速度。FSB是記憶體控制器提供給DRAM晶片的介面。在我寫作本文的時候,FSB已經達到800MHz、1066MHz,甚至1333MHz,並且下一代的1600MHz也已經宣佈。但這並不表示時鐘頻率有這麼高。實際上,目前的匯流排都是雙倍或四倍傳輸的,每個週期傳輸2次或4次資料。報的越高,賣的越好,所以這些廠商們喜歡把四倍傳輸的200MHz匯流排宣傳為“有效的”800MHz匯流排。
以今天的SDRAM為例,每次資料傳輸包含64位,即8位元組。所以FSB的傳輸速率應該是有效匯流排頻率乘於8位元組(對於4倍傳輸200MHz匯流排而言,傳輸速率為6.4GB/s)。聽起來很高,但要知道這只是峰值速率,實際上無法達到的最高速率。我們將會看到,與RAM模組交流的協議有大量時間是處於非工作狀態,不進行資料傳輸。我們必須對這些非工作時間有所瞭解,並儘量縮短它們,才能獲得最佳的效能。
2.2.1 讀訪問協議
圖2.8: SDRAM讀訪問的時序
圖2.8展示了某個DRAM模組一些聯結器上的活動,可分為三個階段,圖上以不同顏色表示。按慣例,時間為從左向右流逝。這裡忽略了許多細節,我們只關注時鐘頻率、RAS與CAS訊號、地址匯流排和資料匯流排。首先,記憶體控制器將行地址放在地址總線上,並降低RAS訊號,讀週期開始。所有訊號都在時鐘(CLK)的上升沿讀取,因此,只要訊號在讀取的時間點上保持穩定,就算不是標準的方波也沒有關係。設定行地址會促使RAM晶片鎖住指定的行。
CAS訊號在tRCD(RAS到CAS時延)個時鐘週期後發出。記憶體控制器將列地址放在地址總線上,降低CAS線。這裡我們可以看到,地址的兩個組成部分是怎麼通過同一條匯流排傳輸的。
至此,定址結束,是時候傳輸資料了。但RAM晶片任然需要一些準備時間,這個時間稱為CAS時延(CL)。在圖2.8中CL為2。這個值可大可小,它取決於記憶體控制器、主機板和DRAM模組的質量。CL還可能是半週期。假設CL為2.5,那麼資料將在藍色區域內的第一個下降沿準備就緒。
既然資料的傳輸需要這麼多的準備工作,僅僅傳輸一個字顯然是太浪費了。因此,DRAM模組允許記憶體控制指定本次傳輸多少資料。可以是2、4或8個字。這樣,就可以一次填滿快取記憶體的整條線,而不需要額外的RAS/CAS序列。另外,記憶體控制器還可以在不重置行選擇的前提下發送新的CAS訊號。這樣,讀取或寫入連續的地址就可以變得非常快,因為不需要傳送RAS訊號,也不需要把行置為非啟用狀態(見下文)。是否要將行保持為“開啟”狀態是記憶體控制器判斷的事情。讓它一直保持開啟的話,對真正的應用會有不好的影響(參見[highperfdram])。CAS訊號的傳送僅與RAM模組的命令速率(Command Rate)有關(常常記為Tx,其中x為1或2,高效能的DRAM模組一般為1,表示在每個週期都可以接收新命令)。
在上圖中,SDRAM的每個週期輸出一個字的資料。這是第一代的SDRAM。而DDR可以在一個週期中輸出兩個字。這種做法可以減少傳輸時間,但無法降低時延。DDR2儘管看上去不同,但在本質上也是相同的做法。對於DDR2,不需要再深入介紹了,我們只需要知道DDR2更快、更便宜、更可靠、更節能(參見[ddrtwo])就足夠了。
2.2.2 預充電與啟用
圖2.8並不完整,它只畫出了訪問DRAM的完整迴圈的一部分。在傳送RAS訊號之前,必須先把當前鎖住的行置為非啟用狀態,並對新行進行預充電。在這裡,我們主要討論由於顯式傳送指令而觸發以上行為的情況。協議本身作了一些改進,在某些情況下是可以省略這個步驟的,但預充電帶來的時延還是會影響整個操作。
圖2.9: SDRAM的預充電與啟用
圖2.9顯示的是兩次CAS訊號的時序圖。第一次的資料在CL週期後準備就緒。圖中的例子裡,是在SDRAM上,用兩個週期傳輸了兩個字的資料。如果換成DDR的話,則可以傳輸4個字。
即使是在一個命令速率為1的DRAM模組上,也無法立即發出預充電命令,而要等資料傳輸完成。在上圖中,即為兩個週期。剛好與CL相同,但只是巧合而已。預充電訊號並沒有專用線,某些實現是用同時降低寫使能(WE)線和RAS線的方式來觸發。這一組合方式本身沒有特殊的意義(參見[micronddr])。
發出預充電信命令後,還需等待tRP(行預充電時間)個週期之後才能使行被選中。在圖2.9中,這個時間(紫色部分)大部分與記憶體傳輸的時間(淡藍色部分)重合。不錯。但tRP大於傳輸時間,因此下一個RAS訊號只能等待一個週期。
如果我們補充完整上圖中的時間線,最後會發現下一次資料傳輸發生在前一次的5個週期之後。這意味著,資料匯流排的7個週期中只有2個週期才是真正在用的。再用它乘於FSB速度,結果就是,800MHz匯流排的理論速率6.4GB/s降到了1.8GB/s。真是太糟了。第6節將介紹一些技術,可以幫助我們提高匯流排有效速率。程式設計師們也需要儘自己的努力。
SDRAM還有一些定時值,我們並沒有談到。在圖2.9中,預充電命令僅受制於資料傳輸時間。除此之外,SDRAM模組在RAS訊號之後,需要經過一段時間,才能進行預充電(記為tRAS)。它的值很大,一般達到tRP的2到3倍。如果在某個RAS訊號之後,只有一個CAS訊號,而且資料只傳輸很少幾個週期,那麼就有問題了。假設在圖2.9中,第一個CAS訊號是直接跟在一個RAS訊號後免的,而tRAS為8個週期。那麼預充電命令還需要被推遲一個週期,因為tRCD、CL和tRP加起來才7個週期。
DDR模組往往用w-z-y-z-T來表示。例如,2-3-2-8-T1,意思是:
w 2 CAS時延(CL)
x 3 RAS-to-CAS時延(t RCD)
y 2 RAS預充電時間(t RP)
z 8 啟用到預充電時間(t RAS)
T T1 命令速率
當然,除以上的引數外,還有許多其它引數影響命令的傳送與處理。但以上5個引數已經足以確定模組的效能。
在解讀計算機效能引數時,這些資訊可能會派上用場。而在購買計算機時,這些資訊就更有用了,因為它們與FSB/SDRAM速度一起,都是決定計算機速度的關鍵因素。
喜歡冒險的讀者們還可以利用它們來調優系統。有些計算機的BIOS可以讓你修改這些引數。SDRAM模組有一些可程式設計暫存器,可供設定引數。BIOS一般會挑選最佳值。如果RAM模組的質量足夠好,我們可以在保持系統穩定的前提下將減小以上某個時延引數。網際網路上有大量超頻網站提供了相關的文件。不過,這是有風險的,需要大家自己承擔,可別怪我沒有事先提醒喲。
2.2.3 重充電
談到DRAM的訪問時,重充電是常常被忽略的一個主題。在2.1.2中曾經介紹,DRAM必須保持重新整理。……行在充電時是無法訪問的。[highperfdram]的研究發現,“令人吃驚,DRAM重新整理對效能有著巨大的影響”。
根據JEDEC規範,DRAM單元必須保持每64ms重新整理一次。對於8192行的DRAM,這意味著記憶體控制器平均每7.8125µs就需要發出一個重新整理命令(在實際情況下,由於重新整理命令可以納入佇列,因此這個時間間隔可以更大一些)。重新整理命令的排程由記憶體控制器負責。DRAM模組會記錄上一次重新整理行的地址,然後在下次重新整理請求時自動對這個地址進行遞增。
對於重新整理及發出重新整理命令的時間點,程式設計師無法施加影響。但我們在解讀效能引數時有必要知道,它也是DRAM生命週期的一個部分。如果系統需要讀取某個重要的字,而剛好它所在的行正在重新整理,那麼處理器將會被延遲很長一段時間。重新整理的具體耗時取決於DRAM模組本身。
2.2.4 記憶體型別
我們有必要花一些時間來了解一下目前流行的記憶體,以及那些即將流行的記憶體。首先從SDR(單倍速)SDRAM開始,因為它們是DDR(雙倍速)SDRAM的基礎。SDR非常簡單,記憶體單元和資料傳輸率是相等的。
圖2.10: SDR SDRAM的操作
在圖2.10中,DRAM單元陣列能以等同於記憶體匯流排的速率輸出內容。假設DRAM單元陣列工作在100MHz上,那麼匯流排的資料傳輸率可以達到100Mb/s。所有元件的頻率f保持相同。由於提高頻率會導致耗電量增加,所以提高吞吐量需要付出很高的的代價。如果是很大規模的記憶體陣列,代價會非常巨大。{功率 = 動態電容 x 電壓2 x 頻率}。而且,提高頻率還需要在保持系統穩定的情況下提高電壓,這更是一個問題。因此,就有了DDR SDRAM(現在叫DDR1),它可以在不提高頻率的前提下提高吞吐量。
圖2.11 DDR1 SDRAM的操作
我們從圖2.11上可以看出DDR1與SDR的不同之處,也可以從DDR1的名字裡猜到那麼幾分,DDR1的每個週期可以傳輸兩倍的資料,它的上升沿和下降沿都傳輸資料。有時又被稱為“雙泵(double-pumped)”匯流排。為了在不提升頻率的前提下實現雙倍傳輸,DDR引入了一個緩衝區。緩衝區的每條資料線都持有兩位。它要求記憶體單元陣列的資料匯流排包含兩條線。實現的方式很簡單,用同一個列地址同時訪問兩個DRAM單元。對單元陣列的修改也很小。
SDR DRAM是以頻率來命名的(例如,對應於100MHz的稱為PC100)。為了讓DDR1聽上去更好聽,營銷人員們不得不想了一種新的命名方案。這種新方案中含有DDR模組可支援的傳輸速率(DDR擁有64位匯流排):
100MHz x 64位 x 2 = 1600MB/s
於是,100MHz頻率的DDR模組就被稱為PC1600。由於1600 > 100,營銷方面的需求得到了滿足,聽起來非常棒,但實際上僅僅只是提升了兩倍而已。{我接受兩倍這個事實,但不喜歡類似的數字膨脹戲法。}
圖2.12: DDR2 SDRAM的操作
為了更進一步,DDR2有了更多的創新。在圖2.12中,最明顯的變化是,匯流排的頻率加倍了。頻率的加倍意味著頻寬的加倍。如果對單元陣列的頻率加倍,顯然是不經濟的,因此DDR2要求I/O緩衝區在每個時鐘週期讀取4位。也就是說,DDR2的變化僅在於使I/O緩衝區執行在更高的速度上。這是可行的,而且耗電也不會顯著增加。DDR2的命名與DDR1相仿,只是將因子2替換成4(四泵匯流排)。圖2.13顯示了目前常用的一些模組的名稱。
陣列頻率 匯流排頻率 資料率 名稱(速率) 名稱
(FSB)133MHz 266MHz 4,256MB/s PC2-4200 DDR2-533 166MHz 333MHz 5,312MB/s PC2-5300 DDR2-667 200MHz 400MHz 6,400MB/s PC2-6400 DDR2-800 250MHz 500MHz 8,000MB/s PC2-8000 DDR2-1000 266MHz 533MHz 8,512MB/s PC2-8500 DDR2-1066
圖2.13: DDR2模組名
在命名方面還有一個擰巴的地方。FSB速度是用有效頻率來標記的,即把上升、下降沿均傳輸資料的因素考慮進去,因此數字被撐大了。所以,擁有266MHz匯流排的133MHz模組有著533MHz的FSB“頻率”。
DDR3要求更多的改變(這裡指真正的DDR3,而不是圖形卡中假冒的GDDR3)。電壓從1.8V下降到1.5V。由於耗電是與電壓的平方成正比,因此可以節約30%的電力。加上管芯(die)的縮小和電氣方面的其它進展,DDR3可以在保持相同頻率的情況下,降低一半的電力消耗。或者,在保持相同耗電的情況下,達到更高的頻率。又或者,在保持相同熱量排放的情況下,實現容量的翻番。
DDR3模組的單元陣列將執行在內部匯流排的四分之一速度上,DDR3的I/O緩衝區從DDR2的4位提升到8位。見圖2.14。
圖2.14: DDR3 SDRAM的操作
一開始,DDR3可能會有較高的CAS時延,因為DDR2的技術相比之下更為成熟。由於這個原因,DDR3可能只會用於DDR2無法達到的高頻率下,而且頻寬比時延更重要的場景。此前,已經有討論指出,1.3V的DDR3可以達到與DDR2相同的CAS時延。無論如何,更高速度帶來的價值都會超過時延增加帶來的影響。
DDR3可能會有一個問題,即在1600Mb/s或更高速率下,每個通道的模組數可能會限制為1。在早期版本中,這一要求是針對所有頻率的。我們希望這個要求可以提高一些,否則系統容量將會受到嚴重的限制。
圖2.15顯示了我們預計中各DDR3模組的名稱。JEDEC目前同意了前四種。由於Intel的45nm處理器是1600Mb/s的FSB,1866Mb/s可以用於超頻市場。隨著DDR3的發展,可能會有更多型別加入。
圖2.15: DDR3模組名
陣列頻率 匯流排頻率 資料速率 名稱(速率) 名稱
(FSB)100MHz 400MHz 6,400MB/s PC3-6400 DDR3-800 133MHz 533MHz 8,512MB/s PC3-8500 DDR3-1066 166MHz 667MHz 10,667MB/s PC3-10667 DDR3-1333 200MHz 800MHz 12,800MB/s PC3-12800 DDR3-1600 233MHz 933MHz 14,933MB/s PC3-14900 DDR3-1866
所有的DDR記憶體都有一個問題:不斷增加的頻率使得建立並行資料匯流排變得十分困難。一個DDR2模組有240根引腳。所有到地址和資料引腳的連線必須被佈置得差不多一樣長。更大的問題是,如果多於一個DDR模組通過菊花鏈連線在同一個總線上,每個模組所接收到的訊號隨著模組的增加會變得越來越扭曲。DDR2規範允許每條匯流排(又稱通道)連線最多兩個模組,DDR3在高頻率下只允許每個通道連線一個模組。每條匯流排多達240根引腳使得單個北橋無法以合理的方式驅動兩個通道。替代方案是增加外部記憶體控制器(如圖2.2),但這會提高成本。
這意味著商品主機板所搭載的DDR2或DDR3模組數將被限制在最多四條,這嚴重限制了系統的最大記憶體容量。即使是老舊的32位IA-32處理器也可以使用64GB記憶體。即使是家庭對記憶體的需求也在不斷增長,所以,某些事必須開始做了。
一種解法是,在處理器中加入記憶體控制器,我們在第2節中曾經介紹過。AMD的Opteron系列和Intel的CSI技術就是採用這種方法。只要我們能把處理器要求的記憶體連線到處理器上,這種解法就是有效的。如果不能,按照這種思路就會引入NUMA架構,當然同時也會引入它的缺點。而在有些情況下,我們需要其它解法。
Intel針對大型伺服器方面的解法(至少在未來幾年),是被稱為全緩衝DRAM(FB-DRAM)的技術。FB-DRAM採用與DDR2相同的器件,因此造價低廉。不同之處在於它們與記憶體控制器的連線方式。FB-DRAM沒有用並行匯流排,而用了序列匯流排(Rambus DRAM had this back when, too, 而SATA是PATA的繼任者,就像PCI Express是PCI/AGP的繼承人一樣)。序列匯流排可以達到更高的頻率,序列化的負面影響,甚至可以增加頻寬。使用序列匯流排後
- 每個通道可以使用更多的模組。
- 每個北橋/記憶體控制器可以使用更多的通道。
- 序列匯流排是全雙工的(兩條線)。
FB-DRAM只有69個腳。通過菊花鏈方式連線多個FB-DRAM也很簡單。FB-DRAM規範允許每個通道連線最多8個模組。
在對比下雙通道北橋的連線性,採用FB-DRAM後,北橋可以驅動6個通道,而且腳數更少——6x69對比2x240。每個通道的佈線也更為簡單,有助於降低主機板的成本。
全雙工的並行匯流排過於昂貴。而換成序列線後,這不再是一個問題,因此序列匯流排按全雙工來設計的,這也意味著,在某些情況下,僅靠這一特性,匯流排的理論頻寬已經翻了一倍。還不止於此。由於FB-DRAM控制器可同時連線6個通道,因此可以利用它來增加某些小記憶體系統的頻寬。對於一個雙通道、4模組的DDR2系統,我們可以用一個普通FB-DRAM控制器,用4通道來實現相同的容量。序列匯流排的實際頻寬取決於在FB-DRAM模組中所使用的DDR2(或DDR3)晶片的型別。
我們可以像這樣總結這些優勢:
DDR2 FB-DRAM
DDR2 FB-DRAM 腳 240 69 通道 2 6 每通道DIMM數 2 8 最大記憶體 16GB 192GB 吞吐量 ~10GB/s ~40GB/s
如果在單個通道上使用多個DIMM,會有一些問題。訊號在每個DIMM上都會有延遲(儘管很小),也就是說,延遲是遞增的。不過,如果在相同頻率和相同容量上進行比較,FB-DRAM總是能快過DDR2及DDR3,因為FB-DRAM只需要在每個通道上使用一個DIMM即可。而如果說到大型記憶體系統,那麼DDR更是沒有商用元件的解決方案。
2.2.5 結論
通過本節,大家應該瞭解到訪問DRAM的過程並不是一個快速的過程。至少與處理器的速度相比,或與處理器訪問暫存器及快取的速度相比,DRAM的訪問不算快。大家還需要記住CPU和記憶體的頻率是不同的。Intel Core 2處理器執行在2.933GHz,而1.066GHz FSB有11:1的時鐘比率(注: 1.066GHz的匯流排為四泵匯流排)。那麼,記憶體總線上延遲一個週期意味著處理器延遲11個週期。絕大多數機器使用的DRAM更慢,因此延遲更大。在後續的章節中,我們需要討論延遲這個問題時,請把以上的數字記在心裡。
前文中讀命令的時序圖表明,DRAM模組可以支援高速資料傳輸。每個完整行可以被毫無延遲地傳輸。資料匯流排可以100%被佔。對DDR而言,意味著每個週期傳輸2個64位字。對於DDR2-800模組和雙通道而言,意味著12.8GB/s的速率。
但是,除非是特殊設計,DRAM的訪問並不總是序列的。訪問不連續的記憶體區意味著需要預充電和RAS訊號。於是,各種速度開始慢下來,DRAM模組急需幫助。預充電的時間越短,資料傳輸所受的懲罰越小。
硬體和軟體的預取(參見第6.3節)可以在時序中製造更多的重疊區,降低延遲。預取還可以轉移記憶體操作的時間,從而減少爭用。我們常常遇到的問題是,在這一輪中生成的資料需要被儲存,而下一輪的資料需要被讀出來。通過轉移讀取的時間,讀和寫就不需要同時發出了。
2.3 主存的其它使用者
除了CPU外,系統中還有其它一些元件也可以訪問主存。高效能網絡卡或大規模儲存控制器是無法承受通過CPU來傳輸資料的,它們一般直接對記憶體進行讀寫(直接記憶體訪問,DMA)。在圖2.1中可以看到,它們可以通過南橋和北橋直接訪問記憶體。另外,其它匯流排,比如USB等也需要FSB頻寬,即使它們並不使用DMA,但南橋仍要通過FSB連線到北橋。
DMA當然有很大的優點,但也意味著FSB頻寬會有更多的競爭。在有大量DMA流量的情況下,CPU在訪問記憶體時必然會有更大的延遲。我們可以用一些硬體來解決這個問題。例如,通過圖2.3中的架構,我們可以挑選不受DMA影響的節點,讓它們的記憶體為我們的計算服務。還可以在每個節點上連線一個南橋,將FSB的負荷均勻地分擔到每個節點上。除此以外,還有許多其它方法。我們將在第6節中介紹一些技術和程式設計介面,它們能夠幫助我們通過軟體的方式改善這個問題。
最後,還需要提一下某些廉價系統,它們的圖形系統沒有專用的視訊記憶體,而是採用主存的一部分作為視訊記憶體。由於對視訊記憶體的訪問非常頻繁(例如,對於1024x768、16bpp、60Hz的顯示設定來說,需要95MB/s的資料速率),而主存並不像顯示卡上的視訊記憶體,並沒有兩個埠,因此這種配置會對系統性能、尤其是時延造成一定的影響。如果大家對系統性能要求比較高,最好不要採用這種配置。這種系統帶來的問題超過了本身的價值。人們在購買它們時已經做好了效能不佳的心理準備。