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