Операция матричного умножения на замену кода BLAS MathWorks

Можно разработать библиотеку замещения кода для операций умножения с плавающей точкой для матрицы/матрицы и матрицы/вектора с функциями умножения dgemm и dgemv определено в библиотеке MathWorks BLAS. Если для замены используется сторонняя библиотека BLAS, необходимо изменить требования к сборке в этом примере, чтобы указать на библиотеку. Для разработки библиотеки замещения кода используйте интерактивный или программный подход. Для получения дополнительной информации см. раздел «Разработка библиотеки замещения кода».

Интерактивная разработка библиотеки замещения кода

  1. Откройте Code Replacement Tool (crtool) из командной строки MATLAB с помощью следующей команды:

    >>crtool
  2. Составьте таблицу.

    1. В контекстном меню crtool выберите File > New Table.

    2. На правой панели назовите таблицу crl_table_blas. Нажмите Apply.

  3. Создайте запись. В контекстном меню crtool выберите File > New entry > Blas Operation (Fortran).

  4. Создайте параметры входа. В раскрывающемся списке Function выберите Multiply.

  5. Создайте концептуальное представление. Концептуальное представление описывает сигнатуру функции, которую вы хотите заменить. В Conceptual function подразделе crtool задайте возвращаемый аргумент y1и входной параметр, u1 и u2 с Data Type double и Argument Type матрица.

  6. Создайте представление реализации. Представление реализации описывает сигнатуру оптимизационной функции. В данном примере, чтобы указать, что аргументы реализации имеют тот же порядок и свойства, что и концептуальные аргументы, установите флажок Make conceptual and implementation argument types the same. Установите BLAS level равным 2(Vector).

    Задайте Name для функции замены под Function prototype.

  7. Укажите сведения о сборке. Перейдите на вкладку Build Information, чтобы открыть панель Requirements к сборке. Укажите файлы (источник, заголовок, объект), которые требуется генератору кода для замены кода. В данном примере вам не нужно указывать информацию о сборке.

  8. Проверьте и сохраните таблицу. На вкладке Mapping Information нажмите Validate entry. В контекстном меню crtool выберите File > Save table > Save.

  9. Зарегистрируйте библиотеку замещения кода. Регистрация создает библиотеку, состоящую из заданных таблиц. Выберите File > Generate registration file. В диалоговом окне Сгенерировать файл регистрации заполните следующие поля:

    Чтобы использовать библиотеку замены кода, обновите текущий сеанс работы с MATLAB командой:

    >>sl_refresh_customizations

  10. Проверьте библиотеку замещения кода. Из командной строки MATLAB откройте библиотеку с помощью Code Replacement Viewer и проверьте, что таблица и запись заданы правильно. Дополнительные сведения см. в разделе Проверка библиотеки замещения кода. Сконфигурируйте модель, чтобы использовать библиотеку замены кода, сгенерировать код и проверить, что замена происходит должным образом. Если происходит непредвиденное поведение, исследуйте журналы попадания и пропуска, чтобы устранить проблемы.

