2009-12-26 134 views
20

我的unix/windows C++應用程序已經使用MPI進行了並行化:作業被拆分爲N cpus,並且每個塊都並行執行,相當高效,非常好的速度調整,作業完成正確。共享內存,MPI和排隊系統

但是有些數據在每個過程中都會重複出現,而且由於技術原因,這些數據不能通過MPI(...)輕鬆拆分。 例如:

  • 5靜態數據,每個進程加載
  • 4 GB的數據,可以在MPI分佈完全相同的東西的GB,所述多個CPU被使用,更小的這個每個CPU RAM是。

對於一個4 CPU的工作,這意味着至少20Gb的RAM負載,大部分內存'浪費',這是可怕的。

我在考慮使用共享內存來減少整體負載,每個計算機只能加載一次「靜態」塊。

所以,主要的問題是:

  • 有什麼標準MPI方式在一個節點上共享內存?某種現成的+免費圖書館?

    • 如果不是,我會使用boost.interprocess並使用MPI調用來分配本地共享內存標識符。
    • 共享內存將由每個節點上的「本地主機」讀取,並且共享只讀。不需要任何形式的信號/同步,因爲它不會改變。
  • 是否有任何性能問題或需要特別注意的問題?

    • (有不會是任何「串」或過於怪異的數據結構,什麼都可以降至陣列和結構指針)
  • 該作業將在PBS中執行(或SGE )排隊系統,在進程不乾淨的情況下退出,我想知道這些是否會清理節點特定的共享內存。

+0

答案到目前爲止,測試和進一步的讀數,內存映射文件可能是最簡單的選擇: - 只有主MPI進程需要「準備」內存文件,這將被所有進程映射。 - 由於該文件將是隻讀的,因此不需要擔心內容的一致性。 - 沒有關於性能的想法壽命...也許只有實驗才能說明。 – Blklight 2009-12-27 15:50:24

+0

性能完全取決於您的平臺。你的細節很稀疏,但是考慮到你可用的CPU和RAM,你不應該有一個大問題。如果您需要更改共享內存(您的分佈式數據),則不需要共享內存的內容是持久性的,只需要共享內存即可。在這種情況下,您的系統將浪費大量時間將所有內存更改寫入磁盤。 – 2010-01-10 05:38:35

+0

已經離開,不能選擇最後的答案,最多的一個得到它:) 但無論如何,很多好的答案四周,但沒有什麼回答我正在尋找的東西,所以我想沒有廣泛的標準的方式來做到這一點! – Blklight 2010-01-11 19:40:28

回答

9

高性能計算(HPC)中一個日益普遍的方法是混合MPI/OpenMP程序。即你有N個MPI進程,每個MPI進程有M個線程。這種方法很好地映射到由共享內存多處理器節點組成的集羣。

更改爲這樣的分層並行化方案顯然需要一些或多或少的侵入性更改,OTOH如果正確完成,除了減少複製數據的內存消耗外,還可以提高代碼的性能和可伸縮性。

根據MPI實現,您可能會也可能不會從所有線程進行MPI調用。這由MPI_Init_Thread()函數的參數requiredprovided指定,您必須調用該函數而不是MPI_Init()。可能的值是

 
{ MPI_THREAD_SINGLE} 
    Only one thread will execute. 
{ MPI_THREAD_FUNNELED} 
    The process may be multi-threaded, but only the main thread will make MPI calls (all MPI calls are ``funneled'' to the main thread). 
{ MPI_THREAD_SERIALIZED} 
    The process may be multi-threaded, and multiple threads may make MPI calls, but only one at a time: MPI calls are not made concurrently from two distinct threads (all MPI calls are ``serialized''). 
{ MPI_THREAD_MULTIPLE} 
    Multiple threads may call MPI, with no restrictions. 

以我的經驗,現代MPI實現如Open MPI支持最靈活MPI_THREAD_MULTIPLE。如果您使用較舊的MPI庫或某些專門的體系結構,則可能會變得更糟。

當然,您不需要使用OpenMP進行線程處理,這只是HPC中最受歡迎的選項。您可以使用例如Boost線程庫,Intel TBB庫或者直線pthread或windows線程。

+0

如果您將代碼更改爲每個共享內存多處理器節點上的多線程,請確保仔細編寫線程調度,以將高速緩存局部性和其他內存體系結構考慮在內。 – stephan 2010-01-07 07:20:07

+2

我不確定混合方法越來越普遍。這裏有一個證據表明,它可能不是一種值得采取的方法 - http://www.pdc.kth.se/education/historical/2008/PRACE-P2S2/coursework/handouts.html#hybrid 是的,這是一個很好的概念,但是與修改應用程序所需的努力相比,它在實踐中存在可疑的價值。 – 2010-01-07 09:47:07

+0

此答案未解決問題 – lurscher 2012-01-17 21:47:25

0

我不太瞭解unix,我不知道MPI是什麼。但在Windows中,您所描述的是文件映射對象的精確匹配。

如果這些數據嵌入在您加載的.EXE或.DLL文件中,那麼它將自動在所有進程之間共享。即使崩潰導致您的流程被破壞,也不會導致數據泄露或未公佈的鎖定。然而一個9Gb .dll聽起來有點不對勁。所以這可能不適合你。

但是,您可以將您的數據放入一個文件,然後CreateFileMappingMapViewOfFile就可以了。該映射可以是隻讀的,您可以將全部或部分文件映射到內存中。所有進程將共享映射到同一底層CreateFileMapping對象的頁面。關閉取消映射視圖和關閉句柄是一個很好的做法,但是如果操作系統不會在拆卸時爲你做。

