我可以在Matlab MEX函数中使用C++17/C++20中的并行STL算法吗?

omhiaaxx  于 2022-12-13  发布在  Matlab
关注(0)|答案(1)|浏览(149)

我正在整理一个在Matlab MEX函数中利用parallelism features in C++17/20的最小示例。我能够从Matlab编译和运行mex函数,但当我将C++ STL函数的execution policy设置为“par”而不是“seq”时,Matlab给出了运行时链接投诉。代码和错误消息如下:
test.m(Matlab顶级脚本):

vec_in = zeros(5);
coeff = 0.05;

vec_out = test_mex_gateway(vec_in, coeff);

测试_墨西哥_网关. cpp(Matlab的C++接口):

#include "mex.h"

extern void test_execute(float *array_in, float *array_out, const size_t vec_size, const float coeff);

void mexFunction( int nlhs,
                  mxArray *plhs[],
                  int nrhs,
                  const mxArray *prhs[] )
{
    // Check for proper number of input and output arguments
    if( nrhs != 2 )
    {
        mexErrMsgTxt( "3 input arguments required: input_data, coeff" );
    }

    if( nlhs > 2 )
    {
        mexErrMsgTxt( "Too many output arguments." );
    }

    const mwSize *matlab_data_dims_in;
    mwSize matlab_data_dims_out[1];

    // Input Parameters
    float *input_data = (float *) mxGetData(prhs[0]);
    float coeff = mxGetScalar(prhs[1]);

    // Get dimensions
    matlab_data_dims_in = mxGetDimensions(prhs[0]);
    const int vec_len = matlab_data_dims_in[1];

    // Set output data dimension
    matlab_data_dims_out[0] = vec_len;

    // Output data
    plhs[0] = mxCreateNumericArray(1, matlab_data_dims_out, mxSINGLE_CLASS, mxREAL);
    float *output_data = (float *) mxGetData(plhs[0]);

    test_execute(input_data, output_data, vec_len, coeff);

}

test_execute. cpp(这是进行实际C++ STL调用的位置):

#include <execution> // std::execution::*
#include <numeric>   // std::exclusive_scan()

void test_execute(float *array_in, float *array_out, const size_t vec_size, const float coeff)
{
    std::exclusive_scan
    (
        std::execution::par, // std::execution::seq works here for Mex call, par does not
        array_in,
        array_in + vec_size,
        array_out,
        0.0f,
        [coeff](float a, float b)
        {
            float ret = a + b + coeff;
            return ret;
        }
    );
}

我还有一个独立的main函数来替换Mex Package 器,以执行纯C++测试test_standalone.cpp:

#include <vector>
#include <iostream>

size_t VEC_NUM_ELEM = 10;

extern void test_execute(float *array_in, float *array_out, const size_t vec_size, const float coeff);

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        std::cout << "Try: " << argv[0] << "<coeff>" << std::endl;
        return -1;
    }

    const float coeff = std::stof(argv[1]);

    std::cout << "Coeff: " << coeff << std::endl;

    float __attribute__ ((aligned (64))) *vec1_array = (float *)malloc(VEC_NUM_ELEM * sizeof(float));
    float __attribute__ ((aligned (64))) *vec2_array = (float *)malloc(VEC_NUM_ELEM * sizeof(float));

    for (unsigned i = 0; i < VEC_NUM_ELEM; i++)
    {
        vec1_array[i] = static_cast<float>(i);
    }

    test_execute(vec1_array, vec2_array, VEC_NUM_ELEM, coeff);

    return 0;
}

下面是我如何构建和链接build.sh:

#!/bin/bash

rm *.o
rm *.exe
rm *.mexa64

cstd=c++17

gpp910=/home/m/compilers/bin/g++

tbblib=/home/m/reqs/tbb/lib/intel64/gcc4.8

echo "Building test_execute.cpp..."
$gpp910 -std=$cstd -I/home/m/reqs/tbb/include -L$tbblib -ltbb -Wl,rpath=$tbblib -c test_execute.cpp -fPIC

echo "Building test_standalone.cpp..."
$gpp910 -std=$cstd -L$tbblib test_execute.o test_standalone.cpp -o test_standalone.exe -ltbb

echo "Building test_mex_gateway.cpp..."
mex test_execute.o test_mex_gateway.cpp -L$tbblib -ltbb

并行STL调用需要链接到英特尔TBB(线程构建模块),因此在运行Matlab调用test.m或运行test_standalone. exe之前,我运行:
导出LD_库路径=/home/m/reqs/tbb/lib/英特尔64/gcc4.8:$LD_库路径
我还确保在运行时提供与我们使用构建的愚者版本相关联的C++库:
导出LD_LIBRARY_PATH=/home/m/编译器/lib 64:$LD_LIBRARY_PATH
当我运行test_standalone.exe时,无论我在std::exclusive_scan上将执行策略设置为“par”还是“seq”,一切都正常运行。当运行test.m时,如果“seq”被编译,我可以无错误运行。如果“par”被编译,Matlab在运行时抱怨链接问题:

  • 无效的MEX文件“test_mex_gateway.mexa64”:测试_墨西哥_网关.墨西哥64:未定义符号:_ZN3tbb10接口78内部20隔离区域内ERNS1_13委派基础El *

我怀疑这是一个应该与TBB相关联的功能,我证实了这一点:
英特尔®}| grep基准El
0000000000028 a30 T _ZN3tbb10接口78内部20隔离区域内ERNS1_13代理基础El
000000000005 ed 70 r ZN 3 tbb 10接口78内部20隔离区域内ERNS1_13委派基础E1 $$LSDA
我确认Matlab的LD_LIBRARY_PATH具有我在上述“export..”中提供的到此库的路径。
我试图确保我的库出现在Matlab从终端启动后添加到LD_LIBRARY_PATH的许多以Matlab为中心的路径之前。
我尝试通过一个-Wl,rpath=到链接器的通道来烘焙链接库的路径<path_to_tbb.so>。
两天后,我还是搞不懂为什么Matlab会有这个特殊的运行时问题,尤其是纯C++版本没有。

RHEL 7.9版本
Matlab R2020a
合同通用条款第9.1.0条
TBB(英特尔线程构建模块)2020.3

3xiyfsfu

3xiyfsfu1#

看起来Matlablibtbb.so的安装中包含了一个www.example.com版本,据我所知,当启动一个Mex文件时,Matlab将首先使用它自己的库,不管你的LD_LIBRARY_PATH顺序如何。这就是为什么我在运行Mex文件时会出现问题,而在运行纯C++文件时不会出现问题。从Matlab的安装目录中删除libtbb.so会允许运行时链接找到 my libtbb的版本,而且我能够毫无错误地运行。感谢Cris Luengo为我指明了正确的方向。

相关问题