Программно разрабатывайте библиотеку замещения кода

  1. Откройте программный интерфейс из меню MATLAB, выбрав New > Function.

  2. Составьте таблицу.

    1. Создайте функцию, чтобы вызвать таблицу библиотеки замещения кода. Функция не должна иметь аргументов и возвращать объект таблицы.

    2. Создайте объект таблицы путем вызова RTW.TflTable.

    function hTable = crl_table_blas
    % Create a function to call the code replacement library table 
    
    %% Create a table object
    hTable = RTW.TflTable;
    
  3. Создайте запись. Поскольку этот пример заменяет функцию, создайте запись замены кода в вашей таблице, вызвав функцию entry RTW.TflBlasEntryGenerator.

    function hTable = crl_table_blas
    % Create a code replacement library table 
    
    %% Create a table object
    hTable = RTW.TflTable;
    
    %% Create an entry
    %%%%%%%%%%%% Define library path for Windows or UNIX block%%%%%%%%%%%%%%%%%%
    
    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
    
    
    if ispc
        libExt = 'lib';
    elseif ismac
        libExt = 'dylib';
    else
        libExt = 'so';
    end
    
    
    %%%%%%Beginning of entries for the first dgemm block%%%%%%%%%%%%%%%%%%
    
    
    % Create table entry for dgemm32
    hEntry = RTW.TflBlasEntryGenerator;
  4. Создайте параметры входа. Поскольку эти примеры заменяют функцию, создайте параметры входа путем вызова функции setTflCFunctionEntryParameters.

    function hTable = crl_table_blas
    % Create a code replacement library table 
    
    %% Create a table object
    hTable = RTW.TflTable;
    
    %% Create an entry
    %%%%%%%%%%%% Define library path for Windows or UNIX block%%%%%%%%%%%%%%%%%%
    
    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
    
    
    if ispc
        libExt = 'lib';
    elseif ismac
        libExt = 'dylib';
    else
        libExt = 'so';
    end
    
    
    %%%%%%Beginning of entries for the first dgemm block%%%%%%%%%%%%%%%%%%
    
    
    % Create table entry for dgemm32
    hEntry = RTW.TflBlasEntryGenerator;
    
    %% Create entry parameters
    setTflCOperationEntryParameters(hEntry, ...
        '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);
  5. Создайте концептуальное представление. Концептуальное представление описывает сигнатуру функции, которую вы хотите заменить. Чтобы явным образом задать свойства аргумента, вызовите функцию createAndAddConceptualArg. Чтобы задать матричный аргумент в вызове функции, используйте класс аргумента RTW.TflArgMatrix и укажите базовый тип и размерности, для которых допустим аргумент. Этот тип записи таблицы поддерживает область значений измерений, заданных в формате [Dim1Min Dim2Min ... DimNMin; Dim1Max Dim2Max ... DimNMax]. Для примера [2 2; inf inf] означает двумерную матрицу размера 2x2 или больше. Концептуальный выходной аргумент для записи dgemm32 для замены умножения матрицы/матрицы задает размерности [2 2; inf inf], в то время как концептуальный выходной аргумент для dgemv32 запись для замены умножения матрицы/вектора задает размерности [2 1; inf 1].

    function hTable = crl_table_blas
    % Create a code replacement library table 
    
    %% Create a table object
    hTable = RTW.TflTable;
    
    %% Create an entry
    %%%%%%%%%%%% Define library path for Windows or UNIX block%%%%%%%%%%%%%%%%%%
    
    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
    
    
    if ispc
        libExt = 'lib';
    elseif ismac
        libExt = 'dylib';
    else
        libExt = 'so';
    end
    
    
    %%%%%%Beginning of entries for the first dgemm block%%%%%%%%%%%%%%%%%%
    
    
    % Create table entry for dgemm32
    hEntry = RTW.TflBlasEntryGenerator;
    
    %% Create entry parameters
    setTflCOperationEntryParameters(hEntry, ...
        '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);
    
    %% Create the conceptual representation
    createAndAddConceptualArg(hEntry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(hEntry, 'RTW.TflArgMatrix', ...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(hEntry, 'RTW.TflArgMatrix', ...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [1 1; inf inf]);
  6. Создайте представление реализации. Представление реализации описывает сигнатуру оптимизационной функции. Чтобы указать, что аргументы реализации имеют тот же порядок и свойства, что и концептуальные аргументы, вызовите функцию getTflArgFromString. Код примера конфигурирует специальные аргументы реализации, которые требуются для dgemm и dgemv замена функций. Методы удобства setReturn и addArgument задает, является ли аргумент возврата значением или аргументом, и добавляет аргумент к массиву аргументов реализации элемента. Добавьте полную запись в таблицу путем вызова функции addEntry.

    function hTable = crl_table_blas
    % Create a code replacement library table 
    
    %% Create a table object
    hTable = RTW.TflTable;
    
    %% Create an entry
    %%%%%%%%%%%% Define library path for Windows or UNIX block%%%%%%%%%%%%%%%%%%
    
    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
    
    
    if ispc
        libExt = 'lib';
    elseif ismac
        libExt = 'dylib';
    else
        libExt = 'so';
    end
    
    
    %%%%%%Beginning of entries for the first dgemm block%%%%%%%%%%%%%%%%%%
    
    
    % Create table entry for dgemm32
    hEntry = RTW.TflBlasEntryGenerator;
    
    %% Create entry parameters
    setTflCOperationEntryParameters(hEntry, ...
        '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);
    
    %% Create the conceptual representation
    createAndAddConceptualArg(hEntry, 'RTW.TflArgMatrix', ...
                              'Name',         'y1', ...
                              'IOType',       'RTW_IO_OUTPUT', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(hEntry, 'RTW.TflArgMatrix', ...
                              'Name',         'u1', ...
                              'BaseType',     'double', ...
                              'DimRange',     [2 2; inf inf]);
    createAndAddConceptualArg(hEntry, 'RTW.TflArgMatrix', ...
                              'Name',         'u2', ...
                              'BaseType',     'double', ...
                              'DimRange',     [1 1; inf inf]);
    
    %% Create the Implementation Representation
    % 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';
    hEntry.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';
    hEntry.Implementation.addArgument(arg);
    
    arg = RTW.TflArgCharConstant('TRANSB');
    arg.PassByType = 'RTW_PASSBY_POINTER';
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'M', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'N', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'K', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'ALPHA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u1', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDA', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'u2', ['double' '*']);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDB', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'BETA', 'double', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'y1', ['double' '*']);
    arg.IOType = 'RTW_IO_OUTPUT';
    arg.PassByType = 'RTW_PASSBY_POINTER';
    hEntry.Implementation.addArgument(arg);
    
    arg = getTflArgFromString(hTable, 'LDC', 'integer', 0);
    arg.PassByType = 'RTW_PASSBY_POINTER';
    arg.Type.ReadOnly = true;
    hEntry.Implementation.addArgument(arg);
    
    
    %% Add the entry to the table
    addEntry(hTable, hEntry);
  7. Укажите сведения о сборке. В параметрах входа укажите файлы (заголовок, источник, объект), которые нужны генератору кода для замены кода. В данном примере информация о сборке не требуется.

  8. Проверьте и сохраните файл индивидуальной настройки. В меню MATLAB сохраните этот файл индивидуальной настройки, выбрав File > Save. В командной строке проверьте таблицу библиотеки замещения кода, вызвав ее:

    >> hTable = crl_table_blas
  9. Зарегистрируйте библиотеку замещения кода. Регистрация создает библиотеку замещения кода путем определения имени библиотеки, таблиц замещения кода и другой информации. Создайте файл регистрации с этими спецификациями:

    function rtwTargetInfo(cm)
     
    cm.registerTargetInfo(@loc_register_crl);
    end
     
    function this = loc_register_crl 
     
    this(1) = RTW.TflRegistry; 
    this(1).Name = 'CRL for matrix multiplication for Mathworks Blas code’;
    this(1).TableList = {'crl_table_blas.m'}; % table created in this example
    this(1).TargetHWDeviceType = {'*'};
    this(1).Description = 'Example code replacement library';
    
    end
    

    Чтобы использовать библиотеку замены кода, обновите текущий сеанс работы с MATLAB командой:

    >>sl_refresh_customizations

  10. Проверьте библиотеку замещения кода. Из командной строки MATLAB откройте библиотеку с помощью Code Replacement Viewer и проверьте, что таблица и запись заданы правильно. Дополнительные сведения см. в разделе Проверка библиотеки замещения кода. Сконфигурируйте модель, чтобы использовать библиотеку замены кода, сгенерировать код и проверить, что замена происходит должным образом. Если происходит непредвиденное поведение, исследуйте журналы попадания и пропуска, чтобы устранить проблемы.

Преобразуйте операцию матричного умножения в MathWorks BLAS через замену кода

В этом разделе вы генерируете код с помощью библиотеки замены кода, которую вы создали в первых двух разделах этого примера. Операция умножения матрицы/матрицы с плавающей точкой заменяется пользовательской функцией умножения dgemm в сгенерированном коде. Этот пример не предоставляет функцию реализации. Напишите свою собственную реализацию.

Пример модели

Откройте модель crl_blas для настройки библиотеки замещения кода.

open_system('crl_blas');

copyfile BlasTargetInfo.txt rtwTargetInfo.m

Запустите файл индивидуальной настройки MATLAB, чтобы создать таблицу замещения кода и зарегистрировать файл. Файл индивидуальной настройки уже выполнен. Запустите функцию sl_refresh_customizations, чтобы зарегистрировать библиотеку.

sl_refresh_customizations;

Включите библиотеку замещения кода

  1. Откройте диалоговое окно Параметры конфигурации.

  2. На панели Интерфейс установите библиотеку замещения кода нажав Выбрать и добавить CRL for matrix multiplication for Mathworks Blas code к библиотекам замены выбранного кода - приоритетная панель списка. Также используйте API командной строки, чтобы включить замену кода:

set_param('crl_blas', 'CodeReplacementLibrary', 'CRL for matrix multiplication for Mathworks Blas code');

Сгенерируйте код из модели:

evalc('slbuild(''crl_blas'')');

Просмотрите сгенерированный код. Вот фрагмент crl_blas.c.

cfile = fullfile('crl_blas_ert_rtw','crl_blas.c');
rtwdemodbtype(cfile,'/* Model step function ','/* Model initialize function',1, 1);
/* Model step function */
void crl_blas_step(void)
{
  real_T ALPHA;
  real_T BETA;
  int32_T K;
  int32_T LDA;
  int32_T LDB;
  int32_T LDC;
  int32_T M;
  int32_T N;
  char_T TRANSA;
  char_T TRANSB;

  /* Product: '<Root>/DGEMM32' */
  TRANSA = 'N';
  TRANSB = 'N';
  M = 10;
  N = 10;
  K = 20;
  ALPHA = 1.0;
  LDA = 10;
  LDB = 20;
  BETA = 0.0;
  LDC = 10;

  /* Outport: '<Root>/Out1' incorporates:
   *  Inport: '<Root>/In1'
   *  Inport: '<Root>/In2'
   *  Product: '<Root>/DGEMM32'
   */
  dgemm32(&TRANSA, &TRANSB, &M, &N, &K, &ALPHA, &rtU.In1[0], &LDA, &rtU.In2[0],
          &LDB, &BETA, &rtY.Out1[0], &LDC);

  /* MATLAB Function: '<Root>/DGEMM32_2' */
  /* MATLAB Function 'DGEMM32_2': '<S1>:1' */
  /* '<S1>:1:5' */
  TRANSA = 'N';
  TRANSB = 'N';

  /* Outport: '<Root>/Out7' incorporates:
   *  Inport: '<Root>/In1'
   *  Inport: '<Root>/In2'
   *  MATLAB Function: '<Root>/DGEMM32_2'
   */
  dgemm32(&TRANSA, &TRANSB, &M, &N, &K, &ALPHA, &rtU.In1[0], &LDA, &rtU.In2[0],
          &LDB, &BETA, &rtY.Out7[0], &LDC);
}

Операция матричного/матричного умножения повторяется с помощью пользовательского dgemm32 функция.

Закройте модель и отчет о генерации кода.

delete ./rtwTargetInfo.m
bdclose('crl_blas');
rtwdemoclean;

Похожие темы

Для просмотра документации необходимо авторизоваться на сайте