通过重新排序生成代码中的块操作来提高执行效率
为了提高执行效率,代码生成器可以改变块的执行顺序。在“配置参数”对话框中设置优化大宗订单参数提高执行速度
,代码生成器可以改变块操作的顺序来实现这些优化:
消除执行就地操作(即使用相同的输入和输出变量)的块的数据副本,并包含包含不必要数据副本的算法代码。
把更多的
为
通过一起执行具有相同大小的块来循环。通过在上游块之前执行单元延迟块,重用单元延迟块的输入、输出和状态的相同变量。
这些优化提高了执行速度,节约了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
.
要实现缓冲区重用,代码生成器不会违反用户指定的块优先级。