Main Content

Convert Data Copies to Pointer Assignments

The code generator optimizes generated code for vector signal assignments by trying to replace for loop controlled element assignments and memcpy function calls with pointer assignments. Pointer assignments avoid expensive data copies. Therefore, they use less stack space and offer faster execution speed than for loop controlled element assignments and memcpy function calls. If you assign large data sets to vector signals, this optimization can result in significant improvements to code efficiency.

Configure Model to Optimize Generated Code for Vector Signal Assignments

To apply this optimization:

  1. Verify that your target supports the memcpy function.

  2. Determine whether your model uses vector signal assignments (such as Y=expression) to move large amounts of data. For example, your model could use a Selector block to select input elements from a vector, matrix, or multidimension signal.

  3. On the Optimization pane, the Use memcpy for vector assignment parameter, which is on by default, enables the associated Memcpy threshold (bytes) parameter.

  4. Examine the setting of Memcpy threshold (bytes). By default, it specifies 64 bytes as the minimum array size for which memcpy function calls or pointer assignments can replace for loops in the generated code. Based on the array sizes in your application's vector signal assignments, and target environment considerations on the threshold selection, accept the default value or specify another array size.

Example Model

Open the example model rtwdemo_pointer_conversion. This model uses a Switch block to assign data to a vector signal. This signal then feeds into a Bus Selector block.

model='rtwdemo_pointer_conversion';
open_system(model);

Generate Code Without Optimization

In the Configuration Parameters dialog box, clear the Use memcpy for vector assignment parameter. Alternatively, use the command-line.

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

Press Ctrl+B to generate code. Alternatively, use the command-line.

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

Build Summary

Top model targets:

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

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

View the generated code without the optimization. Here is a portion of rtwdemo_pointer_conversion.c.

cfile = fullfile('rtwdemo_pointer_conversion_ert_rtw','rtwdemo_pointer_conversion.c');
coder.example.extractLines(cfile,'/* Model step','/* Model initialize',1, 0);
/* Model step function */
void rtwdemo_pointer_conversion_step(void)
{
  int32_T i;
  int16_T rtb_dataX[100];
  int16_T rtb_dataY[100];

  /* Switch generated from: '<Root>/Switch' incorporates:
   *  Constant: '<Root>/Constant'
   *  Constant: '<Root>/Constant1'
   *  Constant: '<Root>/Constant2'
   *  Constant: '<Root>/Constant3'
   *  Inport: '<Root>/In1'
   */
  for (i = 0; i < 100; i++) {
    if (rtU.In1) {
      rtb_dataX[i] = rtCP_Constant_Value[i];
      rtb_dataY[i] = rtCP_Constant1_Value[i];
    } else {
      rtb_dataX[i] = rtCP_Constant2_Value[i];
      rtb_dataY[i] = rtCP_Constant3_Value[i];
    }
  }

  /* End of Switch generated from: '<Root>/Switch' */

  /* S-Function (sfix_look1_dyn): '<Root>/Lookup Table Dynamic' incorporates:
   *  Inport: '<Root>/In2'
   *  Outport: '<Root>/Out1'
   */
  /* Dynamic Look-Up Table Block: '<Root>/Lookup Table Dynamic'
   * Input0  Data Type:  Integer        S16
   * Input1  Data Type:  Integer        S16
   * Input2  Data Type:  Integer        S16
   * Output0 Data Type:  Integer        S16
   * Lookup Method: Linear_Endpoint
   *
   */
  LookUp_S16_S16( &(rtY.Out1), &rtb_dataY[0], rtU.In2, &rtb_dataX[0], 99U);
}

Without the optimization, the generated code contains for loop controlled element assignments.

Enable Optimization and Generate Code

In the Configuration Parameter dialog box, select the Use memcpy for vector assignment parameter.

set_param(model, 'EnableMemcpy','on')

Generate code.

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

Build Summary

Top model targets:

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

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

View the generated code with the optimization. Here is a portion of rtwdemo_pointer_conversion.c.

cfile = fullfile('rtwdemo_pointer_conversion_ert_rtw','rtwdemo_pointer_conversion.c');
coder.example.extractLines(cfile,'/* Model step','/* Model initialize',1, 0);
/* Model step function */
void rtwdemo_pointer_conversion_step(void)
{
  const int16_T *rtb_dataX_0;
  const int16_T *rtb_dataY_0;

  /* Inport: '<Root>/In1' */
  if (rtU.In1) {
    /* Switch generated from: '<Root>/Switch' incorporates:
     *  Constant: '<Root>/Constant'
     */
    rtb_dataX_0 = &rtCP_Constant_Value[0];

    /* Switch generated from: '<Root>/Switch' incorporates:
     *  Constant: '<Root>/Constant1'
     */
    rtb_dataY_0 = &rtCP_Constant1_Value[0];
  } else {
    /* Switch generated from: '<Root>/Switch' incorporates:
     *  Constant: '<Root>/Constant2'
     */
    rtb_dataX_0 = &rtCP_Constant2_Value[0];

    /* Switch generated from: '<Root>/Switch' incorporates:
     *  Constant: '<Root>/Constant3'
     */
    rtb_dataY_0 = &rtCP_Constant3_Value[0];
  }

  /* End of Inport: '<Root>/In1' */

  /* S-Function (sfix_look1_dyn): '<Root>/Lookup Table Dynamic' incorporates:
   *  Inport: '<Root>/In2'
   *  Outport: '<Root>/Out1'
   */
  /* Dynamic Look-Up Table Block: '<Root>/Lookup Table Dynamic'
   * Input0  Data Type:  Integer        S16
   * Input1  Data Type:  Integer        S16
   * Input2  Data Type:  Integer        S16
   * Output0 Data Type:  Integer        S16
   * Lookup Method: Linear_Endpoint
   *
   */
  LookUp_S16_S16( &(rtY.Out1), &rtb_dataY_0[0], rtU.In2, &rtb_dataX_0[0], 99U);
}

Because the setting of the Memcpy threshold (bytes) parameter is below the array sizes in the generated code, the optimized code contains pointer assignments for the vector signal assignments.

bdclose(model)

See Also

|

Related Topics