Повышение эффективности выполнения путем переупорядочивания блочных операций в сгенерированном коде

Чтобы улучшить эффективность выполнения, генератор кода может изменить порядок выполнения блока. В диалоговом окне Параметров конфигурации, когда вы устанавливаете параметр Optimize Блока Порядка равным Improved Execution Speedгенератор кода может изменить порядок операции блока, чтобы реализовать эти оптимизации:

  • Исключить копии данных для блоков, которые выполняют операции inplace (то есть используют ту же входную и выходную переменную) и содержат код алгоритма с ненужными копиями данных.

  • Объедините больше for циклы путем выполнения блоков вместе с одинаковым размером.

  • Повторно используйте ту же переменную для входа, вывода и состояния блока Unit Delay путем выполнения блока Unit Delay перед вышестоящими блоками.

Эти оптимизации улучшают скорость выполнения и сохраняют потребление ОЗУ и ПЗУ.

Пример модели

Откройте matlab:rtwdemo_optimizeblockorder модели. Эта модель содержит три подсистемы для демонстрации того, как операции переупорядочивания блоков улучшают эффективность выполнения.

for Циклическое слияние

Подсистема LoopFusionScheduling показывает, как генератор кода переупорядочивает операции блока так, чтобы блоки с одинаковым размером выхода выполнялись вместе. Это переупорядочивание позволяет for цикл. Установите порядок блоков Optimize в сгенерированном параметре сгенерированного кода равным Off.

Во временной папке вашей системы создайте папку для процесса сборки и проверки и создайте модель.

### Starting build procedure for: rtwdemo_optimizeblockorder
### Successful completion of build procedure for: rtwdemo_optimizeblockorder

Build Summary

Top model targets built:

Model                       Action                       Rebuild Reason                                    
===========================================================================================================
rtwdemo_optimizeblockorder  Code generated and compiled  Code generation information file does not exist.  

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

Просмотрите сгенерированный код без оптимизации. Код для LoopFusionScheduling подсистема:

/* Output and update for atomic system: '<Root>/LoopFusionScheduling' */
static void LoopFusionScheduling(const real_T rtu_In1[6], const real_T rtu_In2[6],
  const real_T rtu_In3[6], const real_T rtu_In4[6], real_T rty_Out1[6], real_T
  rty_Out2[9], real_T rty_Out3[6], real_T rty_Out4[9])
{
  int32_T i;
  int32_T i_0;
  int32_T tmp;
  int32_T tmp_0;

  /* Bias: '<S2>/Bias' incorporates:
   *  Gain: '<S2>/Gain'
   */
  for (i = 0; i < 6; i++) {
    rty_Out1[i] = -0.3 * rtu_In1[i] + 0.5;
  }

  /* End of Bias: '<S2>/Bias' */

  /* Product: '<S2>/Product' */
  for (i = 0; i < 3; i++) {
    for (i_0 = 0; i_0 < 3; i_0++) {
      tmp = i_0 + 3 * i;
      rty_Out2[tmp] = 0.0;
      tmp_0 = i << 1;
      rty_Out2[tmp] += rtu_In2[tmp_0] * rtu_In1[i_0];
      rty_Out2[tmp] += rtu_In2[tmp_0 + 1] * rtu_In1[i_0 + 3];
    }
  }

  /* End of Product: '<S2>/Product' */

  /* Bias: '<S2>/Bias1' incorporates:
   *  Gain: '<S2>/Gain1'
   */
  for (i = 0; i < 6; i++) {
    rty_Out3[i] = -0.3 * rtu_In3[i] + 0.5;
  }

  /* End of Bias: '<S2>/Bias1' */

  /* Product: '<S2>/Product1' */
  for (i = 0; i < 3; i++) {
    for (i_0 = 0; i_0 < 3; i_0++) {
      tmp = i_0 + 3 * i;
      rty_Out4[tmp] = 0.0;
      tmp_0 = i << 1;
      rty_Out4[tmp] += rtu_In4[tmp_0] * rtu_In3[i_0];
      rty_Out4[tmp] += rtu_In4[tmp_0 + 1] * rtu_In3[i_0 + 3];
    }
  }

  /* End of Product: '<S2>/Product1' */
}

С порядком выполнения по умолчанию блоки выполняются слева направо и сверху вниз. В результате существуют отдельные for циклы для двух комбинаций блоков Gain и Bias и блоков Product.

Сгенерируйте код с оптимизацией. Установите порядок блоков Optimize в сгенерированном параметре сгенерированного кода равным Improved Execution Speed и создайте модель.

### Starting build procedure for: rtwdemo_optimizeblockorder
### Successful completion of build procedure for: rtwdemo_optimizeblockorder

Build Summary

Top model targets built:

