То В этом примере показано, как заменить операции матрицы/матрицы и матрицы/векторного умножения с плавающей точкой на умножение, функционирует 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);
Сохраните табличный файл определения. Используйте имя табличной функции определения, чтобы назвать файл.
Протестировать этот пример:
Укажите заменяющее отображение кода.
Создайте модель, которая включает два блока Product.
Для каждого блока Product, набор параметры блоков 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
.
Сгенерируйте код и отчет генерации кода.
Рассмотрите замены кода.