Main Content

Matrix Multiplication Operation to MathWorks BLAS Code Replacement

You can develop a code replacement library for floating-point matrix/matrix and matrix/vector multiplication operations with the multiplication functions dgemm and dgemv defined in the MathWorks BLAS library. If you use a third-party BLAS library for replacement, you must change the build requirements in this example to point to your library. To develop a code replacement library use either the interactive or programmatic approach. For more information, see Develop a Code Replacement Library.

Interactively Develop a Code Replacement Library

  1. Open the Code Replacement Tool (crtool), from the MATLAB command line with the following command:

    >>crtool
  2. Create a table.

    1. From the crtool context menu, select File > New Table.

    2. In the right pane, name the table crl_table_blas. Click Apply.

  3. Create an entry. From the crtool context menu, select File > New entry > Blas Operation (Fortran).

  4. Create entry parameters. In the Function drop-down list, select Multiply.

  5. Create the conceptual representation. The conceptual representation describes the signature of the function that you want to replace. In the Conceptual function subsection of the crtool, specify the return argument, y1, and the input argument, u1 and u2 with the Data Type of double and the Argument Type of Matrix.

  6. Create the implementation representation. The implementation representation describes the signature of the optimization function. For this example, to specify that the implementation arguments have the same order and properties as the conceptual arguments, select the Make conceptual and implementation argument types the same check box. Set the BLAS level to 2(Vector).

    Specify a Name for the replacement function under Function prototype.

  7. Specify build information. Click the Build Information tab to open the build requirements pane. Specify the files (source, header, object) that the code generator requires for code replacement. For this example, you do not need to specify build information.

  8. Validate and save the table. In the Mapping Information tab, click Validate entry. In the crtool context menu, select File > Save table > Save.

  9. Register a code replacement library. Registration creates a library composed of the tables that you specify. Select File > Generate registration file. In the Generate registration file dialog box, fill out these fields:

    To use your code replacement library, refresh your current MATLAB session with the command:

    >>sl_refresh_customizations

  10. Verify the code replacement library. From the MATLAB command line, open the library by using the Code Replacement Viewer and verify that the table and entry are correctly specified. For more information, see Verify Code Replacement Library. Configure your model to use the code replacement library, generate code, and verify that replacement occurs as expected. If unexpected behavior occurs, examine the hit and miss logs to troubleshoot the issues.

Programmatically Develop a Code Replacement Library

  1. Open the programmatic interface from the MATLAB menu by selecting New > Function.

  2. Create a table.

    1. Create a function to call your code replacement library table. The function should not have arguments and return a table object.

    2. Create a table object by calling 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. Create an entry. Because this example replaces a function, create a code replacement entry in your table by calling the entry function 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. Create entry parameters. Because this examples replaces a function, create entry parameters by calling the function 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. Create the conceptual representation. The conceptual representation describes the signature of the function that you want to replace. To explicitly specify argument properties, call the function createAndAddConceptualArg. To specify a matrix argument in the function call, use the argument class RTW.TflArgMatrix and specify the base type and the dimensions for which the argument is valid. This type of table entry supports a range of dimensions specified in the format [Dim1Min Dim2Min ... DimNMin; Dim1Max Dim2Max ... DimNMax]. For example, [2 2; inf inf] means a two-dimensional matrix of size 2x2 or larger. The conceptual output argument for the dgemm32 entry for matrix/matrix multiplication replacement specifies dimensions [2 2; inf inf], while the conceptual output argument for the dgemv32 entry for matrix/vector multiplication replacement specifies dimensions [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. Create the implementation representation. The implementation representation describes the signature of the optimization function. To specify that the implementation arguments have the same order and properties as the conceptual arguments, call the function getTflArgFromString. The example code configures special implementation arguments that are required for dgemm and dgemv function replacements. The convenience methods setReturn and addArgument specify whether an argument is a return value or argument and adds the argument to the entry’s array of implementation arguments. Add the complete entry to the table by calling the function 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. Specify build information. In the entry parameters, specify files (header, source, object) that the code generator needs for code replacement. For this example, build information is not required.

  8. Validate and save the customization file. From the MATLAB menu, save this customization file by selecting File > Save. From the command line, validate the code replacement library table by calling it:

    >> hTable = crl_table_blas
  9. Register the code replacement library. Registration creates a code replacement library by defining the library name, code replacement tables, and other information. Create a registration file with these specifications:

    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
    

    To use your code replacement library, refresh your current MATLAB session with the command:

    >>sl_refresh_customizations

  10. Verify the code replacement library. From the MATLAB command line, open the library by using the Code Replacement Viewer and verify that the table and entry are correctly specified. For more information, see Verify Code Replacement Library. Configure your model to use the code replacement library, generate code, and verify that replacement occurs as expected. If unexpected behavior occurs, examine the hit and miss logs to troubleshoot the issues.

Convert a Matrix Multiplication Operation to MathWorks BLAS Through Code Replacement

In this section, you generate code using the code replacement library that you created in the first two sections of this example. A floating-point matrix/matrix multiplication operation is replaced with a custom multiplication function dgemm in the generated code. This example does not provide an implementation function. Write your own implementation.

Example Model

Open the model crl_blas for configuring the code replacement library.

open_system('crl_blas');

copyfile BlasTargetInfo.txt rtwTargetInfo.m

Run the MATLAB customization file to create a code replacement table and register the file. The customization file has already been executed. Run the sl_refresh_customizations function to register the library.

sl_refresh_customizations;

Enable Code Replacement Library

  1. Open the Configuration Parameters dialog box.

  2. On the Interface pane, set Code Replacement Library by clicking Select and adding CRL for matrix multiplication for Mathworks Blas code to the Selected code replacement libraries - prioritized list pane. Alternatively, use the command-line API to enable the code replacement:

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

Generate code from the model:

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

View the generated code. Here is a portion of crl_blas.c.

cfile = fullfile('crl_blas_ert_rtw','crl_blas.c');
coder.example.extractLines(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);
}

The matrix/matrix multiplication operation is repalced with the custom dgemm32 function.

Close the model and code generation report.

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

Related Topics