spmdReduce
による MPI_Allreduce 機能の実現
この例では、関数 spmdReduce
およびそれを利用する関数 spmdPlus
および spmdCat
について確認します。これらはシンプルな関数に見えますが、実は並列プログラミングにおける極めて強力なツールであることがわかります。
関数 spmdReduce
を使用すると、すべてのワーカーで定義される変数の結合二項演算を実行できます。これによって、すべてのワーカーの変数の総和を求められるようになるだけでなく、すべてのワーカーにおける変数の最小値と最大値を求めたり、変数を連結したりするなど、多くの便利な演算を実行できるようになります。
この例のコードは以下の関数に含まれています。
function paralleltutorial_gop
はじめに
並列プログラミングを行う場合は、変数がすべてのワーカーで定義されるようにすることや、変数がすべてのワーカーに存在するためにその変数に関する演算を実行しなければならなくなることがよくあります。たとえば、以下のように spmd ステートメントを入力して定義するとします。
spmd x = spmdIndex; end
これをすべてのワーカーで定義して、すべてのワーカーにおける x
の値の総和を計算する場合を考えます。これはまさに spmdPlus
演算で実行できます。つまり、すべてのワーカーの x
を合計し、すべてのワーカーで結果を複製します。
spmd s = spmdPlus(x); end
spmd ステートメント内部で代入されている変数はクライアントで Composite として表されます。結果の値は、cell 配列の場合と同様、Composite にインデックスを付けることによってワーカーからクライアントに取り込まれます。
s{1} % Display the value of s on worker 1. All workers store the same value.
ans = 21
さらに、spmdReduce
、spmdPlus
および spmdCat
では、関数の出力先となる単一のワーカーを指定できます。その場合、他のワーカーには空のベクトルが返されます。
spmd s = spmdPlus(x, 1); end s{1}
ans = 21
この例では、すべてのワーカーでの加算と同じような演算のホストを実行する方法を示します。MPI の場合、これらは集合演算と呼ばれ、MPI_SUM、MPI_PROD、MPI_MIN, MPI_MAX などがあります。
例の入力データの作成
すべての例で使用するデータは極めてシンプルです。最初に定義した x
より若干複雑な 1 行 2 列のバリアント配列です。
spmd x = spmdIndex + (1:2) end
spmdPlus
および spmdCat
の使用
ベクトル x
がワーカーごとに異なる値に初期化されたため、すべてのワーカーにわたって x
の値の要素単位の総和などを求めることができます。また、積、最小値および最大値についてはどうでしょうか。これは当初の見込みどおり、以下のようになります。
spmd s = spmdPlus(x); end s{1}
ans = 27 33
これは x
の値の要素単位の和を返します。ただし、spmdPlus
は spmdReduce
演算の特殊なケースに過ぎません。関数 spmdReduce
では、バリアント配列の要素について、すべてのワーカーにわたる任意の結合演算を実行できます。結合演算の最も基本的な例は加算です。加算は、以下に示すように、どのようにグループ化されるかに影響されないため結合的な演算となります。
(a + b) + c = a + (b + c)
MATLAB® では、加算を関数ハンドル @plus
によって表すことができます。したがって、spmdPlus(x)
は以下のように記述することもできます。
spmd s = spmdReduce(@plus, x); end s{1}
ans = 27 33
ベクトル x
は、関数 spmdCat
を使用することにより、すべてのワーカーにわたって連結できます。また、連結する次元を選択することもできます。
spmd y1 = spmdCat(x, 1); % Concatenate along rows. y2 = spmdCat(x, 2); % Concatenate along columns. end y1{1} y2{1}
ans = 2 3 3 4 4 5 5 6 6 7 7 8 ans = 2 3 3 4 4 5 5 6 6 7 7 8
その他の要素単位演算での spmdReduce
の使用
すべてのワーカーにわたる x
の値の要素単位の積は、以下のように簡単に計算できます。
spmd p = spmdReduce(@times, x); end p{1}
ans = 5040 20160
また、すべてのワーカーにわたる x
の要素単位の最大値も以下のように求めることができます。
spmd M = spmdReduce(@max, x); m = spmdReduce(@min, x); end M{1} m{1}
ans = 7 8 ans = 2 3
論理演算
MATLAB には他にも組み込みの結合演算があります。AND、OR、XOR の論理演算は、それぞれ関数ハンドル @and
、@or
、@xor
で表されます。たとえば、以下のような論理配列があるとします。
spmd y = (x > 4) end
この場合、すべてのワーカーにわたって以下の論理演算を y
の要素に対して簡単に実行できます。
spmd yand = spmdReduce(@and, y); yor = spmdReduce(@or, y); yxor = spmdReduce(@xor, y); end yand{1} yor{1} yxor{1}
ans = 1×2 logical array 0 0 ans = 1×2 logical array 1 1 ans = 1×2 logical array 1 0
ビット演算
MATLAB に組み込まれている結合演算に関する説明の締めくくりとして、AND、OR、XOR のビット演算について見てみます。これらは、それぞれ関数ハンドル @bitand
、@bitor
、@bitxor
で表されます。
spmd xbitand = spmdReduce(@bitand, x); xbitor = spmdReduce(@bitor, x); xbitxor = spmdReduce(@bitxor, x); end xbitand{1} xbitor{1} xbitxor{1}
ans = 0 0 ans = 7 15 ans = 1 11
最小値と最大値の位置の検出
すべてのワーカーにわたる x
の要素単位の最大値がある位置に対応する spmdIndex
を見つけるには、若干のプログラミングが必要です。この処理は、以下のようにわずか数行のコードで実行することができます。
type pctdemo_aux_gop_maxloc
function [val, loc] = pctdemo_aux_gop_maxloc(inval) %PCTDEMO_AUX_GOP_MAXLOC Find maximum value of a variant and its spmdIndex. % [val, loc] = pctdemo_aux_gop_maxloc(inval) returns to val the maximum value % of inval across all workers. The spmdIndex where this maximum value % resides is returned to loc. % Copyright 2007 The MathWorks, Inc. out = spmdReduce(@iMaxLoc, {inval, spmdIndex*ones(size(inval))}); val = out{1}; loc = out{2}; end function out = iMaxLoc(in1, in2) % Calculate the max values and their locations. Return them as a cell array. in1Largest = (in1{1} >= in2{1}); maxVal = in1{1}; maxVal(~in1Largest) = in2{1}(~in1Largest); maxLoc = in1{2}; maxLoc(~in1Largest) = in2{2}(~in1Largest); out = {maxVal, maxLoc}; end
また、この関数が実装されている場合は、まるで組み込み関数のように簡単に適用することができます。
spmd [maxval, maxloc] = pctdemo_aux_gop_maxloc(x); end [maxval{1}, maxloc{1}]
ans = 7 8 6 6
同様に、すべてのワーカーにわたる x
の要素単位の最小値がある位置に対応する spmdIndex
を見つける場合も、数行のコードで済みます。
type pctdemo_aux_gop_minloc
function [val, loc] = pctdemo_aux_gop_minloc(inval) %PCTDEMO_AUX_GOP_MINLOC Find minimum value of a variant and its spmdIndex. % [val, loc] = pctdemo_aux_gop_minloc(inval) returns to val the minimum value % of inval across all workers. The spmdIndex where this minimum value % resides is returned to loc. % Copyright 2007 The MathWorks, Inc. out = spmdReduce(@iMinLoc, {inval, spmdIndex*ones(size(inval))}); val = out{1}; loc = out{2}; end function out = iMinLoc(in1, in2) % Calculate the min values and their locations. Return them as a cell array. in1Smallest = (in1{1} < in2{1}); minVal = in1{1}; minVal(~in1Smallest) = in2{1}(~in1Smallest); minLoc = in1{2}; minLoc(~in1Smallest) = in2{2}(~in1Smallest); out = {minVal, minLoc}; end
これで、spmdReduce
を使用して、簡単に最小値を求めることができます。
spmd [minval, minloc] = pctdemo_aux_gop_minloc(x); end [minval{1}, minloc{1}]
ans = 2 3 1 1
参考
spmd
| spmdReduce
| spmdPlus
| spmdCat