Model                       Action                       Rebuild Reason                   
==========================================================================================
rtwdemo_optimizeblockorder  Code generated and compiled  Generated code was out of date.  

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

Просмотрите сгенерированный код с оптимизацией.

/* Output and update for atomic system: '<Root>/LoopFusionScheduling' */
static void LoopFusionScheduling(const real_T rtu_In1[6], const real_T rtu_In2[6],
  const real_T rtu_In3[6], const real_T rtu_In4[6], real_T rty_Out1[6], real_T
  rty_Out2[9], real_T rty_Out3[6], real_T rty_Out4[9])
{
  int32_T i;
  int32_T i_0;
  int32_T tmp;
  int32_T tmp_0;
  for (i = 0; i < 3; i++) {
    for (i_0 = 0; i_0 < 3; i_0++) {
      /* Product: '<S2>/Product' incorporates:
       *  Product: '<S2>/Product1'
       */
      tmp = i_0 + 3 * i;
      rty_Out2[tmp] = 0.0;

      /* Product: '<S2>/Product1' */
      rty_Out4[tmp] = 0.0;

      /* Product: '<S2>/Product' incorporates:
       *  Product: '<S2>/Product1'
       */
      tmp_0 = i << 1;
      rty_Out2[tmp] += rtu_In2[tmp_0] * rtu_In1[i_0];

      /* Product: '<S2>/Product1' */
      rty_Out4[tmp] += rtu_In4[tmp_0] * rtu_In3[i_0];

      /* Product: '<S2>/Product' */
      rty_Out2[tmp] += rtu_In2[tmp_0 + 1] * rtu_In1[i_0 + 3];

      /* Product: '<S2>/Product1' incorporates:
       *  Product: '<S2>/Product'
       */
      rty_Out4[tmp] += rtu_In4[tmp_0 + 1] * rtu_In3[i_0 + 3];
    }
  }

  for (i = 0; i < 6; i++) {
    /* Bias: '<S2>/Bias' incorporates:
     *  Gain: '<S2>/Gain'
     */
    rty_Out1[i] = -0.3 * rtu_In1[i] + 0.5;

    /* Bias: '<S2>/Bias1' incorporates:
     *  Gain: '<S2>/Gain1'
     */
    rty_Out3[i] = -0.3 * rtu_In3[i] + 0.5;
  }
}

В оптимизированном коде блоки с таким же размером выхода выполняются вместе. Два набора блоков Gain и Bias имеют выходной размер размерности 6так они казнят вместе. Блоки Продукта имеют выход размерности размер 9так они казнят вместе. Слияние for циклы позволяет генератору кода задать значение выражения 3 * i + i_0 равной временной переменной tmp_0. Эта оптимизация также повышает эффективность выполнения.

Повторное использование буфера для блоков Входа, Выхода и состояния Unit Delay

Подсистема RegionScheduling показывает, как генератор кода переупорядочивает операции блока, чтобы включить повторное использование буфера для входных, выходных и состояний блоков Unit Delay. Когда расчет является частью отдельных областей, которые соединяются только через блоки Delay, генератор кода может изменить порядок выполнения блока, чтобы нисходящие области выполнялись перед областями в восходящем направлении. Этот порядок выполнения позволяет максимально повторно использовать состояния блока Delay и входные и выходные переменные. Установите порядок блоков Optimize в сгенерированном параметре сгенерированного кода равным Off и создайте модель.

### Starting build procedure for: rtwdemo_optimizeblockorder
### Successful completion of build procedure for: rtwdemo_optimizeblockorder

Build Summary

Top model targets built:

Model                       Action                       Rebuild Reason                   
==========================================================================================
rtwdemo_optimizeblockorder  Code generated and compiled  Generated code was out of date.  

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

Просмотрите сгенерированный код без оптимизации. Код для RegionScheduling подсистема:

/* Output and update for atomic system: '<Root>/RegionScheduling' */
static void RegionScheduling(const real_T rtu_In1[6], const real_T rtu_In2[6],
  real_T rty_Out1[6], rtDW_RegionScheduling *localDW)
{
  real_T rtb_Sum;
  int32_T i;
  for (i = 0; i < 6; i++) {
    /* Sum: '<S3>/Sum' incorporates:
     *  UnitDelay: '<S3>/Delay'
     *  UnitDelay: '<S3>/UnitDelay'
     */
    rtb_Sum = localDW->Delay_DSTATE[i] + localDW->UnitDelay_DSTATE[i];

    /* UnitDelay: '<S3>/UnitDelay2' */
    rty_Out1[i] = localDW->UnitDelay2_DSTATE[i];

    /* Update for UnitDelay: '<S3>/Delay' incorporates:
     *  Bias: '<S3>/Bias'
     */
    localDW->Delay_DSTATE[i] = rtu_In1[i] + 3.0;

    /* Update for UnitDelay: '<S3>/UnitDelay' incorporates:
     *  Gain: '<S3>/Gain'
     */
    localDW->UnitDelay_DSTATE[i] = 2.0 * rtu_In2[i];

    /* Update for UnitDelay: '<S3>/UnitDelay2' */
    localDW->UnitDelay2_DSTATE[i] = rtb_Sum;
  }
}

