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