Операция Умножения матриц к ANSI/ISO C BLAS Замена Кода

Этот пример показывает, как задать заменяющие отображения кода, которые заменяют нескалярные операции умножения на функции умножения C BLAS ANSI®/ISO® xgemm и xgemv. Пример задает заменяющие записи кода, которые сопоставляют операции матрицы/матрицы и матрицы/векторного умножения с плавающей точкой с функциями умножения библиотеки ANSI/ISO C BLAS dgemm и dgemv. Пример задает функциональные отображения программно. Также можно использовать Code Replacement Tool, чтобы задать те же отображения.

Таблица поддержки библиотек BLAS / умножение матриц в форме  C = (op (A) * op (B)) + до н.э. op (X) средние значения X, перемещение 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_cblas_mmult_double
    
  2. В теле функции составьте таблицу путем вызова функционального RTW.TflTable.

    hTable = RTW.TflTable;
    
  3. Задайте путь для библиотеки функции CBLAS. Например:

    LibPath = fullfile(matlabroot, 'toolbox', 'rtw', 'rtwdemos', 'crl_demo');
    
  4. Создайте запись для первого отображения с вызовом функции RTW.TflBlasEntryGenerator.

    % Create table entry for cblas_dgemm
    op_entry = RTW.TflCBlasEntryGenerator;
  5. Установите параметры записи оператора с вызовом функции setTflCOperationEntryParameters. Вызов функции устанавливает свойства записи оператора умножения матриц. Генератор кода игнорирует насыщение и округление режимов для нескалярного сложения с плавающей точкой и вычитания.

    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_MUL', ...
        'Priority',                 100, ...
        'ImplementationName',       'cblas_dgemm', ...
        'ImplementationHeaderFile', 'cblas.h', ...
        'ImplementationHeaderPath', LibPath, ...
        'AdditionalIncludePaths',   {LibPath}, ...
        'GenCallback',              'RTW.copyFileToBuildDir', ...
        '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, чтобы создать аргументы. Пример кода конфигурирует специальные аргументы реализации, которые требуются для dgemm и замен функции dgemv. setReturn удобных методов и addArgument задают, является ли аргумент возвращаемым значением или аргументом и добавляет аргумент в массив записи аргументов реализации.

    % Using RTW.TflCBlasEntryGenerator for xgemm requires the following
    % implementation signature:
    %
    % void f(enum ORDER, enum TRANSA, enum TRANSB, int M, int N, int K,
    %        type ALPHA, type* u1, int LDA, type* u2, int LDB,
    %        type BETA, type* y, int LDC)
    %
    % Since CRLs do not have the ability to specify enums, you must
    % use integer.  (This will cause problems with C++ code generation,
    % so for C++, use a wrapper function to cast each int to the
    % corresponding enumeration type.)
    %
    % When a match occurs, the code generator computes the
    % values for M, N, K, LDA, LDB, and LDC and insert them into the
    % generated code.
    
    % Specify replacement function signature
    
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    
    arg = getTflArgFromString(hTable, 'ORDER', 'integer', 102);
    % arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'TRANSA', 'integer', 111);
    % arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'TRANSB', 'integer', 111);
    % arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'M', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'N', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'K', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'ALPHA', 'double', 1);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDA', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDB', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'BETA', 'double', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDC', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
  8. Добавьте запись в заменяющую таблицу кода с вызовом функции addEntry.

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

    % Create table entry for cblas_dgemv
    op_entry = RTW.TflCBlasEntryGenerator;
    setTflCOperationEntryParameters(op_entry, ...
        'Key',                      'RTW_OP_MUL', ...
        'Priority',                 100, ...
        'ImplementationName',       'cblas_dgemv', ...
        'ImplementationHeaderFile', 'cblas.h', ...
        'ImplementationHeaderPath', LibPath, ...
        'AdditionalIncludePaths',   {LibPath}, ...
        'GenCallback',              'RTW.copyFileToBuildDir', ...
        '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.TflCBlasEntryGenerator for xgemv requires the following
    % implementation signature:
    %
    % void f(enum ORDER, enum TRANSA, int M, int N,
    %        type ALPHA, type* u1, int LDA, type* u2, int INCX,
    %        type BETA, type* y, int INCY)
    %
    % Since CRLs do not have the ability to specify enums, you must
    % use integer.  (This will cause problems with C++ code generation,
    % so for C++, use a wrapper function to cast each int to the
    % corresponding enumeration type.)
    %
    % Upon a match, the CRL entry will compute the
    % values for M, N, LDA, INCX, and INCY and insert them into the
    % generated code.
    
    % Specify replacement function signature
    
    arg = getTflArgFromString(hTable, 'y2', 'void');
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.setReturn(arg);
    
    arg = getTflArgFromString(hTable, 'ORDER', 'integer', 102);
    % arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'TRANSA', 'integer', 111);
    % arg.Type.ReadOnly=true;
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'M','integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'N', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'ALPHA', 'double', 1);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDA', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'INCX', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'BETA', 'double', 0);
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    op_entry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'INCY', 'integer', 0);
    op_entry.Implementation.addArgument(arg);
    
    addEntry(hTable, op_entry);
  10. Сохраните табличный файл определения. Используйте имя табличной функции определения, чтобы назвать файл.

Чтобы протестировать этот пример, создайте модель, которая использует два блока продукта. Например:

  1. Создайте модель, которая включает два блока продукта, такие как следующее:

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

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

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

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

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

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

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

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

Похожие темы