Операция умножения матриц к MathWorks BLAS Code Replacement

То В этом примере показано, как заменить операции матрицы/матрицы и матрицы/векторного умножения с плавающей точкой на умножение, функционирует dgemm и dgemv заданный в библиотеке MathWorks BLAS. Если вы будете пользоваться сторонней библиотекой BLAS для замены, необходимо будет изменить требования сборки в этом примере, чтобы указать на библиотеку. Этот пример задает функциональные отображения программно. В качестве альтернативы можно использовать Code Replacement Tool, чтобы задать те же отображения.

Заменяющие библиотеки кода только поддерживают ограниченные случаи от библиотек BLAS. Таблица поддержки библиотек BLAS / умножение матриц в форме  C = (op (A) * op (B)) + до н.э. Где выражение op (X) представляет или перемещение или Эрмитово перемещение X. Однако заменяющие библиотеки кода только поддерживают ограниченный случай  C = op (A) * op (B) ( = 1.0, b = 0.0). Кроме того, таблица поддержки библиотек BLAS / векторное умножение в форме  y = (op (A) * x) + , в то время как заменяющие библиотеки кода только поддерживают ограниченный случай  y = op (A) * x ( = 1.0, b = 0.0).

  1. Создайте табличный файл определения, который содержит функциональное определение. Например:

    function hTable = crl_table_tmwblas_mmult_double
  2. В теле функции составьте таблицу путем вызова функционального RTW.TflTable.

    hTable = RTW.TflTable;
    
  3. Задайте путь для библиотеки функции BLAS. Если ваши заменяющие функции находятся на пути поиска файлов MATLAB® или находятся в вашей рабочей папке, можно пропустить этот шаг.

    % Define library path for Windows or UNIX
    arch = computer('arch');
    if ~ispc
        LibPath = fullfile('$(MATLAB_ROOT)', 'bin', arch);
    else
        % Use Stateflow to get the compiler info
        compilerInfo = sf('Private','compilerman','get_compiler_info');
        compilerName = compilerInfo.compilerName;
        if strcmp(compilerName, 'msvc90') || ...
                strcmp(compilerName, 'msvc80') || ...
                strcmp(compilerName, 'msvc71') || ...
                strcmp(compilerName, 'msvc60'), ...
                compilerName = 'microsoft';
        end
        LibPath = fullfile('$(MATLAB_ROOT)', 'extern', 'lib', arch, compilerName);
    end
    
  4. Создайте запись для первого отображения с вызовом RTW.TflBlasEntryGenerator функция.

    % Create table entry for dgemm32
    op_entry = RTW.TflBlasEntryGenerator;
    
  5. Вызовите setTflCFunctionEntryParameters устанавливать параметры записи оператора. Для нескалярного сложения с плавающей точкой и вычитания, генератор кода игнорирует насыщение и округление режимов. Для нескалярного сложения и операций вычитания, которые не включают данные фиксированной точки, задайте SaturationMode как 'RTW_SATURATE_UNSPECIFIED' и RoundingModes как {'RTW_ROUND_UNSPECIFIED'}.

    if ispc
        libExt = 'lib';
    elseif ismac
        libExt = 'dylib';
    else
        libExt = 'so';
    end
    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_MUL', ...
        'Priority',                 100, ...
        'ImplementationName',       'dgemm32', ...
        'ImplementationHeaderFile', 'blascompat32_crl.h', ...
        'ImplementationHeaderPath', fullfile('$(MATLAB_ROOT)','extern','include'), ...
        'AdditionalLinkObjs',       {['libmwblascompat32.' libExt]}, ...
        'AdditionalLinkObjsPaths',  {LibPath}, ...
        'SideEffects',              true);
    
  6. Создайте концептуальные аргументы y1, u1, и u2. Существует несколько способов настроить концептуальные аргументы. Этот пример использует вызовы createAndAddConceptualArg функция, чтобы создать и добавить аргумент с одним вызовом функции. Чтобы задать матричный аргумент в вызове функции, используйте класс аргумента RTW.TflArgMatrix и задайте базовый тип и размерности, для которых аргумент допустим. Этот тип записи таблицы поддерживает область значений размерностей, заданных в формате [Dim1Min Dim2Min ... DimNMin; Dim1Max Dim2Max ... DimNMax]. Например, [2 2; inf inf] означает двумерную матрицу размера 2x2 или больше. Концептуальный выходной аргумент в пользу dgemm32 запись для замены матрицы/умножения матриц задает размерности [2 2; inf inf], в то время как концептуальный выходной аргумент в пользу dgemv32 запись для замены матрицы/векторного умножения задает размерности [2 1; inf 1].

    % Specify operands and result
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [1 1; inf inf]);
    
  7. Создайте аргументы реализации. Существует несколько способов настроить аргументы реализации. Этот пример использует вызовы getTflArgFromString и RTW.TflArgCharConstant функции, чтобы создать аргументы. Пример кода конфигурирует специальные аргументы реализации, которые требуются для dgemm и dgemv функциональные замены. Удобные методы setReturn и addArgument задайте, является ли аргумент возвращаемым значением или аргументом и добавляет аргумент в массив записи аргументов реализации.

    % Using RTW.TflBlasEntryGenerator for xgemm requires the following
    % implementation signature:
    %
    % void f(char* TRANSA, char* TRANSB, int* M, int* N, int* K,
    %        type* ALPHA, type* u1, int* LDA, type* u2, int* LDB,
    %        type* BETA, type* y, int* LDC)
    %
    % When a match occurs, the code generator computes the
    % values for M, N, K, LDA, LDB, and LDC and inserts them into the
    % generated code. TRANSA and TRANSB are set to 'N'.
    
    % Specify replacement function signature
    
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    
    arg = RTW.TflArgCharConstant('TRANSA');
    % Possible values for PassByType property are
    %  RTW_PASSBY_AUTO, RTW_PASSBY_POINTER,
    %  RTW_PASSBY_VOID_POINTER, RTW_PASSBY_BASE_POINTER
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = RTW.TflArgCharConstant('TRANSB');
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'M', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'N', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'K', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'ALPHA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDA', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDB', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'BETA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDC', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
  8. Добавьте запись в заменяющую таблицу кода с вызовом addEntry функция.

    addEntry(hTable, op_entry);
  9. Создайте запись для второго отображения.

    % Create table entry for dgemv32
    op_entry = RTW.TflBlasEntryGenerator;
    if ispc
        libExt = 'lib';
    elseif ismac
        libExt = 'dylib';
    else
        libExt = 'so';
    end
    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_MUL', ...
        'Priority',                 100, ...
        'ImplementationName',       'dgemv32', ...
        'ImplementationHeaderFile', 'blascompat32_crl.h', ...
        'ImplementationHeaderPath', fullfile('$(MATLAB_ROOT)','extern','include'), ...
        'AdditionalLinkObjs',       {['libmwblascompat32.' libExt]}, ...
        'AdditionalLinkObjsPaths',  {LibPath},...
        'SideEffects',              true);
    
    % Specify operands and result
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 1; inf 1]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix', ...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(op_entry, 'RTW.TflArgMatrix',...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [1 1; inf 1]);
    
    % Using RTW.TflBlasEntryGenerator for xgemv requires the following
    % implementation signature:
    %
    % void f(char* TRANS, int* M, int* N,
    %        type* ALPHA, type* u1, int* LDA, type* u2, int* INCX,
    %        type* BETA, type* y, int* INCY)
    %
    % Upon a match, the CRL entry will compute the
    % values for M, N, LDA, INCX, and INCY, and insert them into the
    % generated code. TRANS will be set to 'N'.
    
    % Specify replacement function signature
    
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    
    arg = RTW.TflArgCharConstant('TRANS');
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'M', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'N', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'ALPHA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDA', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'INCX','integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'BETA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    arg.PassByType = 'RTW_PASSBY_POINTER';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'INCY', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    op_entry.Implementation.addArgument(arg);
    
    addEntry(hTable, op_entry);
  10. Сохраните табличный файл определения. Используйте имя табличной функции определения, чтобы назвать файл.

Протестировать этот пример:

  1. Укажите заменяющее отображение кода.

  2. Создайте модель, которая включает два блока Product.

  3. Для каждого блока Product, набор параметры блоков Multiplication к значению Matrix(*).

  4. Сконфигурируйте модель со следующими настройками:

    • На панели Solver выберите фиксированный шаг, дискретный решатель с размером фиксированного шага, таким как 0.1.

    • На панели Code Generation выберите ERT-based system target file.

    • На Code Generation> панель Interface, выберите заменяющую библиотеку кода, которая содержит вашу запись операции сложения.

  5. В Model Explorer сконфигурируйте Signal Attributes для In1, In2, и In3 исходные блоки. Для In1 и In2, установите Port dimensions на [3 3] и набор Data type к double. Для In3, установите Port dimensions на [3 1] и набор Data type к double.

  6. Сгенерируйте код и отчет генерации кода.

  7. Рассмотрите замены кода.

Похожие темы