Documentation

Optimize Generated Code By Developing and Using Code Replacement Libraries - Simulink®

Develop and use code replacement libraries to replace function and operators in generated code. Code replacement is a technique to change the code that the code generator produces for functions and operators to meet application code requirements. For example, you can replace generated code to meet requirements such as:

  • Optimization for a specific run-time environment, including, but not limited to, specific target hardware

  • Integration with existing application code

  • Compliance with a standard, such as AUTOSAR

  • Modification of code behavior, such as enabling or disabling nonfinite or inline support

  • Application- or project-specific code requirements, such as use of BLAS or elimination of math.h, system header files, or calls to memcpy or memset.

You can configure a model such that the code generator uses a code replacement library that MathWorks® provides. If you have an Embedded Coder® license, you can develop your own code replacement library interactively with the Code Replacement Tool or programmatically.

This example uses models to show a variety of ways you can define code replacement mappings programmatically. Each model includes buttons that you can use to

  • View the code replacement library table definitions from the Code Replacement Viewer

  • Open the library table definition file in the editor

  • Open the library registration file in the editor

  • View the model configuration

  • Generate code

For more information, see Define Code Replacement Mappings and Register Code Replacement Mappings.

Steps for Developing a Code Replacement Library

  1. Identify your code replacement requirements with respect to function or operating mappings, build information, and registration information.

  2. Prepare for code replacement library development (for example, identify or develop models to test your library).

  3. Define code replacement mappings.

  4. Specify build information for replacement code.

  5. Register code replacement mappings.

  6. Verify code replacements.

  7. Deploy the library.

For more information, see Quick Start Library Development.

Math Function Replacement

This example defines and registers code replacement mappings for math functions. You can define code replacement mappings for a variety of functions (see Code You Can Replace From Simulink Models).

Open the model rtwdemo_crlmath and use the buttons at the bottom of the model window to explore the files that define and register the code replacement library mappings.

For more information, see Math Function Code Replacement.

open_system('rtwdemo_crlmath')

Addition and Subtraction Operator Replacement

This example shows how to define and register code replacement mappings for addition (+) and subtraction (-) operations. When defining entries for addition and subtraction operatations, you can specify which of the following algorithms (EntryInfoAlgorithm) your library functions implement:

  • Cast-before-operation (CBO) (RTW_CAST_BEFORE_OP), the default

  • Cast-after-operation (CAO) (RTW_CAST_AFTER_OP)

1. Open the model rtwdemo_crladdsub. The model shows how to define and register code replacement mappings for scalar addition subtraction (-) operations on two operands with the following pairings of built-in integer data types:

  • int8, uint8

  • int16, uint16

  • int32, uint32

CBO, the default algorithm, is assumed.

open_system('rtwdemo_crladdsub')

2. Use the buttons at the bottom of the model window to explore the files that define and register the code replacement library mappings.

3. Explore the differences between the CBO and CAO algorithms by opening the model rtwdemo_crl_cbo_cao. The model shows two SUM blocks, each demonstrating one of the algorithm settings to match a corresponding code replacement entry.

  • For the Cast_before_operation_Sub block, the code generator calculates the subtraction operation in the accumulator data type (int8), which is smaller than the input data type (int16). This is equivalent to a CBO because the code generator converts the input to the output data type before calculating the result.

  • For the Cast_after_operation_Sub block, the code generator calculates the subtraction operation in the accumulator data type (int32), which is larger than the input data type (int16). This is equivalent to a CAO because the code generator produces the same result by calculating the result without loss of range or precision before converting to the output data type.

open_system('rtwdemo_crl_cbo_cao')

4. Use the buttons at the bottom of the model window to explore the files that define and register the code replacement library mappings.

For more information on addition and subtraction operator replacement, see Addition and Subtraction Operator Code Replacement. For more information on the addition and subtraction algorithm (EntryInfoAlgorithm) options, see setTflCOperationEntryParameters.

Multiplication and Division Operator Replacement for Built-In Integers

This example defines and registers code replacement mappings for scalar multiplication (*) and division (/) operations. The operations take two operands with the following pairings of built-in integer data types:

  • int8, uint8

  • int16, uint16

  • int32, uint32

