Specify Buffer Reuse for Signals in a Path - MATLAB & Simulink (original) (raw)

If your model has the optimal parameter settings for removing data copies, you might be able to remove additional data copies by using the Reusable storage class on the signals through the Code Mappings editor or Simulink.Signal data objects. This optimization decreases data copies and memory consumption and increases code execution speed. After studying the generated code and the Static Code Metrics Report and identifying areas where you think buffer reuse is possible, you specify the Reusable storage class on signal lines.

You can specify buffer reuse on signals that include a pair of root inport and outport signals. You can also specify buffer reuse on just a pair of root inport and outport signals. This optimization reduces ROM and RAM consumption because there are less global variables and data copies in the generated code. Code execution speed also increases.

Example Model

The model ex_reusable_csc contains the nonreusable subsystem DeltaSubsystem and the MATLAB Function block Downsample. DeltaSubsystem contains the MATLAB Function blocks DeltaX and DeltaY.

model ='ex_reusable_csc'; open_system(model);

Specify Reusable Storage Class in Code Mappings Editor

  1. Open the Embedded Coder app.
  2. To open the Code Mappings editor, click Code Interface > Individual Element Code Mappings.
  3. In the model, select the RCSC_REAL signal line. To view this signal or any signal in the Code Mappings editor, on the Signals/States tab, click the Add selected signals to code mappings button.
  4. For the row that represents the signal line, set the Storage Class column to Reusable.
  5. Similary, add these signals to the Code Mappings editor and set Storage Class to Reusable:

And these signals inside the subsystem:

Alternatively, use these commands in the MATLABĀ® Command Window:

cmo = coder.mapping.utils.create(model); cm = coder.mapping.api.get(model);

portHandles = get_param(... 'ex_reusable_csc/Complex to Real-Imag','portHandles'); addSignal(cm,[portHandles.Outport(1),portHandles.Outport(2)],... 'StorageClass','Reusable');

portHandles = get_param(... 'ex_reusable_csc/Downsample','portHandles'); addSignal(cm,[portHandles.Outport(1),portHandles.Outport(2)],... 'StorageClass','Reusable');

portHandles = get_param(... 'ex_reusable_csc/DeltaSubsystem/DeltaX','portHandles'); addSignal(cm,[portHandles.Outport(1),portHandles.Outport(2)],... 'StorageClass','Reusable');

portHandles = get_param(... 'ex_reusable_csc/DeltaSubsystem/DeltaY','portHandles'); addSignal(cm,[portHandles.Outport(1),portHandles.Outport(2)],... 'StorageClass','Reusable');

Build the model.

Searching for referenced models in model 'ex_reusable_csc'.

Total of 1 models to build.

Starting build procedure for: ex_reusable_csc

Successful completion of build procedure for: ex_reusable_csc

Build Summary

Top model targets:

Model Build Reason Status Build Duration

ex_reusable_csc Information cache folder or artifacts were missing. Code generated and compiled. 0h 0m 19.692s

1 of 1 models built (0 models already up to date) Build duration: 0h 0m 20.144s

For buffer reuse, the ex_reusable_csc.c file contains these global variables:

cfile = fullfile(pwd,... 'ex_reusable_csc_ert_rtw','ex_reusable_csc.c'); coder.example.extractLines(cfile,... '/* Definition for custom storage class: Reusable /',... '/ External inputs (root inport signals with default storage) */',1,0);

/* Definition for custom storage class: Reusable / static real_T RCSC_IMAG[1048576]; / '/Complex to Real-Imag' / static real_T RCSC_IMAG2[262144]; / '/Downsample' / static real_T RCSC_REAL[1048576]; / '/Complex to Real-Imag' / static real_T RCSC_REAL2[262144]; / '/Downsample' */

The ex_reusable_csc.c file contains this code:

cfile = fullfile(pwd,... 'ex_reusable_csc_ert_rtw','ex_reusable_csc.c'); coder.example.extractLines(cfile,... '/* Output and update for atomic system: ''/DeltaSubsystem'' /',... '/ Output and update for atomic system: ''/Downsample'' /',1,0); coder.example.extractLines(cfile,... '/ Model step function /','/ Model initialize function */',1,0);