С порядком выполнения по умолчанию сгенерированный код содержит дополнительную временную переменную rtb_Sum и копию данных.

Сгенерируйте код с оптимизацией. Установите порядок блоков Optimize в сгенерированном параметре сгенерированного кода равным Improved Execution Speed и создайте модель.

### Starting build procedure for: rtwdemo_optimizeblockorder
### Successful completion of build procedure for: rtwdemo_optimizeblockorder

Build Summary

Top model targets built:

Model                       Action                       Rebuild Reason                   
==========================================================================================
rtwdemo_optimizeblockorder  Code generated and compiled  Generated code was out of date.  

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

Просмотрите сгенерированный код с оптимизацией.

/* Output and update for atomic system: '<Root>/RegionScheduling' */
static void RegionScheduling(const real_T rtu_In1[6], const real_T rtu_In2[6],
  real_T rty_Out1[6], rtDW_RegionScheduling *localDW)
{
  int32_T i;
  for (i = 0; i < 6; i++) {
    /* UnitDelay: '<S3>/UnitDelay2' */
    rty_Out1[i] = localDW->UnitDelay2_DSTATE[i];

    /* Sum: '<S3>/Sum' incorporates:
     *  UnitDelay: '<S3>/Delay'
     *  UnitDelay: '<S3>/UnitDelay'
     *  UnitDelay: '<S3>/UnitDelay2'
     */
    localDW->UnitDelay2_DSTATE[i] = localDW->Delay_DSTATE[i] +
      localDW->UnitDelay_DSTATE[i];

    /* Bias: '<S3>/Bias' incorporates:
     *  UnitDelay: '<S3>/Delay'
     */
    localDW->Delay_DSTATE[i] = rtu_In1[i] + 3.0;

    /* Gain: '<S3>/Gain' incorporates:
     *  UnitDelay: '<S3>/UnitDelay'
     */
    localDW->UnitDelay_DSTATE[i] = 2.0 * rtu_In2[i];
  }
}

В оптимизированном коде блоки в областях 3, 2 и 1 выполняются в этом порядке. С этим порядком выполнения сгенерированный код не содержит временную переменную rtb_Sum и соответствующую копию данных.

Устранение копий данных для блоков, которые выполняют операции Inplace

Подсистема InplaceScheduling показывает, как генератор кода переупорядочивает операции блока, чтобы исключить копии данных для блоков, которые выполняют операции inplace. В Параметры конфигурации окне установите Порядок блока Оптимизации в параметре сгенерированного кода равным Off и создайте модель.

### Starting build procedure for: rtwdemo_optimizeblockorder
### Successful completion of build procedure for: rtwdemo_optimizeblockorder

Build Summary

Top model targets built:

Model                       Action                       Rebuild Reason                   
==========================================================================================
rtwdemo_optimizeblockorder  Code generated and compiled  Generated code was out of date.  

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

Просмотрите сгенерированный код без оптимизации. Код для InplaceScheduling подсистема:

/* Output and update for atomic system: '<Root>/InplaceScheduling' */
static void InplaceScheduling(void)
{
  real_T rtb_Max[6];
  real_T acc;
  int32_T idx1;
  int32_T idx2;
  int32_T k;
  for (idx1 = 0; idx1 < 6; idx1++) {
    /* Sum: '<S1>/Sum2x3' incorporates:
     *  Inport: '<Root>/In7'
     *  UnitDelay: '<S1>/Unit Delay'
     */
    rtDWork.UnitDelay_DSTATE[idx1] += rtU.In7[idx1];

    /* MinMax: '<S1>/Max' */
    acc = rtDWork.UnitDelay_DSTATE[idx1];
    if (2.0 > acc) {
      rtb_Max[idx1] = 2.0;
    } else {
      rtb_Max[idx1] = acc;
    }

    /* End of MinMax: '<S1>/Max' */
  }

  /* S-Function (sdsp2norm2): '<S1>/Normalization' incorporates:
   *  Outport: '<Root>/Out7'
   */
  idx1 = 0;
  idx2 = 0;
  acc = 0.0;
  for (k = 0; k < 6; k++) {
    acc += rtb_Max[idx1] * rtb_Max[idx1];
    idx1++;
  }

  acc = 1.0 / (sqrt(acc) + 1.0E-10);
  for (k = 0; k < 6; k++) {
    rtY.Out7[idx2] = rtb_Max[idx2] * acc;
    idx2++;

    /* Outport: '<Root>/Out6' incorporates:
     *  Bias: '<S1>/Bias'
     *  Inport: '<Root>/In8'
     *  Outport: '<Root>/Out7'
     *  Product: '<S1>/Product'
     */
    rtY.Out6[k] = (rtU.In8 + 1.0) * rtDWork.UnitDelay_DSTATE[k];

    /* Switch: '<S1>/Switch' incorporates:
     *  Inport: '<Root>/In9'
     */
    if (rtU.In9[k] > 0.0) {
      /* Update for UnitDelay: '<S1>/Unit Delay' */
      rtDWork.UnitDelay_DSTATE[k] = 0.0;
    } else {
      /* Update for UnitDelay: '<S1>/Unit Delay' */
      rtDWork.UnitDelay_DSTATE[k] = rtb_Max[k];
    }

    /* End of Switch: '<S1>/Switch' */
  }

  /* End of S-Function (sdsp2norm2): '<S1>/Normalization' */
}