Open the model rtwdemo_crlmuldiv and use the buttons at the bottom of the model window to explore the files that define and register the code replacement library mappings.

open_system('rtwdemo_crlmuldiv')

Scalar Operator Replacement

This example defines and registers code replacement mappings for scalar operations: addition, subraction, multiplication, complex conjugate, cast, arithmetic shift right, and arithmetic shift left.

Supported types include:

  • single, double

  • int8, uint8

  • int16, uint16

  • int32, uint32

  • csingle, cdouble

  • cint8, cuint8

  • cint16, cuint16

  • cint32, cuint32

  • fixed-point integers

  • mixed types (different type on each input)

Open the model rtwdemo_crlscalarops and use the buttons at the bottom of the model window to explore the files that define and register the code replacement library mappings.

For more information on scalar operator replacement, Scalar Operator Code Replacement.

CBO, the default algorithm for addition and subtraction operations, is assumed.

open_system('rtwdemo_crlscalarops')

Matrix Operator Replacement

This example defines and registers code replacement mappings for matrix operations: addition, subtraction, multiplication, transposition, conjugate, and Hermitian.

Supported types include:

  • single, double

  • int8, uint8

  • int16, uint16

  • int32, uint32

  • csingle, cdouble

  • cint8, cuint8

  • cint16, cuint16

  • cint32, cuint32

  • fixed-point integers

  • mixed types (different type on each input)

Open the model rtwdemo_crlmatops, which shows some of these replacements. Use the buttons at the bottom of the model window to explore the files that define and register the code replacement library mappings.

For more information on matrix operator replacement, see Small Matrix Operation to Processor Code Replacement.

CBO, the default algorithm for addition and subtraction operations, is assumed.

open_system('rtwdemo_crlmatops')

Matrix Multiplication Replacement for BLAS

This example defines and registers code replacement mappings for Basic Linear Algebra Subroutines (BLAS) subroutines xGEMM and xGEMV. You can map the following operations to a BLAS subroutine:

  • Matrix multiplication

  • Matrix multiplication with transpose on single or both inputs

  • Matrix multiplication with Hermitian operation on single or both inputs

Open the model rtwdemo_crlblas and use the buttons at the bottom of the model window to explore the files that define and register the code replacement library mappings.

For more information on matrix multiplication replacement for BLAS, see Matrix Multiplication Operation to MathWorks BLAS Code Replacement.

open_system('rtwdemo_crlblas')

Fixed-Point Operator Replacement for Basic Operators

This example defines and registers code replacement mappings for scalar addition (+), subtraction (-), multiplication (*), and division (/) operations. The operations take two operands with fixed-point data types.

You can define code replacements as matching:

  • Slope/bias scaling combination on the inputs and output

  • Binary-point scaling combination on the inputs and output

  • Relative scaling between the inputs and output

  • Same slope value and a zero net bias across the inputs and output.

Open the model rtwdemo_crlfixpt and use the buttons at the bottom of the model window to explore the files that define and register the code replacement library mappings.

  • By default, for addition and subtraction operator code replacements, the code generator assumes that replacement code implements a cast-before-operation (CBO) algorithm.

  • Using fixed-point data types in a model requires a Fixed-Point Designer™ license.

For more information about fixed-point operator code replacement, see Fixed-Point Operator Code Replacement.

open_system('rtwdemo_crlfixpt')

Match and Replacement Process Customization for Functions

This example defines and registers code replacement mappings for custom entries. You can create your own entry by subclassing from RTW.TflCFunctionEntryML or RTW.TflCOperationEntryML. Your entry class must implement a do_match method that customizes your matching logic or modifies the matched entry. The do_match method must have a fixed preset signature.

Open the model rtwdemo_crlcustomentry. The model shows how to modify the matched entry by injecting constants as additional implementation function arguments. DTC1, Trigonometric Function, and Product show custom entry code replacement for:

  • Cast operation that demonstrates how to extract the fraction lenghts from types and pass them into the implementation function - Out1 = custom_cast(In1, 2, 4).

  • Sine that demonstrates how to pass a constant value to the implementation function - Out2=custom_sin(In2, 1).

  • Multiplication operation that demonstrates how to compute the net slope of an operation and pass that into the implementation function - Out3=custom_multiply_shift_right(In3,In4,3).

