[英]MPI_SEND takes huge part of virtual memory
在大量內核上調試我的程序,我遇到了insufficient virtual memory
非常奇怪的錯誤。 我的調查導致代碼的和平,主機向每個從機發送小消息。 然后我寫了一個小程序,其中1個master只用MPI_SEND
發送10個整數,所有從站用MPI_RECV
接收它。 MPI_SEND
之前和之后的文件/proc/self/status
MPI_SEND
表明,內存大小之間的差異是巨大的! 最有趣的事情(崩潰我的程序)是,這個內存在MPI_Send
之后不會釋放,並且仍然需要占用大量空間。
有任何想法嗎?
System memory usage before MPI_Send, rank: 0
Name: test_send_size
State: R (running)
Pid: 7825
Groups: 2840
VmPeak: 251400 kB
VmSize: 186628 kB
VmLck: 72 kB
VmHWM: 4068 kB
VmRSS: 4068 kB
VmData: 71076 kB
VmStk: 92 kB
VmExe: 604 kB
VmLib: 6588 kB
VmPTE: 148 kB
VmSwap: 0 kB
Threads: 3
System memory usage after MPI_Send, rank 0
Name: test_send_size
State: R (running)
Pid: 7825
Groups: 2840
VmPeak: 456880 kB
VmSize: 456872 kB
VmLck: 257884 kB
VmHWM: 274612 kB
VmRSS: 274612 kB
VmData: 341320 kB
VmStk: 92 kB
VmExe: 604 kB
VmLib: 6588 kB
VmPTE: 676 kB
VmSwap: 0 kB
Threads: 3
這是幾乎任何在InfiniBand上運行的MPI實現的預期行為。 IB RDMA機制要求應該注冊數據緩沖區,即它們首先被鎖定在物理內存中的固定位置,然后驅動程序告訴InfiniBand HCA如何將虛擬地址映射到物理內存。 這是非常復雜的,因此注冊內存以供IB HCA使用的過程非常緩慢 ,這就是為什么大多數MPI實現永遠不會注冊曾經注冊的內存,希望以后將相同的內存再次用作源或數據目標。 如果已注冊的內存是堆內存,則它永遠不會返回到操作系統,這就是為什么您的數據段只會增大。
盡可能重用發送和接收緩沖區。 請記住,通過InfiniBand進行通信會導致高內存開銷。 大多數人並沒有真正考慮這個問題,而且通常記錄很少,但InfiniBand使用了許多特殊的數據結構(隊列),這些結構在進程的內存中分配,並且這些隊列隨着進程的數量而顯着增長。 在一些完全連接的情況下,隊列內存的數量可能很大,以至於實際上沒有為應用程序留下任何內存。
有一些參數可以控制英特爾MPI使用的IB隊列。 在您的情況下,最重要的是I_MPI_DAPL_BUFFER_NUM
,它控制預分配和預注冊內存的數量。 它的默認值是16
,所以你可能想減少它。 但請注意可能的性能影響。 您還可以通過將I_MPI_DAPL_BUFFER_ENLARGEMENT
設置為1
來嘗試使用動態預分配緩沖區大小。 啟用此選項后,Intel MPI最初會注冊小緩沖區,如果需要,稍后會增加它們。 另請注意,IMPI會延遲打開連接,這就是為什么只有在調用MPI_Send
之后才會看到使用內存大幅增加的原因。
如果不使用DAPL運輸,例如,使用ofa
運輸代替,沒有太多可以做的。 您可以通過將I_MPI_OFA_USE_XRC
設置為1
來啟用XRC隊列。 這應該以某種方式減少使用的內存。 如果程序的通信圖形未完全連接(完全連接的程序是每個級別與所有其他級別對話的程序),則通過將I_MPI_OFA_DYNAMIC_QPS
設置為1
來啟用動態隊列對創建可能會降低內存使用量。
Hristo的答案大多是正確的,但由於你使用的是小消息,所以有一點不同。 消息最終出現在急切路徑上:它們首先被復制到已經注冊的緩沖區,然后該緩沖區用於傳輸,接收方將消息從其末端的急切緩沖區中復制出來。 在代碼中重用緩沖區只會有助於處理大型郵件。
這樣做是為了避免注冊用戶提供的緩沖區的速度慢。 對於大型消息,副本比注冊時間更長,因此使用集合協議。
這些急切的緩沖區有點浪費。 例如,默認情況下,它們在具有OF動詞的英特爾MPI上為16kB。 除非使用消息聚合,否則每個10-int大小的消息正在占用4個4kB頁面。 但無論如何,在與多個接收器通信時,聚合將無濟於事。
那么該怎么辦? 減少熱切緩沖區的大小。 這可以通過設置eager / rendezvous閾值( I_MPI_RDMA_EAGER_THRESHOLD
環境變量)來控制。 嘗試2048甚至更小。 請注意,這可能會導致延遲增加。 或者更改I_MPI_DAPL_BUFFER_NUM
變量以控制這些緩沖區的數量,或者嘗試Hristo建議的動態調整大小功能。 假設您的IMPI正在使用DAPL(默認值)。 如果直接使用OF動詞,則DAPL變量將不起作用。
編輯:因此,要使其運行的最終解決方案是設置I_MPI_DAPL_UD=enable
。 我可以推測魔法的起源,但我無法訪問英特爾的代碼來實際證實這一點。
IB可以具有不同的傳輸模式,其中兩個是RC(可靠連接)和UD(不可靠數據報)。 RC需要主機之間的顯式連接(如TCP),並且每個連接花費一些內存。 更重要的是,每個連接都有與之相關的急切緩沖區,這確實加起來了。 這是英特爾默認設置的結果。
可以進行優化:在連接之間共享急切緩沖區(這稱為SRQ - 共享接收隊列)。 還有一個名為XRC(擴展RC)的Mellanox擴展,它進一步實現了隊列共享:在同一節點上的進程之間。 默認情況下,Intel的MPI通過DAPL訪問IB設備,而不是直接通過OF動詞訪問IB設備。 我的猜測是這排除了這些優化(我沒有DAPL的經驗)。 通過設置I_MPI_FABRICS=shm:ofa
I_MPI_OFA_USE_XRC=1
和I_MPI_OFA_USE_XRC=1
(使英特爾MPI使用OFA接口而不是DAPL),可以啟用XRC支持。
當您切換到UD傳輸時,您可以在緩沖區共享的基礎上進一步優化:不再需要跟蹤連接。 緩沖區共享在此模型中很自然:由於沒有連接,所有內部緩沖區都在共享池中,就像SRQ一樣。 因此可以節省更多內存,但需要付出代價:數據報交付可能會失敗,並且由軟件而不是IB硬件來處理重新傳輸。 當然,這對使用MPI的應用程序代碼都是透明的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.