2011-01-29 107 views
15

假設你有一個巨大的(40+ GB)特徵值(浮點)矩陣,行是不同的特徵,列是樣本/圖像。如何在內存映射一個巨大的矩陣?

該表是預計算列式。 然後它是完全訪問行和多線程(每個線程加載一整行)幾次。

什麼是處理這個矩陣的最好方法?我特別琢磨5點:

  1. 因爲它在一臺x64的PC上運行,我可以一次將內存映射到整個矩陣,但這樣做有道理嗎?
  2. 多線程(多線程初始計算呢?)的影響呢?
  3. 如何佈局矩陣:行或列主要?
  4. 在預計算完成後將矩陣標記爲只讀是否有幫助?
  5. 可以使用類似http://www.kernel.org/doc/man-pages/online/pages/man2/madvise.2.html的東西來加速嗎?
+0

這個問題可能會因爲*太有趣而關閉 - 但我希望不會。操作系統是否有限制? (從鏈接猜測Linux) – 2011-01-29 20:41:28

+0

我不明白爲什麼它可能會關閉,是否有一些規則我錯過了? 是的,該軟件目前僅限於Linux。但有關Windows的答案也是受歡迎的。 – Trass3r 2011-01-29 23:55:27

回答

5

內存映射整個文件可以使過程更容易。

您想佈置數據以針對最常見的訪問模式進行優化。這聽起來好像數據將被寫入一次(按列)並且被多次讀取(按行)。這表明數據應該按行優先順序存儲。

將矩陣標記爲只讀一次預計算完成可能不會有助於性能(有一些可能的低級優化,但我認爲沒有什麼實現它們),但它會防止錯誤意外地寫入您不想要的數據。不妨。

madvise可能最終變得有用,一旦你有你的應用程序編寫和工作。

我的總體建議是:先以最簡單的方式編寫程序,然後將計時器放在整個事物和各種主要操作中。確保主要操作時間總和爲總時間,所以你可以確定你沒有錯過任何東西。然後將您的性能改進工作針對實際花費最多時間的組件。您可能最終希望查看hugetlbfs或使用帶有透明大頁面支持的Linux內核版本(合併爲2.6.38,可能已修補到較早版本)。這可能會爲您節省大量的TLB缺失,並說服內核以足夠大的塊執行磁盤IO,以分攤任何尋道開銷。

+1

如果你沒有正確地訪問內存,你最終可能會陷入噩夢。如果發現緩慢,請確保您測量頁面錯誤。 zvrba涵蓋了他在答案中會看到的一些問題,特別是#3。我在90年代初期(20世紀到1年代)研究了一些類似的東西,以及由於錯誤而導致的事件徹底破壞。這是在64MB內存被認爲是最大化的時候。如果可以將頁面大小從4096更改爲4MB,則可以減少抖動(通過減少開銷)。 – JimR 2011-01-29 23:12:43

3
  1. 也許,見下文。
  2. 所有線程的總工作集大小不得超過可用RAM,否則程序將因交換而以蝸牛速度運行。
  3. 只要條件2得到遵守,佈局應匹配訪問模式。
  4. 你是什麼意思的「標記爲只讀」?
  5. 衡量它。

回覆3:如果您有,例如,8個CPU但沒有足夠的RAM來加載8行,你應該讓每個線程按照可管理的塊順序處理它的行。在這種情況下,矩陣的塊佈局是合理的。如果線程必須在內存中有整行來處理它,恐怕你不能使用所有的CPU,因爲這個過程會開始顛簸,也就是說,從ram中踢出一部分矩陣並重新加載另一個需要子集。這比完全交換稍差一點,因爲矩陣從未被修改,所以頁面的內容在被踢出之前不需要被寫入交換文件。但它仍然嚴重損害了業績。另外,從多個線程中進行隨機訪問I/O是一個壞主意,如果你使用mmap(),最終你會這樣做。你(大概)只有一個磁盤,並行I/O只會讓它變慢。所以mmap()可能沒有意義,您可以通過將數據順序讀入RAM來獲得更好的I/O性能。

請注意,40GB是大約1050萬個4096字節的頁面。通過執行mmap(),在最壞的情況下,你將會減少許多硬盤尋找的計算量。每次尋找8ms(取自維基百科),最終會浪費83666秒,即幾乎一整天!

2

如果你可以將整個事物放入主內存中,那麼是的:內存映射它的全部內容,無論它是列主要還是行主要都無關緊要。然而,在40+ Gb,我相信它對於主內存來說太大了。在這種情況下:

  1. 不,不要映射整個事情!至少,不要指望內存像普通內存一樣工作,如果你把它全部映射出來的話。如果你沒有正確處理I/O問題,你的程序將會永遠持續下去。
  2. 多線程訪問問題已解決,如果您將其存儲在行 - 主要(它聽起來像你沒有多線程列寫入)。
  3. 你應該按行進行佈局,假設每個單元格被寫入一次,然後讀取很多次。
  4. 是的,我認爲這會有助於在寫入矩陣後將其標記爲只讀,但純粹是爲了防止錯誤(意外寫入)。它不會影響性能。
  5. 不,沒有多少聰明的內核預讀將解決您的性能問題。你需要在算法級別解決它。

我想你會遇到一個天真實施的性能問題。無論是計算機在寫入時發生顛簸(如果您將其存儲爲主行),或者在查詢時(如果將其存儲在專欄中),它會發生顛簸。後者大概更糟糕,但這是一個雙向的問題。

正確的解決方案是使用既不是行大,也不是列大,而是「大方塊」的中間表示法。取第一個50,000列並將它們存儲在內存映射文件(階段1)中。不管它是列主要還是行主要,因爲它將是純粹的內存駐留。然後,獲取每一行並將其寫入最終行主內存映射文件(階段2)。然後重複下一個50,000列的循環,以此類推。