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

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

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

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

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

Эта оптимизация улучшает скорость выполнения и сохраняет потребление ROM и RAM.

Модель в качестве примера

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

for Fusion цикла

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

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

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

Просмотрите сгенерированный код без оптимизации. Код для 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 циклы для двух комбинаций Усиления и Смещения блокируются и блоки продукта.

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

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

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

/* 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' incorporates:
       *  Product: '<S2>/Product1'
       */
      tmp_0++;
      rty_Out2[tmp] += rtu_In2[tmp_0] * rtu_In1[i_0 + 3];

      /* Product: '<S2>/Product1' */
      rty_Out4[tmp] += rtu_In4[tmp_0] * 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;
  }
}

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

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

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

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

Просмотрите сгенерированный код без оптимизации. Код для 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)
{
  int32_T i;
  real_T rtb_Sum;
  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

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

/* 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 и соответствующая копия данных.

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

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

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

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

/* Output and update for atomic system: '<Root>/InplaceScheduling' */
static void InplaceScheduling(void)
{
  int32_T idx1;
  int32_T idx2;
  real_T acc;
  int32_T k;
  real_T rtb_Max[6];
  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' */
    if (2.0 > rtDWork.UnitDelay_DSTATE[idx1]) {
      rtb_Max[idx1] = 2.0;
    } else {
      rtb_Max[idx1] = rtDWork.UnitDelay_DSTATE[idx1];
    }

    /* 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'
     *  UnitDelay: '<S1>/Unit Delay'
     */
    if (rtU.In9[k] > 0.0) {
      rtDWork.UnitDelay_DSTATE[k] = 0.0;
    } else {
      rtDWork.UnitDelay_DSTATE[k] = rtb_Max[k];
    }

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

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

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

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

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

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

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

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

    /* MinMax: '<S1>/Max' */
    if (2.0 > acc) {
      acc = 2.0;
    }

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

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

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

    /* Sum: '<S1>/Sum2x3' */
    rtb_Max[i] = acc;
  }

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

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

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

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

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

Смотрите также

Похожие темы