Main Content

MEX 関数における配列のコピーの回避

大きなデータ配列のコピーを実行するタイミングを制御することで、MEX 関数のパフォーマンスを改善できる場合がよくあります。次の場合に、配列の不要なコピーを回避できます。

  • MEX 関数が入力配列にアクセスするが、配列の要素を変更しない場合。

  • MEX 関数が入力配列を変更し、かつ変更された配列が呼び出し元関数に返される場合。

C++ アプリケーションではなく MATLAB® コードを作成している場合は、データの不要なコピーの回避を参照してください。

入力配列が変更されない場合

次の MEX 関数は入力配列の要素数を合計しますが、配列は変更しません。inputs[0]const 変数 matlab::data::TypedArray<double> に代入すると、範囲ベースの for ループを使用して要素を合計できます。配列を const として指定することで、変数 inArray が確実に入力配列と共有されたままになります。

#include "mex.hpp"
#include "mexAdapter.hpp"

using namespace matlab::data;
using matlab::mex::ArgumentList;

class MexFunction : public matlab::mex::Function {
    ArrayFactory factory;
public:
    void operator()(ArgumentList outputs, ArgumentList inputs) {
    double sm = 0;
    const TypedArray<double> inArray = inputs[0];
    for (auto& elem : inArray) {
        sm += elem;
    }
    outputs[0] = factory.createScalar(sm);
    }
};

このコードをファイル (この例では addArrayElements.cpp という名前) に保存したら、関数 mex を使用してコンパイルします。double 配列を入力引数として指定し、MATLAB からこの MEX 関数を呼び出します。

mex addArrayElements.cpp
b = addArrayElements([1:1e7]);
b =

        5.0000e+13

入力配列が変更される場合

次の MEX 関数は、入力配列における負の値を 0 で置き換えます。この操作は入力配列を変更するため、入力を変更済み配列と共有したままにしておくことはできません。入力配列の検証が完了したら、関数は inputs[0] を再び使用しません。したがって、検証済み配列 inputs[0] が変数 matlab::data::TypedArray<double> に移動され、範囲ベースの for ループを使用して配列要素を変更できるようになります。

入力配列のコピーを防止するには、std::move() を使用して input[0]matlab::data::TypedArray<double> に移動します。これにより、largeArray への入力配列に関連付けられているメモリがスワップされます。

#include "mex.hpp"
#include "mexAdapter.hpp"

using namespace matlab::data;
using matlab::mex::ArgumentList;

class MexFunction : public matlab::mex::Function {
public:
    void operator()(ArgumentList outputs, ArgumentList inputs) {
        checkArguments(inputs);
        TypedArray<double> largeArray = std::move(inputs[0]);
        for (auto& elem : largeArray) {
            if (elem < 0) {
                elem = 0;
            }
        }
        outputs[0] = largeArray;
    }

    void checkArguments(ArgumentList inputs) {
        std::shared_ptr<matlab::engine::MATLABEngine> matlabPtr = getEngine();
        ArrayFactory factory;

        if (inputs[0].getType() != ArrayType::DOUBLE ||
            inputs[0].getType() == ArrayType::COMPLEX_DOUBLE) {
            matlabPtr->feval(u"error", 0, 
                std::vector<Array>({ factory.createScalar("Incorrect input") }));
        }
    }
};

このコードをファイル (この例では removeNegativeNumbers.cpp という名前) に保存したら、関数 mex を使用してコンパイルします。

mex removeNegativeNumbers.cpp

MATLAB 関数からこの MEX 関数を呼び出します。変更した配列を同じ変数に再代入します。

function arry = processArray(arry)
    arry = removeNegativeNumbers(arry);
    ....
end
    

たとえば、MATLAB 関数 randn から返される大きな配列を指定して、関数 processArray を呼び出します。

A = processArray(randn(10000));
min(A(:))

ans =

     0

関連するトピック