/* Output and update for atomic system: '/DeltaSubsystem' / static void DeltaSubsystem(void) { / ComplexToRealImag: '/Complex to Real-Imag' incorporates:

/* SignalConversion generated from: '/Downsample' incorporates:

/* Model step function */ void ex_reusable_csc_step(void) { int32_T i;

/* ComplexToRealImag: '/Complex to Real-Imag' incorporates:

/* End of ComplexToRealImag: '/Complex to Real-Imag' */

/* MATLAB Function: '/Downsample' */ Downsample(&RCSC_REAL[0], &RCSC_IMAG[0], &RCSC_REAL2[0], &RCSC_IMAG2[0]);

/* Outputs for Atomic SubSystem: '/DeltaSubsystem' */ DeltaSubsystem();

/* End of Outputs for SubSystem: '/DeltaSubsystem' */

/* Outport: '/Out1' incorporates:

/* End of Outport: '/Out1' */ }

The variables RCSC_REAL and RCSC_IMAG hold the outputs of the Complex to Real-Image block and DeltaX. These variables hold the inputs to the DeltaY block. The variables RCSC_REAL2 and RCSC_IMAG2 hold the outputs of Downsample and DeltaY. These variables hold the inputs to the DeltaX block. By interleaving buffers in this way, you eliminate redundant data copies in the generated code.

To remove the signals from the Code Mappings editor, on the Signals/States tab, select the signals and click the Remove selected signals to code mappings button.

Alternatively, use these commands in the MATLAB Command Window:

portHandles = get_param(... 'ex_reusable_csc/Complex to Real-Imag','portHandles'); removeSignal(cm,[portHandles.Outport(1),portHandles.Outport(2)]);

portHandles = get_param(... 'ex_reusable_csc/Downsample','portHandles'); removeSignal(cm,[portHandles.Outport(1),portHandles.Outport(2)]);

portHandles = get_param(... 'ex_reusable_csc/DeltaSubsystem/DeltaX','portHandles'); removeSignal(cm,[portHandles.Outport(1),portHandles.Outport(2)]);

portHandles = get_param(... 'ex_reusable_csc/DeltaSubsystem/DeltaY','portHandles'); removeSignal(cm,[portHandles.Outport(1),portHandles.Outport(2)]);

When you generate code for the model, the ex_reusable_csc.h contains two extra global variables:

slbuild(model); cfile = fullfile(pwd,... 'ex_reusable_csc_ert_rtw','ex_reusable_csc.h'); coder.example.extractLines(cfile,... '/* Block signals and states',... '} D_Work;',1,0);

Searching for referenced models in model 'ex_reusable_csc'.

Total of 1 models to build.

Starting build procedure for: ex_reusable_csc

Successful completion of build procedure for: ex_reusable_csc

Build Summary

Top model targets:

Model Build Reason Status Build Duration

ex_reusable_csc Generated code was out of date. Code generated and compiled. 0h 0m 10.224s

1 of 1 models built (0 models already up to date) Build duration: 0h 0m 10.667s

/* Block signals and states (default storage) for system '' / typedef struct { real_T z2[262144]; / '/DeltaY' / real_T z1[262144]; / '/DeltaY' / real_T z1_m[261632]; / '/DeltaX' / real_T z2_c[261632]; / '/DeltaX' / real_T RCSC_REAL[1048576]; / '/Complex to Real-Imag' / real_T RCSC_IMAG[1048576]; / '/Complex to Real-Imag' */

The ex_reusable_csc.c file now contains this code.

cfile = fullfile(pwd,... 'ex_reusable_csc_ert_rtw','ex_reusable_csc.c'); coder.example.extractLines(cfile,... '/* Output and update for atomic system: ''/DeltaSubsystem'' /',... '/ Output and update for atomic system: ''/Downsample'' /',1,0); coder.example.extractLines(cfile,... '/ Model step function /','/ Model initialize function */',1,0);