С порядком выполнения по умолчанию блок Max выполняется перед блоком Product. Чтобы сохранить выход блока Sum, сгенерированный код содержит две переменные, UnitDelay_DSTATE и rtb_Max.

Сгенерируйте код с оптимизацией. Установите порядок блоков Optimize в сгенерированном параметре сгенерированного кода равным Improved Execution Speed и создайте модель.

### Starting build procedure for: rtwdemo_optimizeblockorder
### Successful completion of build procedure for: rtwdemo_optimizeblockorder

Build Summary

Top model targets built:

Model                       Action                       Rebuild Reason                   
==========================================================================================
rtwdemo_optimizeblockorder  Code generated and compiled  Generated code was out of date.  

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

Просмотрите сгенерированный код с оптимизацией.

/* Output and update for atomic system: '<Root>/InplaceScheduling' */
static void InplaceScheduling(void)
{
  real_T acc;
  int32_T idx1;
  int32_T idx2;
  int32_T k;
  for (idx1 = 0; idx1 < 6; idx1++) {
    /* Sum: '<S1>/Sum2x3' incorporates:
     *  Inport: '<Root>/In7'
     *  UnitDelay: '<S1>/Unit Delay'
     */
    rtDWork.UnitDelay_DSTATE[idx1] += rtU.In7[idx1];

    /* Outport: '<Root>/Out6' incorporates:
     *  Bias: '<S1>/Bias'
     *  Inport: '<Root>/In8'
     *  Product: '<S1>/Product'
     */
    rtY.Out6[idx1] = (rtU.In8 + 1.0) * rtDWork.UnitDelay_DSTATE[idx1];

    /* MinMax: '<S1>/Max' */
    acc = rtDWork.UnitDelay_DSTATE[idx1];
    if (2.0 > acc) {
      rtDWork.UnitDelay_DSTATE[idx1] = 2.0;
    } else {
      rtDWork.UnitDelay_DSTATE[idx1] = acc;
    }

    /* End of MinMax: '<S1>/Max' */
  }

  /* S-Function (sdsp2norm2): '<S1>/Normalization' incorporates:
   *  Outport: '<Root>/Out7'
   */
  idx1 = 0;
  idx2 = 0;
  acc = 0.0;
  for (k = 0; k < 6; k++) {
    acc += rtDWork.UnitDelay_DSTATE[idx1] * rtDWork.UnitDelay_DSTATE[idx1];
    idx1++;
  }

  acc = 1.0 / (sqrt(acc) + 1.0E-10);
  for (k = 0; k < 6; k++) {
    rtY.Out7[idx2] = rtDWork.UnitDelay_DSTATE[idx2] * acc;
    idx2++;
  }

  /* End of S-Function (sdsp2norm2): '<S1>/Normalization' */

  /* Update for UnitDelay: '<S1>/Unit Delay' */
  for (idx1 = 0; idx1 < 6; idx1++) {
    /* Switch: '<S1>/Switch' incorporates:
     *  Inport: '<Root>/In9'
     */
    if (rtU.In9[idx1] > 0.0) {
      rtDWork.UnitDelay_DSTATE[idx1] = 0.0;
    }

    /* End of Switch: '<S1>/Switch' */
  }

  /* End of Update for UnitDelay: '<S1>/Unit Delay' */
}

Оптимизированный код не содержит переменную rtb_Max или копий. Данные содержат одну переменную, UnitDelay_DSTATE, для удержания вывода блока Sum. Блок Product читается с UnitDelay_DSTATE и блок Max читает и записывает в UnitDelay_DSTATE.

Чтобы реализовать повторное использование буфера, генератор кода не нарушает заданные пользователем приоритеты блоков.

См. также

Похожие темы