Этот пример показывает, как задать заменяющие отображения кода, которые заменяют нескалярные операции умножения на функции умножения C BLAS ANSI®/ISO®
и xgemm
. Пример задает заменяющие записи кода, которые сопоставляют операции матрицы/матрицы и матрицы/векторного умножения с плавающей точкой с функциями умножения библиотеки ANSI/ISO C BLAS xgemv
dgemm
и dgemv
. Пример задает функциональные отображения программно. Также можно использовать Code Replacement Tool, чтобы задать те же отображения.
Таблица поддержки библиотек BLAS / умножение матриц в форме . средние значения X, перемещение X или Эрмитово перемещение X. Однако заменяющие библиотеки кода поддерживают только ограниченный случай . Соответственно, несмотря на то, что таблица поддержки библиотек BLAS / векторное умножение в форме , заменяющие библиотеки кода поддерживают только ограниченный случай .
Создайте табличный файл определения, который содержит функциональное определение. Например:
function hTable = crl_table_cblas_mmult_double
В теле функции составьте таблицу путем вызова функционального RTW.TflTable
.
hTable = RTW.TflTable;
Задайте путь для библиотеки функции CBLAS. Например:
LibPath = fullfile(matlabroot, 'toolbox', 'rtw', 'rtwdemos', 'crl_demo');
Создайте запись для первого отображения с вызовом функции RTW.TflBlasEntryGenerator
.
% Create table entry for cblas_dgemm
op_entry = RTW.TflCBlasEntryGenerator;
Установите параметры записи оператора с вызовом функции 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);
Создайте концептуальные аргументы 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]);
Создайте аргументы реализации. Существует несколько способов настроить аргументы реализации. Этот пример использует вызовы функции 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);
Добавьте запись в заменяющую таблицу кода с вызовом функции addEntry
.
addEntry(hTable, op_entry);
Создайте запись для второго отображения.
% 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);
Сохраните табличный файл определения. Используйте имя табличной функции определения, чтобы назвать файл.
Чтобы протестировать этот пример, создайте модель, которая использует два блока продукта. Например:
Создайте модель, которая включает два блока продукта, такие как следующее:
Сконфигурируйте модель со следующими настройками:
На панели Solver выберите фиксированный шаг, дискретный решатель с размером фиксированного шага, таким как 0.1
.
На панели Code Generation выберите ERT-based system target file.
На Code Generation> панель Interface, выберите заменяющую библиотеку кода, которая содержит вашу запись операции сложения.
Для каждого блока продукта, набор параметры блоков Multiplication к значению Matrix(*)
.
В Model Explorer сконфигурируйте Signal Attributes для In1
, In2
и исходных блоков In3
. Для In1
и In2
, набора Port dimensions к [3 3]
и набору Data type к double
. Для In3
, набор Port dimensions к [3 1]
и набору Data type к double
.
Сгенерируйте код и отчет генерации кода.
Рассмотрите замены кода.