2016-12-01 38 views
2

我使用arrayfire在GPU(OpenCL)的幫助下加速了一些C++代碼。我有600MB以上的af :: array,我需要沿列維翻轉,然後轉置它。如何避免在arrayfire中使用flip和transpose進行memcpy?

到目前爲止,我用C++例程幾乎完成了這些操作。然而,我現在想用AF做它,但注意到AF庫過多的內存使用。我有兩個問題:

1)我完全不明白爲什麼300MB陣列上的任何操作(例如翻轉或T)應該使用超過900MB的內存。 2)我想知道如何避免創建數組foo的副本。我想通過將操作封裝在一個單獨的函數中,我會擺脫任何副本。

我有這樣的代碼:

void prepare_array(af::array &a) { 
    af::array b = af::flip(a, 1);    // ~1400MB 
    a = b.T();         // ~3000MB 
} 

af::array foo = af::randn(768,16384,3,1,c64); // ~300MB 
prepare_array(foo); 
af::deviceGC();        // ~600MB 

我需要做這個手術只有一次這樣的速度是不太重要,那麼內存的使用情況,但我寧願在AF框架內做到這一點的操作。

(所有的內存使用統計信息與來自Debian的NVIDIA的內核驅動程序包gpustat讀出。)

內存使用率是CPU後端太過度。


感謝的答覆歐麥爾-艾爾沙德:當我把異形MEM-使用最後一次,我跑了CPU的代碼 - 假設它會同樣表現。我加倍檢查GPU上的測量結果,並使用gpustat和nvidia-smi。事實上,測量的代碼是不同的,正如你所解釋的那樣。它現在使所有的理想 - 至少是GPU的一部分。

也許在CPU上foo首先只有f64,因爲只有實部被使用,並且通過使用翻轉或換位成爲c64。

,與本網站「分配觸發一個隱含的同步設備上的特定平臺上的所有隊列」在一起的事實:http://forums.accelereyes.com/forums/viewtopic.php?f=17&t=43097&p=61730&hilit=copy+host+memory+into+an+array#p61727 和AF :: printMemInfo(); 幫助我終於弄清楚AF的大部分內存處理。大大加快我的計劃。

但是目前仍然是唯一的替代辦就地這兩個操作(或儘可能少的開銷可能)是使用:

// Generate/store data in std::array<af::cdouble> foo_unwrap = new af::cdouble[768*16384*3*1]; 

// Flip/Transpose foo_unwrap in plain C/C++, like in: 
// for(column = 0; column < max_num_column/2; column++) 
// swap column with max_num_column-1-column 
// 
// http://www.geeksforgeeks.org/inplace-m-x-n-size-matrix-transpose/ 
// but for Column-Major Order matrices 
// 
// and afterwards whenever needed do ad-hoc: 
af::cdouble* first_elem = (af::cdouble*) &(foo_unwrap[0]); // to ensure correct type detection via AF 
af::array foo = af::array(768,16384,3,1, first_elem, afDevice); 

然而,這是相當麻煩,因爲我不想麻煩Row/Column-Major格式和索引魔術。所以我在這裏尋找建議。

+0

是的,我不知道'gpustat'在做什麼,但是這些數字實際上是錯誤的(請參考下面的奧馬爾的回答)。你可以使用'nvidia-smi'獲得更好的信息。您也可以使用'af :: deviceMemInfo'來查看內部正在做什麼arrayfire。 –

+0

通常,當我使用ArrayFire時,我將尺寸視爲第一維,第二維而非列,行。只要你是一致的,維度的表示應該不重要。當然,這不適用於線性代數運算,但AF中的一些函數(特別是matmul)具有可選參數,這些參數執行計算,就好像數組已轉置而不重新排序數據。有關您的應用程序的其他上下文也可能有所幫助SO不是這種類型討論的最佳論壇。我們在谷歌組和gitter上非常活躍。 –

回答

2

ArrayFire使用內存管理器來避免不必要的分配和釋放。這是必需的,因爲所有分配都會觸發某些平臺上的所有隊列上的隱式設備同步。這可能會非常昂貴,因此ArrayFire將跟蹤af::array s超出範圍並在必要時重用它們。 ArrayFire也在啓動時分配內存。

在你的情況下,你在randu調用時分配了〜600MB(c64是一個複數double,因此每個元素都是16個字節)。翻轉操作還有600MB的分配存儲在b中。轉置將分配600MB,但會保留舊值以供重用。此時由於這些操作,您已分配大約1800 MB的內存。

當您從prepared_array返回時,函數調用b將超出範圍並將被標記爲刪除。此時你有3個緩衝區,每個600MB。其中兩個緩衝區未使用,但ArrayFire可以在未來的操作中使用這些緩衝區。一旦你調用deviceGC函數,這兩個未使用的數組將被釋放,儘管你可能會分配一個相似大小的數組,所以保留這些數組是有用的。

您可以使用af::printMemInfo()函數跟蹤由ArrayFire所作的分配。

Disclamer:我是ArrayFire的開發人員之一。

+0

此外,如果您的轉置矩陣是正方形,那麼您可以使用[transposeInPlace](http://arrayfire.org/docs/group__blas__func__transpose.htm#gae77f8ba484534fe5bf85c73f8641c133) – shehzan

相關問題