Use the buttons at the bottom of the model window to explore the files that define and register the code replacement mappings.

For more information on custom entries, see Customize Match and Replacement Process.

open_system('rtwdemo_crlcustomentry')

MATLAB Function Replacement

This example defines and registers code replacement mappings for MATLAB® functions specified in the MATLAB Function block. The function can be opted for replacement by specifying coder.replace within it. This feature supports replacement of MATLAB® functions with the following:

  • Single or multiple inputs

  • Single or multiple outputs

  • Scalar and matrix inputs and outputs

Open the model rtwdemo_crlcoderreplace. The model shows some of these requirements. Supported types include:

  • single, double

  • int8, uint8

  • int16, uint16

  • int32, uint32

  • csingle, cdouble

  • cint8, cuint8

  • cint16, cuint16

  • cint32, cuint32

  • Fixed-point integers

  • Mixed types (different type on each input)

Use the buttons at the bottom of the model window to explore the files that define and register the code replacement mappings.

For more information on MATLAB® function replacement, see coder.replace.

open_system('rtwdemo_crlcoderreplace')

Data Alignment for Function Implementations

This example shows how to specify the alignment of matrix operands passed into a replacement function. Some target-specific function implementations require data to be aligned to optimize application performance. To configure data alignment for a function implementation:

  • Specify the data alignment requirements in a table entry. You can specify alignment for implementation function arguments individually or collectively.

  • Specify the data alignment capabilities and syntax for your compiler. Attach an AlignmentSpecification object to the TargetCharacteristics object of the registry entry specified in your rtwTargetInfo.m file.

Open the model rtwdemo_crlalign. The model shows three data alignment code replacement scenarios:

  • Add - Alignment of exported and imported signals. You can specify an exact value for the alignment in the Signal Properties dialog box or allow the code generator to determine the best alignment based on usage by leaving the alignment value set to -1.

  • Product - Alignment of virtual and nonvirtual bus types. You can specify an exact value for the alignment for the Alignment property of the Simulink.Bus object or allow the code generator to determine the best alignment based on usage by leaving the Alignment property set to -1.

  • EML_MMUL - Alignment of local variables, global variables, and block parameters.

Use the buttons at the bottom of the model window to explore the files that define and register the code replacement mappings. Note that the model is configured to use a GCC, Clang, MSVC, or MinGW compiler.

For more information on specifying data alignment for code replacement, see Data Alignment for Code Replacement.

open_system('rtwdemo_crlalign')

Performance Gain from Data Alignment

This example shows how code replacement data alignment can accelerate execution of a generated executable by enabling deployment of SIMD operations in generated code.

1. Open model rtwdemo_crlalignperf. This model illustrates a basic image processing algorithm, represented by subsystem Root/Filtering/Process/ALGORITHM. The algorithm slides a 5x5 template across the image one pixel at a time. The image area covered by the template forms another 5x5 matrix. This matrix is element-wise multiplied by the template matrix. The twenty-five elements in the resultant matrix are summed together to form the new value for that pixel. This element-wise matrix multiplication is performed for all pixels in an image, so its efficiency has a significant impact on the overall algorithm performance.

perf = 'rtwdemo_crlalignperf';
open_system(perf)

cc = rtwprivate('getCompilerForModel',perf);
isDaDemoSupported = strcmpi(cc.comp.Manufacturer,'GNU') || ...
                    strcmpi(cc.comp.Manufacturer,'Apple') || ...
                    strcmpi(cc.comp.Manufacturer,'Microsoft');
if ~isDaDemoSupported
  recMsg = ['Use "mex -setup" to select either GCC, Clang, MSVC, or MinGW and restart this ' ...
            'example'];
  warning(['The model "%s" is configured to use GCC, Clang, MSVC, or MinGW to create ' ...
          'a Data Aligned Executable. %s.'], perf,recMsg); %#ok<CTPCT>
end

2. Use the buttons at the bottom of the model window to explore the files that define and register the code replacement mappings.

