文档

通过重新排序生成代码中的块操作来提高执行效率

为了提高执行效率,代码生成器可以改变块的执行顺序。在“配置参数”对话框中设置优化大宗订单参数提高执行速度,代码生成器可以改变块操作的顺序来实现这些优化:

  • 消除执行就地操作(即使用相同的输入和输出变量)的块的数据副本,并包含包含不必要数据副本的算法代码。

  • 把更多的通过一起执行具有相同大小的块来循环。

  • 通过在上游块之前执行单元延迟块,重用单元延迟块的输入、输出和状态的相同变量。

这些优化提高了执行速度,节约了RAM和ROM的消耗。

示例模型

打开模型matlab: rtwdemo_optimizeblockorder.该模型包含三个子系统,用于演示重新排序块操作如何提高执行效率。

循环融合

子系统LoopFusionScheduling演示代码生成器如何对块操作进行重新排序,以便具有相同输出大小的块一起执行。这种重新排序使循环融合。设置优化生成代码中的块顺序参数

在系统的临时文件夹中,为构建和检查过程创建一个文件夹,并构建模型。

已成功完成模型的构建过程:rtwdemo_optimizeblockorder

查看未进行优化的生成代码。的代码LoopFusionScheduling子系统:

/*输出和更新原子系统:'/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;/ *偏见:“< S2 > /偏见”包含:*获得:“< S2 > /增益”* / (i = 0;I < 6;i++) {rty_Out1[i] = -0.3 * rtu_In1[i] + 0.5;} / *的偏见:“< S2 > /偏见”* / / *产品:“< S2 > /产品”* / (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: '/Product' */ /* Bias: '/Bias1' incorporates: * Gain: '/Gain1' */ for (i = 0; i < 6; i++) { rty_Out3[i] = -0.3 * rtu_In3[i] + 0.5; } /* End of Bias: '/Bias1' */ /* Product: '/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: '/Product1' */ }

在默认的执行顺序下,块从左到右、从上到下执行。因此,有了分离增益和偏差块和乘积块的两个组合的循环。

生成带有优化的代码。设置优化生成代码中的块顺序参数提高执行速度然后建立模型。

已成功完成模型的构建过程:rtwdemo_optimizeblockorder

查看优化后生成的代码。

/*输出和更新原子系统:'/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: '/Product'合并:* Product: '/Product1' */ tmp = i_0+ 3 * i;rty_Out2[tmp] = 0.0; /* Product: '/Product1' */ rty_Out4[tmp] = 0.0; /* Product: '/Product' incorporates: * Product: '/Product1' */ tmp_0 = i << 1; rty_Out2[tmp] += rtu_In2[tmp_0] * rtu_In1[i_0]; /* Product: '/Product1' */ rty_Out4[tmp] += rtu_In4[tmp_0] * rtu_In3[i_0]; /* Product: '/Product' incorporates: * Product: '/Product1' */ tmp_0++; rty_Out2[tmp] += rtu_In2[tmp_0] * rtu_In1[i_0 + 3]; /* Product: '/Product1' */ rty_Out4[tmp] += rtu_In4[tmp_0] * rtu_In3[i_0 + 3]; } } for (i = 0; i < 6; i++) { /* Bias: '/Bias' incorporates: * Gain: '/Gain' */ rty_Out1[i] = -0.3 * rtu_In1[i] + 0.5; /* Bias: '/Bias1' incorporates: * Gain: '/Gain1' */ rty_Out3[i] = -0.3 * rtu_In3[i] + 0.5; } }

在优化的代码中,具有相同输出大小的块一起执行。两组增益和偏置块的输出尺寸大小为6,所以它们一起执行。Product块的输出尺寸大小为9,所以它们一起执行。融合循环使代码生成器能够设置表达式的值3 * I + i_0等于临时变量tmp_0.此优化还可以提高执行效率。

单元延迟块的输入、输出和状态的缓冲区重用

子系统RegionScheduling演示了代码生成器如何对块操作进行重新排序,以便为单元延迟块的输入、输出和状态启用缓冲区重用。当计算是仅通过Delay块连接的独立区域的一部分时,代码生成器可以更改块执行顺序,以便下游区域先于上游区域执行。这个执行顺序允许最大限度地重用Delay块状态和输入输出变量。设置优化生成代码中的块顺序参数然后建立模型。

已成功完成模型的构建过程:rtwdemo_optimizeblockorder

查看未进行优化的生成代码。的代码RegionScheduling子系统:

/*原子系统的输出和更新:'/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: '/Sum'合并:* UnitDelay: '/Delay' * UnitDelay: '/UnitDelay' */ rtb_Sum = localDW->Delay_DSTATE[i] + localDW->UnitDelay_DSTATE[i];/* UnitDelay: '/UnitDelay2' */ rty_Out1[i] = localDW->UnitDelay2_DSTATE[i];/*更新UnitDelay: '/Delay'合并:* Bias: '/Bias' */ localDW->Delay_DSTATE[i] = rtu_In1[i] + 3.0;/*更新UnitDelay: '/UnitDelay'合并:*增益:'/增益' */ localDW->UnitDelay_DSTATE[i] = 2.0 * rtu_In2[i];/*更新UnitDelay: '/UnitDelay2' */ localDW->UnitDelay2_DSTATE[i] = rtb_Sum;}}

