2016-12-01 5 views
2

私は、GPU(OpenCL)の助けを借りてC++コードを高速化するためにarrayfireを使用します。私はaf :: arrayの600MB以上を持っています。これは列の次元に沿って反転し、それを転置する必要があります。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のバックエンド用として過剰です。


返信ウマル・arshadに感謝:私は、MEM-用法私がCPU上でコードを実行した最後の時間を要したプロファイル - それは同じように振る舞うと仮定。私はGPUでgpustatとnvidia-smiの両方を使って測定値を二重にチェックしました。確かにコードは測定値が違っていて説明した通りでした。それは今、すべての理にかなっている - 少なくともGPUの部分。

おそらくCPU上のfooは、実際の部分のみが使用され、フリップまたはトランスポーズのいずれかによってc64になるため、最初はf64のみです。

このウェブサイトと一緒に「割り当ては、特定のプラットフォーム上のすべてのキューで同期暗黙のデバイスをトリガー」という事実:http://forums.accelereyes.com/forums/viewtopic.php?f=17&t=43097&p=61730&hilit=copy+host+memory+into+an+array#p61727 とAF :: printMemInfo(); は、AFのメモリ処理の大部分を最終的に把握するのに役立ちました。私のプログラムを大幅にスピードアップします。今はまだインプレース(または可能な限り少ないオーバーヘッドで)これら2つの操作を行うための唯一の代替が使用するためしかし

// 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); 

私はしたくなかったので、しかし、これは非常に面倒です行/列メジャー形式と索引マジックについて気にする。だからまだ私はここで提案を探している。

+0

ええ、私は 'gpustat'が何をしているのか分かりませんが、数字は事実上間違っています(下記のUmarの答えを参照してください)。より良い情報のために 'nvidia-smi'を使うことができます。また、 'af :: deviceMemInfo'を使って、arrayfireが内部で何をしているのかを知ることができます。 –

+0

通常、私がArrayFireを扱うとき、私は次元を第1次元、列、行ではなく第2次元として扱います。あなたが一貫している限り、次元の表現は重要ではありません。もちろん、これは線形代数演算には適用されませんが、AF(matmul)の一部の関数では、データを並べ替えることなく配列が転置されたかのように計算を実行するオプションパラメータがあります。アプリケーションに関する追加のコンテキストも役立ちます。 SOはこのタイプの議論のための最良のフォーラムではありません。私たちはかなりグーグルグループや巨人に積極的です。 –

答えて

2

ArrayFireは不要な割り当てや割り当て解除を避けるためにメモリマネージャを使用します。これは、すべての割り当てが特定のプラットフォーム上のすべてのキューで暗黙のデバイスを同期させるためです。これは非常にコストがかかるので、ArrayFireは範囲外になり、必要に応じて再利用するaf::arrayを追跡します。また、ArrayFireは起動時にメモリを割り当てます。

あなたの場合、randuコールで〜600MBを割り当てています(c64は複雑なダブルで、各要素は16バイトです)。 bに格納されているフリップ操作のための別の600MB割り当てがあります。 Transposeは600MBを割り当てますが、再使用のために古い値を予約します。この時点で、これらの操作のために約1800 MBのメモリが割り当てられます。

prepared_array関数呼び出しから戻るとき、bは範囲外になり、削除対象としてマークされます。この時点で、それぞれ600MBで3つのバッファがあります。 2つのバッファは未使用ですが、ArrayFireは将来の操作でこれらのバッファを使用できます。 deviceGC関数を呼び出すと、未使用の配列は両方とも解放されますが、同様のサイズの配列を割り当てる可能性がありますので、これらの配列を保持すると便利です。

af::printMemInfo()機能を使用してArrayFireによる割り当てを追跡できます。

Disclamer:私はArrayFireの開発者の一人です。

+0

また、転置行列が正方形の場合、[transposeInPlace](http://arrayfire.org/docs/group__blas__func__transpose.htm#gae77f8ba484534fe5bf85c73f8641c133)を使用することができます。 – shehzan

関連する問題