Main Content

Optimize Generated Code by Using Signal Labels to Guide Buffer Reuse

If your model has the optimal parameter settings for removing data copies, you might be able to remove additional data copies by using signal labels. After studying the generated code and the Static Code Metrics Report and identifying areas where you think buffer reuse is possible, you can add labels to signal lines. If possible, the code generator reorders block operations to implement the reuse specification.

Specifying buffer reuse improves execution speed and may reduce RAM consumption.

Example Model

The model SignalLabelReuse demonstrates how you can use signal labels to request buffer reuse for block input and output signals. The generated code can use the same variable for the Saturation and Atomic Subsystem block outputs because those signals contain the same label and the Use Signal Labels to Guide Buffer Reuse parameter is selected.

model='SignalLabelReuse';
open_system(model);

Generate Code Without Optimization

The Use Signal Labels to Guide Buffer Reuse parameter is on by default. Open the Configuration Parameters dialog box and clear the parameter. Alternatively, use the command-line.

set_param(model, 'LabelGuidedReuse', 'off');

Build the model.

slbuild(model)
### Starting build procedure for: SignalLabelReuse
### Successful completion of build procedure for: SignalLabelReuse

Build Summary

Top model targets:

Model             Build Reason                                         Status                        Build Duration
===================================================================================================================
SignalLabelReuse  Information cache folder or artifacts were missing.  Code generated and compiled.  0h 0m 13.147s 

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

View the generated SignalLabelReuse_step function.

file = fullfile('SignalLabelReuse_ert_rtw','SignalLabelReuse.c');
coder.example.extractLines(file,'/* Model step function */','/* Model initialize function',1,1);
/* Model step function */
void SignalLabelReuse_step(void)
{
  real_T rtb_Bias[4];
  real_T rtb_Saturation[4];
  real_T rtb_Bias_0;
  int32_T i;
  AtomicSubsystem(rtU.In1, rtb_Bias);
  for (i = 0; i < 4; i++) {
    rtb_Bias_0 = rtb_Bias[i];
    if (rtb_Bias_0 > 10.0) {
      rtb_Saturation[i] = 10.0;
    } else if (rtb_Bias_0 < -10.0) {
      rtb_Saturation[i] = -10.0;
    } else {
      rtb_Saturation[i] = rtb_Bias_0;
    }

    rtb_Bias[i] = 3.0 * rtb_Bias_0;
  }

  AtomicSubsystem1(rtb_Saturation, rtb_Bias, rtY.Out1);
}

By default, within the for loop, the Gain block executes after the Saturation block. The generated code contains two local variables rtb_Saturation and rtb_Bias for holding intermediate results.

Generate Code with Optimization

Open the Configuration Parameters dialog box. Select the Use Signal Labels to Guide Buffer Reuse parameter. Alternatively, use the command-line.

set_param(model, 'LabelGuidedReuse', 'on');

Build the model.

slbuild(model)
### Starting build procedure for: SignalLabelReuse
### Successful completion of build procedure for: SignalLabelReuse

Build Summary

Top model targets:

Model             Build Reason                     Status                        Build Duration
===============================================================================================
SignalLabelReuse  Generated code was out of date.  Code generated and compiled.  0h 0m 10.409s 

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

View the generated SignalLabelReuse_step function.

file = fullfile('SignalLabelReuse_ert_rtw','SignalLabelReuse.c');
coder.example.extractLines(file,'/* Model step function */','/* Model initialize function',1,1)
/* Model step function */
void SignalLabelReuse_step(void)
{
  real_T rtb_Gain1[4];
  real_T Out1;
  int32_T i;
  AtomicSubsystem(rtU.In1, rtY.Out1);
  for (i = 0; i < 4; i++) {
    Out1 = rtY.Out1[i];
    rtb_Gain1[i] = 3.0 * Out1;
    if (Out1 > 10.0) {
      rtY.Out1[i] = 10.0;
    } else if (Out1 < -10.0) {
      rtY.Out1[i] = -10.0;
    }
  }

  AtomicSubsystem1(rtY.Out1, rtb_Gain1, rtY.Out1);
}

The code generator changed the block execution order so that within the for loop, the Saturation block executes after the Gain block. The generated code contains one local variable rtb_Gain1 for holding intermediate results.

In addition to requesting which buffers to reuse, another possible use case is to request buffer reuse for block input and output signals that are complex.

Using Label-Based Reuse Versus Reusable Storage Classes

You can also use the same Reusable storage class specification on different signal lines to specify which buffers to reuse. As compared to using Reusable storage classes, using signal labels to specify reuse has these benefits:

  • Signal labels are not observation points in the generated code, so using them does not block other optimizations such as dead code elimination and expression folding.

  • The code generator does not force a signal with a label to be a global variable in the generated code. The signal can be a local or global variable.

  • Signals with labels can reuse buffers with signals that do not have labels, so reuse among local and global variables is possible.

Using signal labels is a more conservative method of specifying reuse than using Reusable storage classes. The code generator does not implement label-based reuse when it can implement reuse by using Reusable storage classes in these cases:

  • Reuse that can potentially prevent other optimizations from occurring in the generated code.

  • Reuse on root inport and outport ports.

  • Reuse across model reference or subsystem boundaries.

  • Within a subsystem, buffer reuse on an intermediary signal and an input or output port.

See Also

Related Topics