/* Output and update for atomic system: '/DeltaSubsystem' / static void DeltaSubsystem(void) { / MATLAB Function: '/DeltaX' */ DeltaX(rtDWork.z2, rtDWork.z1, rtDWork.z1_m, rtDWork.z2_c);

/* MATLAB Function: '/DeltaY' */ DeltaY(rtDWork.z1_m, rtDWork.z2_c, &rtDWork.z1[0], &rtDWork.z2[0]); }

/* Model step function */ void ex_reusable_csc_step(void) { int32_T i;

/* ComplexToRealImag: '/Complex to Real-Imag' incorporates:

/* End of ComplexToRealImag: '/Complex to Real-Imag' */

/* MATLAB Function: '/Downsample' */ Downsample(rtDWork.RCSC_REAL, rtDWork.RCSC_IMAG, rtDWork.z2, rtDWork.z1);

/* Outputs for Atomic SubSystem: '/DeltaSubsystem' */ DeltaSubsystem();

/* End of Outputs for SubSystem: '/DeltaSubsystem' */

/* Outport: '/Out1' incorporates:

/* End of Outport: '/Out1' */ }

The generated code contains two additional global variables for holding block inputs and outputs.

Limitations for the Model That Use Reusable Storage Class in Code Mappings Editor

For reused data elements, you can specify the same value for the Identifier property. If you do not specify a value for the Identifier, the code generator uses the same signal label to name the reusable signal in the generated code. The code generator does not reuse signals if:

1. Open the model ReusableStorageClass.

model ='ReusableStorageClass'; open_system(model);

2. The signals in the model resolve to the corresponding Simulink.Signal data objects in the Base Workspace. Right-click on the RCSC_REAL signal line. From the context menu, select Properties. In the Signal Properties dialog box, inspect that the signal name is RCSC_REAL and the parameter Signal name must resolve to Simulink signal object is selected. This setting indicates that there is a Simulink.Signal data object in the Base Workspace with the same name as RCSC_REAL.

3. In the model, navigate into the DeltaSubsystem subsystem. Select the RCSC_REAL signal line in this subsystem. This signal also resolves to the signal object in the Base Workspace.

4. In the Base Workspace, double click the data object RCSC_REAL. The Simulink.Signal dialog box opens.

5. On the Code Generation tab, inspect that the Storage class parameter is set to Reusable. This setting instructs the code generator to generate code for the signal as a global variable named RCSC_REAL. With the Reusable storage class, the generated code can store the output of the Complex to Real-Imag block (at the root-level of the model) and the output of the MATLAB Function block DeltaX (in the subsystem) in the RCSC_REAL global variable.

6. In the Apps gallery, under Code Generation, click Embedded Coder. The C Code tab opens.

7. Click the Build button.

The generated code achieves the same results as the preceding workflow where you add signals to the Code Mappings editor and set Storage Class to Reusable.

Note: You can specify buffer reuse on signals that the code generator cannot implement. For those cases, use two diagnostics to specify the message type that the model displays. In the Configuration Parameters dialog box, these diagnostics are Detect non-reused custom storage classes and Detect ambiguous custom storage class final values.

Buffer Reuse for Unit Delay and Delay Blocks

To reuse the signal of a Unit Delay or Delay block, use the same reusable storage class specification for a pair of input and state arguments or a pair of output and state arguments of a Unit Delay or a Delay block. For Delay blocks, you must set the Delay length parameter to 1 and Initial condition > Source to Dialog. To access these parameters, in the model, open the Property Inspector and click the block in the model.

Limitations for Root Inport and Outport Signals

These limitations apply to a model in which you specify buffer reuse for a pair of root inport and outport signals:

During simulation, the unwritten Assignment block output values are zero. During code generation, the unwritten output values are the same as the input.

These limitations apply to a model in which you specify buffer reuse for signals by using a Simulink.Signal data object:

See Also

Topics