請注意,除非您運行的是x64,否則您將無法將5Gb文件映射到單個視圖(甚至是2Gb文件,1Gb可能會工作)。但鑑於你所談論的是已經有效,我猜你已經只有x64了。

+0

從文檔中,我推斷boost.interprocess允許以跨平臺的方式(不需要#ifdef)和「乾淨的」代碼來做到這一點。還有一個特定於Windows的選項,可以準確地描述你所描述的內容。 但是,這裏問題的關鍵不在於共享內存系統的技術實現,而是如何在8核心機器上分佈128個應用程序實例時乾淨利落地完成此操作:-) – Blklight 2009-12-26 22:17:46

+1

我不確定爲什麼那會是一個問題。你是說你想分享多個_machines_。我很確定每臺機器只會看到它自己的內存,並且機器上的所有內核都共享該機器內存的視圖。 – 2009-12-26 22:35:06

0

如果您將靜態數據存儲在文件中,則可以在unix上使用mmap來隨機訪問數據。當您需要訪問特定位的數據時,數據將被分頁。所有你需要做的是覆蓋文件數據上的任何二進制結構。這是上面提到的CreateFileMapping和MapViewOfFile的unix等價物。

順便說一下,當調用malloc來請求多於一頁數據時,glibc使用mmap。

+0

glibc malloc mmap閾值默認爲128 kB,與頁面大小不同。 – janneb 2010-01-07 06:05:25

7

我沒有使用MPI,但是如果它像其他IPC庫一樣,我已經看到隱藏其他線程/進程/不管是在相同或不同的機器上,那麼它將無法保證共享記憶。是的,它可以處理同一臺機器上兩個節點之間的共享內存,如果該機器本身提供了共享內存的話。但由於複雜的一致性問題的出現,試圖在不同機器上的節點之間共享內存將會非常困難。我希望它只是未被實現。

實際上,如果您需要在節點之間共享內存,最好的辦法是在MPI之外執行此操作。我不認爲你需要使用boost.interprocess風格的共享內存,因爲你沒有描述不同節點對共享內存進行細粒度更改的情況;它不是隻讀就是分區。

John's和deus的答案涵蓋了如何映射文件,這對於5 Gb(giga bit?)靜態數據來說肯定是您想要做的。每個CPU數據聽起來都是一樣的,你只需要向每個節點發送一條消息,告訴它它應該抓取的文件的哪一部分。操作系統應負責將虛擬內存映射到文件的物理內存。

至於清理......我認爲它不會對共享內存進行任何清理,但mmap ed文件應該清理完畢,因爲在清理進程時文件已關閉(應該釋放它們的內存映射) 。我不知道有什麼告誡CreateFileMapping等。

實際的「共享內存」(即boost.interprocess)在進程死亡時未被清除。如果可能的話,我會建議嘗試殺死一個進程並查看留下的內容。

0

我在SHUT中有一些MPI項目。

我所知,有很多方法來分發問題使用MPI,也許你能找到不要求共享內存的另一個解決方案, 我的計劃解決的7000000方程和7000000可變

如果你可以解釋你的問題,我會盡力幫你

+0

當然,問題的「靜態」部分可以更好地並行化,但開發時間會很長。 「完整」問題的大部分內存都可以在每個計算節點上加載*一次*。所以,我的目標是共享內存,並瞄準最好的技術來做到這一點! – Blklight 2009-12-29 02:56:33

+0

我想知道的是你解決的問題有7 * 10^6個變量。 – 2010-01-05 03:01:57

2

有了MPI-2,你可以通過MPI_Put和MPI_Get等函數獲得RMA(遠程內存訪問)。使用這些功能,如果你的MPI安裝支持它們,肯定會幫助你減少程序的總內存消耗。成本增加了編碼的複雜性,但這是並行編程的樂趣之一。然後再次,它確實讓你在MPI的領域。

+0

這不會極大地增加訪問共享內存的延遲嗎?或者MPI_Get只是一個通過內存總線直接獲取的別名? – Crashworks 2010-01-06 23:05:13

+0

@Crashworks是的,MPI-2 RMA實際上並沒有比傳統的Send/Recv更快。在很多情況下,由於需要註冊內存窗口,速度較慢。原則上,在未來的特殊網絡硬件支持下,它可能會變得更快,但今天沒有理由使用它。 – janneb 2010-01-07 06:06:59

+0

是的。但是也許使用MPI2 RMA的一個理由是在MPI範例內進行共享內存編程,而不必求助於內存映射文件或IPC庫等低級功能。較低的執行性能成本可能會大大降低開發性能。我想知道OP在做什麼。 – 2010-01-08 09:17:27

0

幾年前我用MPI的時候遇到過這個問題。

我不確定SGE是否理解內存映射文件。如果你正在分發一個beowulf集羣,我懷疑你會遇到一致性問題。你能否談談你的多處理器體系結構?

我的草案方法是設置一個架構,其中數據的每個部分都由定義的CPU擁有。會有兩個線程:一個線程是MPI雙向通話器,另一個線程用於計算結果。請注意,MPI和線程並不總是一起玩。

+0

中的任何問題是,數據僅由一個CPU擁有,並且是隻讀的。這裏沒有一致性問題。所以,內存映射文件可能是一個簡單的選擇。 – Blklight 2010-01-08 05:01:23

+0

同意。但這將取決於你的架構。 memmapped文件在共享內存體系結構中最好。我不確定*你會怎麼做,以及一個beowulf集羣。 – 2010-01-08 16:46:00