使用默认的执行顺序,生成的代码包含额外的临时变量rtb_Sum还有一份数据副本。

生成带有优化的代码。设置优化生成代码中的块顺序参数提高执行速度然后建立模型。

已成功完成模型的构建过程:rtwdemo_optimizeblockorder

查看优化后生成的代码。

/*原子系统的输出和更新:'/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: '/UnitDelay2' */ rty_Out1[i] = localDW->UnitDelay2_DSTATE[i];/* Sum: '/Sum'合并:* UnitDelay: '/Delay' * UnitDelay: '/UnitDelay' * UnitDelay: '/UnitDelay2' */ localDW->UnitDelay2_DSTATE[i] = localDW->Delay_DSTATE[i] + localDW->UnitDelay_DSTATE[i];/* Bias: '/Bias'合并:* UnitDelay: '/Delay' */ localDW->Delay_DSTATE[i] = rtu_In1[i] + 3.0;/*增益:'/增益'合并:* UnitDelay: '/UnitDelay' */ localDW->UnitDelay_DSTATE[i] = 2.0 * rtu_In2[i];}}

在优化的代码中,区域3、2和1中的块按此顺序执行。使用该执行顺序,生成的代码不包含临时变量rtb_Sum和相应的数据副本。

消除执行Inplace操作的块的数据副本

子系统InplaceScheduling演示代码生成器如何对块操作进行重新排序,以消除执行就地操作的块的数据副本。在“配置参数”对话框中设置优化生成代码中的块顺序参数然后建立模型。

已成功完成模型的构建过程:rtwdemo_optimizeblockorder

查看未进行优化的生成代码。的代码InplaceScheduling子系统:

/*原子系统的输出和更新:'/ inplacesscheduling ' */ static void inplacesscheduling (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: '/Sum2x3'合并:* Inport: '<根>/In7' * UnitDelay: '/单元延迟' */ rtDWork。UnitDelay_DSTATE[idx1] += rtU.In7[idx1];/* MinMax: '/Max' */ if (2.0 > rtDWork.UnitDelay_DSTATE[idx1]) {rtb_Max[idx1] = 2.0;} else {rtb_Max[idx1] = rtDWork.UnitDelay_DSTATE[idx1]; } /* End of MinMax: '/Max' */ } /* S-Function (sdsp2norm2): '/Normalization' incorporates: * Outport: '/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: '/Out6' incorporates: * Bias: '/Bias' * Inport: '/In8' * Outport: '/Out7' * Product: '/Product' */ rtY.Out6[k] = (rtU.In8 + 1.0) * rtDWork.UnitDelay_DSTATE[k]; /* Switch: '/Switch' incorporates: * Inport: '/In9' * UnitDelay: '/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: '/Switch' */ } /* End of S-Function (sdsp2norm2): '/Normalization' */ }

在默认的执行顺序下,Max块在Product块之前执行。为了保存Sum块输出,生成的代码包含两个变量,UnitDelay_DSTATE而且rtb_Max

生成带有优化的代码。设置优化生成代码中的块顺序参数提高执行速度然后建立模型。

已成功完成模型的构建过程:rtwdemo_optimizeblockorder

查看优化后生成的代码。

/*原子系统的输出和更新:'<根>/ inplacesscheduling ' */ static void inplacesscheduling (void) {real_T rtb_Max[6];int32_T idx2;real_T acc;int32_T k;int32_T我;For (i = 0;I < 6;i++) {/* Sum: '/Sum2x3'合并:* import: '<根>/In7' * UnitDelay: '/单元延迟' */ acc = rtU。In7[i] + rtDWork.UnitDelay_DSTATE[i];/*输出端口:'<根>/Out6'包含:* Bias: '<根>/In8' * import: '<根>/In8' * Product: '<根>/Product' */ rtY。Out6[i] = (rtU。In8 + 1.0) * c; /* MinMax: '/Max' */ if (2.0 > acc) { acc = 2.0; } /* End of MinMax: '/Max' */ /* Switch: '/Switch' incorporates: * Inport: '/In9' * UnitDelay: '/Unit Delay' */ if (rtU.In9[i] > 0.0) { rtDWork.UnitDelay_DSTATE[i] = 0.0; } else { rtDWork.UnitDelay_DSTATE[i] = acc; } /* End of Switch: '/Switch' */ /* Sum: '/Sum2x3' */ rtb_Max[i] = acc; } /* S-Function (sdsp2norm2): '/Normalization' incorporates: * Outport: '/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): '/Normalization' */ }

优化后的代码不包含该变量rtb_Max或者数据副本。生成的代码包含一个变量,UnitDelay_DSTATE,用于保存Sum块输出。Product块从UnitDelay_DSTATE和Max块读取和写入UnitDelay_DSTATE

要实现缓冲区重用,代码生成器不会违反用户指定的块优先级。

另请参阅

相关的话题