3. Execute the example by double-clicking Start the Example. Note that the model is configured to use a GCC, Clang, MSVC, or MinGW compiler. This example compiles the model twice. The first compilation produces portable, ANSI-C code without data alignment. The second compilation uses a SIMD code replacement library that does the element-wise matrix multiply using SIMD instructions. The data on which the SIMD instructions operate needs to be aligned on a 16-byte boundary. For both compilations, the generated code is profiled by a profiling hook. After the compilations complete, a figure appears to show a comparison of the execution time of the subsystem Root/Filtering/Process/ALGORITHM with and without data alignment.

For more information on how to use profile hooks, see the example model rtwdemo_profile.

4. Generate a baseline by selecting the ANSI® library, building the model, and then running the generated executable ten times. This model uses an element-wise matrix multiplication operation as part of an image processing algorithm. The matrix multiplication is executed numerous times as each pixel in the image is processed. Profiling hooks time the execution of the executable.

if (isDaDemoSupported)
  % Create a temporary folder (in your system's temporary folder) for the
  % build and inspection process.
  currentDir = pwd;
  [~,cgDir] = rtwdemodir();

  set_param(perf, 'CodeReplacementLibrary','None' ...
                                  , 'TargetLangStandard','C89/C90 (ANSI)');
  rtwbuild(perf);
  iterations = 10;
  T1 = zeros(iterations, 1);
  for idx = 1:iterations
      evalc(['!', fullfile('.', perf)]);
      evalc(['load ', fullfile('.','rtwdemo_crlalignperf.mat')]);
      T1(idx) = rt_yout.signals(1).values;
  end
  if exist('rtwdemo_crlalignperf_ANSI', 'dir')
      rmdir('rtwdemo_crlalignperf_ANSI', 's');
  end
  movefile('rtwdemo_crlalignperf_ert_rtw', 'rtwdemo_crlalignperf_ANSI');
else
  warning('Unable to build model "%s". %s.', perf,recMsg);
end
### Starting build procedure for model: rtwdemo_crlalignperf
### Successful completion of build procedure for model: rtwdemo_crlalignperf

5. Generate an optimized, data-aligned executable by selecting a library that maps element-wise matrix multiplication operations to SIMD intrinsic calls, and then building the model. The SIMD intrinsic calls impose an alignment requirement on data passed to the intrinsic. The optimized executable is run ten times. Profiling hooks again capture timing data.

if (isDaDemoSupported)
  crl=getCorrectCrlForSelectedCompiler(perf);
  set_param(perf,'CodeReplacementLibrary',crl);
  rtwbuild(perf);
  T2 = zeros(iterations, 1);
  for idx=1:iterations
      evalc(['!', fullfile('.', perf)]);
      evalc(['load ', fullfile('.','rtwdemo_crlalignperf.mat')]);
      T2(idx) = rt_yout.signals(1).values;
  end
  if exist('rtwdemo_crlalignperf_SIMD', 'dir')
      rmdir('rtwdemo_crlalignperf_SIMD','s');
  end
  movefile('rtwdemo_crlalignperf_ert_rtw', 'rtwdemo_crlalignperf_SIMD');
else
  warning('The Data Aligned Executable for the model "%s" could not be generated. %s.' ...
          ,perf,recMsg);
end
### Starting build procedure for model: rtwdemo_crlalignperf
### Successful completion of build procedure for model: rtwdemo_crlalignperf

6. Compare timing results of the baseline and data-aligned executables. The timing data captured from running the baseline and data-aligned executables is displayed in a graph. The graph illustrates that using SIMD operations with data alignment can effectively speed up execution of data-parallel operations.

if (isDaDemoSupported)
  T1(T1<0) = NaN;    % The profile counter may overflow.
  T2(T2<0) = NaN;
  t = [min(T1), min(T2)];
  h = figure;

  bar([NaN, t(1), NaN, t(2), NaN]);
  set(gca, 'XLim', [0.5, 5.5], 'XTickLabel', {'', 'ANSI Multiply', '', 'SIMD Multiply', ''}, ...
           'TickLength', [0 0], 'YLim', [0, max(t) * 1.3], 'YTick', []);
  ylabel('Execution Time (CPU Cycles)');
  % annotate the plot
  annotation('textbox', get(gca, 'Position'), ...
             'String', ['Execution Speed Increased By: ', num2str((1 - t(2)/t(1))*100, '%2.0f'), '%'], ...
             'LineStyle', 'none', 'FitBoxToText', 'off', 'FitHeightToText', 'on', ...
             'FontWeight', 'bold', 'FontSize', 12, 'HorizontalAlignment', 'center');
  % annotate first bar (simple multiply without alignment)
  text('Position', [2, t(1)], 'String', int2str(t(1)), 'LineStyle', 'none', ...
       'FontSize', 12, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'bottom');

  % annotate second bar (SIMD Multiply without alignment)
  text('Position', [4, t(2)],  'String', int2str(t(2)), 'LineStyle', 'none', ...
       'FontSize', 12, 'HorizontalAlignment', 'center', 'VerticalAlignment', 'bottom');
else
  warning('The Data Alignment Performance Gain example could not be executed. %s.' ...
        , recMsg);
end

Code Replacement Library Exploration and Verification

This example shows Code Replacement Viewer. You can use the Code Replacement Viewer to:

  • Explore which code replacement library to use

  • Verify the list of tables in a library and the entries in each table

  • Review table entry specifications

  • Troubleshoot code replacement misses

The following commands open the Code Replacement Viewer for code replacement table crl_tablemuldiv:

crl = crl_table_muldiv;
crviewer(crl);
daRoot = DAStudio.Root;
me = daRoot.find('-isa', 'DAStudio.Explorer');

For more information on the Code Replacement Viewer, see Verify Code Replacements.

Build Information

For each entry in a code replacement table, you can specify build information such as the following, for replacements functions:

  • Header file dependencies

  • Source file dependencies

  • Additional include paths

  • Additional source paths

  • Additional link flags

Additionally, you can specify RTW.copyFileToBuildDir to copy header, source, or object files, which are required to generate replacement code, to the build folder before code generation. You can specify RTW.copyFileToBuildDir by setting it as the value of:

  • Property GenCallback in a call to setTflCFunctionEntryParameters, setTflCOperationEntryParameters, or setTflCSemaphoreEntryParameters.

  • Argument genCallback in a call to registerCFunctionEntry, registerCOperationEntry, or registerCSemaphoreEntry.

Note: Models in this example are configured for code generation only because the implementations for the replacement functions are not provided.

For more information on specifying build information, see Specify Build Information for Replacement Code.

Reserved Identifiers

Each function implementation name defined by a code replacement table entry is reserved as a unique identifier. You can specify other identifiers with a table on a per-header-file basis. Providing additional reserved identifiers can help prevent duplicate symbols and other identifier related compile and link issues.

For more information on specifying reserved identifiers, see Reserved Identifiers and Code Replacement.

Remove Example Code Replacement Libraries

When you finish using the example models, remove the example code replacement libraries and close the example models with these commands:

rmpath(fullfile(matlabroot,'toolbox','rtw','rtwdemos','crl_demo'));
sl_refresh_customizations;

close_system('rtwdemo_crladdsub', 0)
close_system('rtwdemo_crl_cbo_cao', 0)
close_system('rtwdemo_crlmuldiv', 0)
close_system('rtwdemo_crlfixpt', 0)
close_system('rtwdemo_crlmath', 0)
close_system('rtwdemo_crlmatops', 0)
close_system('rtwdemo_crlblas', 0)
close_system('rtwdemo_crlscalarops', 0)
close_system('rtwdemo_crlcustomentry', 0)
close_system('rtwdemo_crlcoderreplace', 0)
close_system('rtwdemo_crlalign', 0)
close_system(perf, 0)

drawnow;
if exist('h','var') && ishghandle(h)
  close(h);
end

if ~isempty(me)
    me(end).delete;
end

clear h;
clear crl;
clear codersrc;
clear codercurdir;
clear n1;
clear me;
clear cfg;
clear t;
clear cc;
clear recMsg;
clear isDaDemoSupported;
clear T1;
clear T2;
clear idx;
clear iterations;
clear rt_tout;
clear rt_yout;
clear crl;
clear perf;

rtwdemoclean;
cd(currentDir)
Was this topic helpful?