Tasking 编译器对 TC3xx 代码执行效率的影响,核心不在于“开不开优化”,而在于 --tradeoff 参数和 -O 级别配合后,编译器在指令选择、循环重写、函数内联上的取舍方向。默认的 -O2 并不以速度最大化为目标,真正影响实时性的选项需要单独调整。
优化级别:-O3 才以速度为优先
Tasking 提供 -O0 到 -O3 四个级别,默认是 -O2。-O2 的名称是“Optimize more”,目标是同时减少代码体积和执行时间,并不是纯粹的速度导向。-O3 才是“Optimize most”,官方说明明确建议在程序或硬件无法满足实时性要求时使用 -O3。如果工程默认停留在 -O2,而代码中存在对时序敏感的循环或中断服务程序,执行效率可能并未达到编译器能给出的上限。切换到 -O3 是最直接的速度提升手段,代价是代码体积可能增大。
--tradeoff:速度与体积的权重调节
--tradeoff(或 -t)不开关任何优化阶段,而是给各个优化阶段的启发式决策提供一个权重系数,范围从 0(纯速度)到 4(纯体积)。这个参数直接影响两个关键行为:
指令选择:-t0 到 -t2 时编译器选择周期数最少的指令;-t3 和 -t4 时选择字节数最少的指令。对于 TC3xx 这种带流水线和多发射能力的架构,一条多字节但单周期的指令可能比多条短指令更快,-t0 允许编译器利用这一点。
循环重写:-t0 不将 top-loop 重写为 bottom-loop,而 -t1 及以上会执行这个转换,以减少每次迭代的分支开销。但 -t3 和 -t4 虽然做同样的转换,后续的循环优化方向却是偏向体积而非速度。
Tasking 官方建议:默认按体积优化,只对速度关键的区域单独用 -t0、-t1 或 -t2,不建议在整个应用层面全局使用这几个偏向速度的 tradeoff 值。这意味着更有效的做法是配合 #pragma optimize 或分段编译,而不是一刀切地全局提速。
函数内联:速度收益与代码膨胀的平衡
自动内联在 -O3 的预定义集合中启用,但 --tradeoff 会通过 --inline-max-incr 和 --inline-max-size 间接控制内联的激进程度。默认值随 tradeoff 变化:-t2 时允许代码体积增长 20%,内联阈值 20;-t0 时允许增长 100%,阈值放宽到 50。如果手动指定这两个参数,可以覆盖默认行为,在特定模块中强制更激进的内联。对于频繁调用的小函数(如寄存器读写封装、状态判断),内联消除调用开销和栈操作,对执行效率的提升比较明显。
容易被忽略的 volatile 与循环对齐
--language=+volatile(默认行为)会把对 volatile 对象的访问当作内存屏障,阻止编译器将其他内存操作移到该访问之前或之后。这在驱动代码中保证了寄存器操作的顺序正确,但也限制了调度器的重排空间。如果确认某段代码不需要这种严格顺序(例如纯计算循环),局部关闭该行为可以给编译器更多调度余地,但需要谨慎评估对硬件寄存器访问的影响。
--loop=+cache 和循环对齐选项用于改善取指效率。默认对齐值为 32 字节,与 TC3xx 的取指线宽度匹配。对于位于 cached memory 或 SPRAM 中的热点循环,对齐后的循环体取指次数减少,在流水线密集执行时能降低取指停顿。这个优化只在 tradeoff 小于 3(即偏速度)时生效,因为对齐会占用额外的代码空间。
实践上的取舍
单纯把全局选项改成 -O3 -t0 不一定是最优解,代码体积膨胀可能带来取指 cache 压力,反而抵消部分收益。更可控的做法是:保持工程默认的 -O2 或 -O3 配合适中的 tradeoff,然后通过 TASKING Embedded Profiler 定位实际耗时最多的函数或循环,对这些特定区域用 #pragma optimize 单独调整。TC3xx 的内存访问布局对性能的影响同样显著,同一段代码放在本地 DSPR 和远程 LMU 上的执行效率差异可能达到数倍,优化选项的调整需要和 .lsl 链接脚本中的段分配策略一起考虑,而不是孤立地调编译器参数。 |
|