Операция умножения матриц к MathWorks BLAS Code Replacement

Можно разработать заменяющую библиотеку кода для операций матрицы/матрицы и матрицы/векторного умножения с плавающей точкой с функциями умножения 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 двойных и 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. Создайте запись. Поскольку этот пример заменяет функцию, создайте заменяющую запись кода в своей таблице путем вызывания функции записи 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 и задайте базовый тип и размерности, для которых аргумент допустим. Этот тип записи таблицы поддерживает область значений размерностей, заданных в format [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 Through Code Replacement

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

Модель в качестве примера

Откройте модель crl_blas для конфигурирования заменяющей библиотеки кода.

open_system('crl_blas');

copyfile BlasTargetInfo.txt rtwTargetInfo.m

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

sl_refresh_customizations;

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

  1. Откройте диалоговое окно Configuration Parameters.

  2. На Интерфейсной панели, Заменяющей Библиотеке набора Кода путем нажатия на Select и добавления 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;

Похожие темы