Main Content

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

さらに、spmdReducespmdPlus および 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 の値の要素単位の和を返します。ただし、spmdPlusspmdReduce 演算の特殊なケースに過ぎません。関数 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 で表されます。たとえば、以下のような logical 配列があるとします。

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

参考

| | |

関連するトピック