软件流水循环

1. C6000流水线(Pipeline)

一个指令的处理过程并不是一步完成,它被分为三个阶段:取指(Fetch)、译码(Decode)、执行(Excute)。将每一个阶段放入独立的流程车间处理,形成流水线式的处理过程,可以大大加快指令的处理速度。

如图1所示,流水编排后的3个指令只需5个cycle,相比顺序执行的9个cycle大大减少,当指令数增多,流水线的优势将更加明显。

图1 简单的流水线编排示意

实际上,C6000架构把每一个阶段进一步划分为多个子阶段,每个子阶段消耗1个CPU cycle。

取指(4个子阶段):

  • PG: Program address generate (update program counter register)

  • PS: Program address send (to memory)

  • PW: Program (memory) access ready wait

  • PR: Program fetch packet receive (fetch packet = eight 32-bit instructions)

译码(2个子阶段):

  • DP: Instruction dispatch (or assign, to the functional units)

  • DC: Instruction decode

执行(1-10个子阶段,指令间有区别):

  • E1 – E10, where E1 is the first sub stage in the execute stage

图2 高性能的C6000流水线

2. 流水线阻塞

下列两种情况出现时,流水线将被阻塞:

  • 当前为load、complex multiply等具有多个延时时隙(delay slot)的指令时,下一指令需多个cycle,等其返回结果后才能往下继续执行

  • 跳转指令出现时,CPU无法预知下一步执行哪个分支指令,因此跳转目标指令需等到跳转指令执行到E1阶段才能进入流水线

为了充分利用流水线的资源,避免delay slots造成的阻塞,C6000架构在软件和硬件上分别新增了一个处理机制:

  • 软件上:提供软件流水(software pipelining)指令编排

  • 硬件上:提供SPLOOP buffer(software pipelining loop buffer)

3. 软件流水

软件流水≠流水线!

软件流水技术指编译器通过重新调整指令的位置,使得原本将发生阻塞的流水线得以充分利用,其重点在“软件”两字。

例如处理下面循环:

for(i=0; i<15; i++)

{

sum += tab[i];

}

传统指令流程(Solution1)和软件流水编排后的指令流程(Solution2)如图3所示:

图3 传统编排 Vs 软件流水编排

从图中看到,经过软件重新编排过的指令将不再发生流水线阻塞,提升运行效率的同时也不影响代码功能的实现。

解释下有关软件流水的三个名词:

  • 流水核(Kernel):流水线被充分利用的一段代码

  • 流水填充(Prolog):流水核之前的一段填充过程代码

  • 流水排空(Epilog):流水核之后的一段排空过程代码


4. SPLOOP Buffer

软件流水将会带来两个主要的缺点:汇编文件代码尺寸的增加并影响代码的中断属性。

SPLOOP Buffer的出现就是为了就解决以上问题。SPLOOP Buffer是C6000内部的一个存储区域,用来装载SPLOOP指令。当一个SPLOOP 第一次被执行时,循环的相关指令被拷贝到SPLOOP Buffer中,整个循环运行过程将从这里取指执行,直到循环结束。

C6000还为SPLOOP Buffer的使用提供了专门的寄存器和操作指令,如果编程者使用汇编/线性汇编编程,需要熟悉这些指令和寄存器,并了解SPLOOP Buffer特有的执行机制(参考文献[1]),如果使用C/C++编程则由编译器自动生成相应指令。

以存储块拷贝函数为例,示意使用SPLOOP Buffer前后的编码效果:

图4 memery copy 使用SPLOOP buffer前

图5 memery copy 使用SPLOOP buffer后

*注意:SPLOOP Buffer最多只能存放14个执行包(每个执行包可含8条指令,顺序/并行),因此如果循环体较复杂将不能使用SPLOOP Buffer。

5. 导致软件流水编排失败的因素

在CCS开发环境中,开启-O2/-O3优化选项,编译器将自动为合适的代码进行软件流水编排,因此编程者需要注意的是使设计的循环体符合软件流水编排的条件。

下列一些因素将可能引起软件流水编排失败:

  • 汇编语句嵌入到C/C++代码中

  • 出现复杂的流控制语句如goto、break等

  • 循环中包含一个调用(内嵌函数除外)

  • 需进行软件流水编排的指令太多

  • 没有初始化循环计数器

  • 循环变量在循环过程中被修改

  • 软件流水被关闭:没有使用-O2或-O3选项;使用了-ms2或-ms3选项;使用-mu关闭了软件流水

理解编译器反馈信息

1. 编译器优化循环的几个步骤

循环的运算性能主要取决于编译器能否编排出恰当的软件流水,编译器优化一个循环的过程大致分为三个步骤:

获取循环次数信息。这些信息能帮助编译器判断是否要对循环做自动展开等操作。有时编译器无法从代码中获得完整的这些信息,编译器将会对循环采取保守的优化策略。因此,若要获得最佳的优化性能,编程者应尽可能地提供这些信息给编译器,可通过 MUST_ITERATE 、UNROLL 等 pragma语句。

几个关键参数如下:

  • 最小可能循环次数(Minimum Trip Count)

  • 最大可能循环次数(Maximum Trip Count)

  • 循环倍数系数(Max Trip Count Factor)

收集循环资源和相关图信息。CPU完成一次循环迭代所需的cycle数称为迭代间隔(iteration interval,ii),编译器的优化目标就是最小化ii。

几个关键参数如下:

  • 循环执行相关限(Loop Carried Dependency Bound),指循环体中最大的一条依赖路径的距离,而所谓依赖是指当前指令的开始依赖于前面指令的结束。

以下面一段代码为例:

void simple_sum(short *sum, short *in1, unsigned int N)

{

int i;

for (i = 0; i < N; i++)

{

sum[i] = in1[i] + 1;

}

}

其中最大的依赖路径如下图所示,图中显示,下一次数据的加载需等待上一次数据存储完成。

图6 循环依赖路径

很多时候,循环执行相关限是由于编译器对某些指针变量的信息缺乏了解造成,当指针的确切值无法得知时,编译器必须假定任何两个指针都可能指向相同的位置。因此,从一个指针进行加载暗含了其与另一个指针执行存储操作的相关,反之亦然。类似这种相关通常是不必要的,编程者可通过添加“restrict”关键词来消除这种相关。

  • 未分配资源限(Unpartitioned Resource Bound):编译器将每条指令分配到A、B运算单元之前,使ii达到最小情况下的资源限。

  • 已分配资源限(Partitioned Resource Bound):编译器将每条指令分配到A、B运算单元之后,使ii达到最小情况下的资源限。

寻找软件流水编排策略。编译器首先将ii设为Loop Carried Dependency Bound和Partitioned Resource Bound两个指标中的大值,然后以它为目标寻找编排策略。如果失败,则将ii+1,继续寻找……期间编译器将会反馈出编排失败的原因和一些相关信息。

2. 编译反馈输出相关选项

编程者可以选择查看上述编译器反馈的一些编译信息,来了解代码的优化程度,进而相应调整代码结构。如果要获得反馈输出,需打开-k和-mw选项。

  • -k:保留编译输出的汇编文件

  • -mw:生成详细的软件流水报告

一个反馈信息的例子如下所示:

图7 编译器反馈信息示例

3. 依据反馈信息制定优化策略

Loop Carried Dependency Bound is Much Larger Than Unpartitioned Resource Bound

现象描述:循环执行相关限远大于未分配资源限。

分析:相关路径过长,可能存在潜在的存储器别名混淆问题。

解决方案:

  • 运用-pm程序及优化减少存储器指针别名

  • 对传入函数且没有存储重叠的指针参数加“restrict”

  • 运用-mt选项假定没有存储器别名问题

  • 使用.mdep和.no_mdep汇编优化指令

  • 如果循环控制复杂,尝试用-mh选项

Uneven Resources

现象描述:对某一运算单元的使用次数为奇数。

分析:如一次循环过程调用了3次乘法,那么分配到A、B两侧后,执行这个循环至少需要2个迭代间隔。如果能将该循环展开一倍,则循环一次需6次乘法,分配到A、B两侧后得到一个3周期的ii,从而改善循环性能。

解决方案:展开循环从而得到偶数个资源。

Larger Outer Loop Overhead in Nested Loop

现象描述:存在循环嵌套时,外循环所用时间占整个循环时间的比重很大。

分析:内循环计数值较小,而编译器将只重点优化内循环。

解决方案:展开内层循环,使嵌套结构变为一个大循环。

T Address Paths Are Resource Bound

现象描述:T地址通道数定义为每次循环迭代从地址总线发出的存储器访问次数,该资源的访问对循环进行有限制。

分析:应减少对T地址通道的访问次数。

解决方案:用宽字节存取指令访问存储器。

冗余循环

1. 什么是冗余循环?

为了填充流水线,软件流水循环结构需要循环迭代至少执行某个次数(循环次数要达到最小循环计数值)。当编译器无法确定循环计数时,默认会产生两个循环:一是不经流水编排的代码,二是循环流水编排的。运行时,若循环计数大于等于最小循环计数值,执行第2个循环,否则执行第1个。因此,总有一个循环不被执行,这个循环就是冗余循环。

冗余循环的出现将引起代码尺寸的增加。

2. 如何避免生成冗余循环

  • 设置-ms选项的任一级别都将关闭冗余循环的生成

  • 使用MUST_ITERATE pragma伪指令告诉编译器循环次数的具体信息

中断对循环的影响

1. 单分配和多分配

C6000中的寄存器分配被分为单分配和多分配。单分配代码是可中断的,多分配代码是不可中断的。

多分配是指某一特殊寄存器被分配多于一个值。如下为一段多分配的代码。

cycle

1    SUB .S1 A4,A5,A1 ; writes to A1 in single cycle

2    LDW .D1 *A0,A1 ; writes to A1 after 4 delay slots

3    NOP

4    ADD .L1 A1,A2,A3 ; uses old A1 (result of SUB)

5−6  NOP 2

7    MPY .M1 A1,A4,A5 ; uses new A1 (result of LDW)

在第4周期,ADD指令开始时,寄存器被分配两个不同值。一个值是SUB指令在第1周期所写,已经在寄存器中存在。第二个值叫做in-flight值,在第2周期由LDW指令分配。因为LDW指令在第6周期之前没有实际值写入寄存器A1,所以考虑分配为in-flight。

in-flight操作因其不可预见性所以其代码不可中断。

2. 循环不可被中断的情形

所有小于6个cycle的循环都是不可中断的。

即使代码使用单分配,但循环也可能不能使用中断。因为硬件中断保护所有分值操作的延迟间隙,所以只要CPU有悬挂分支,所有中断就保持悬挂。而又因为分支跳转指令有5个延迟时隙,小于6个cycle的循环总有悬挂分支。

3. 如何设置循环体的中断属性?

循环的中断属性可设置为三个级别:

级别0,不可中断

该级别下编译器不能使中断无效,因此需确保中断不会发生,其优势是允许编译器用多分配代码以及产生最小周期间隔的软件流水循环。

  • -mi选项将某一模块设置为该属性

  • 可用pragma伪指令对某个特殊函数func进行如下设置:

#pragma FUNC_INTERRUPT_THRESHOLD(func, uint_max);

级别1,任何时刻可中断

该级别编译器处处用单分配,绝不产生小于6个cycle的循环。

  • -mi1选项将某一模块设置为该属性

  • 可用pragma伪指令对某个特殊函数func进行如下设置:

#pragma FUNC_INTERRUPT_THRESHOLD(func, 1);

级别2,在阈值周期内不可中断

用户设置一个周期阈值threshold,若循环的cycle数未超过阈值,编译器将在循环周围关中断,并允许寄存器多分配。反之,则产生单分配的代码,循环可中断。如果编译器无法判断循环周期,则假定达到阈值,产生一个可中断循环。

  • -mi(阈值)选项将某一模块设置为该属性

  • 可用pragma伪指令对某个特殊函数func进行如下设置:

#pragma FUNC_INTERRUPT_THRESHOLD(func, threshold);

参考文献

【1】Introduction to TMS320C6000 DSP Optimization--SPRABF2,2011.

【2】TMS320C6000 Programmer's Guide--SPRU198K,2011.

【3】田黎育,何佩琨,朱梦宇. TMS320C6000系列DSP编程工具与指南[M].北京:清华大学出版社 2006.

·END·

想进一步跟踪本博客动态,欢迎关注我的个人微信订阅号:信号君

郑重·专业·有料

TI C6000 优化进阶:循环最重要!相关推荐

  1. 理解:TI C6000 数据存储处理与性能优化

    存储器之于CPU好比仓库之于车间.车间加工过程中的原材料.半成品.成品等均需入出仓库,生产效率再快,如果仓库周转不善,也必然造成生产阻塞.如同仓库需要合理地规划管理一般,数据存储也需要恰当的处理技巧来 ...

  2. GPU 编程入门到精通(五)之 GPU 程序优化进阶

    版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 博主由于工作当中的需要,开始学习 GPU 上面的编程,主要涉及到的是基于 GPU 的深度学习方面的知识,鉴于之前没有接触过 GP ...

  3. 优化汽车零部件循环取货路径的遗传算法模型

    优化汽车零部件循环取货路径的遗传算法模型 随着工业化程度的提高,汽车行业的发展也越来越快速.汽车零部件加工作为汽车行业中的重要环节,为汽车整体质量和性能提供了坚实的保障.而在汽车零部件加工过程中,循环 ...

  4. 性能优化——for循环

    性能优化之for循环 性能优化 问题 伪代码 思路 第一步:确定log日志信息 第二步:打印耗时 第三步:优化for循环 优化 代码优化1:线程池 代码优化2:阻塞主线程,直到所有子线程执行完毕 代码 ...

  5. cesium-Web网页优化进阶

    cesium-Web网页优化进阶 之前我们基于常见的cesium问题已经进行总结了,常见的问题可以基于这篇进行优化 cesium-Web页面优化总结 但是这篇总结的方法都是基于cesium的方法参数进 ...

  6. 打造网络营销利器-第2篇--友情链接交换-网站优化进阶

    网络营销如何做,才能从网络挖掘出大量的新业务?互联网时代你还停留于没业务就扩充销售队伍的思想,你就OUT了! 本系列文章将用通俗的语言介绍网站运营大牛们的惯用手法,网站SEO并没有你们想象那么难!重点 ...

  7. 开源啦!OMAP-L138/C6748 TI C6000 DSP/ARM 工业级核心板/口袋板/教学实验箱硬件设计开源

    源文件下载地址 PDF 格式原理图 https://github.com/wbdosx/OMAP-L138 可编辑 Cadence 16.6 格式原理图.PCB 以及 BOM 表 请发送标题为「获取 ...

  8. java for循环写法优化,Java优化for循环嵌套的高效率方法

    前几天有人问过我一个问题,就是两个嵌套for循环执行效率的问题,问有什么好的办法替换.当时我想了想,实在想不起来,哎,惭愧!!! 请教了答案,恍然大悟. 比如:两个list中分别装有相同的对象数据. ...

  9. java for嵌套循环_Java优化for循环嵌套的高效率方法

    前几天有人问过我一个问题,就是两个嵌套for循环执行效率的问题,问有什么好的办法替换.当时我想了想,实在想不起来,哎,惭愧!!! 请教了答案,恍然大悟. 比如:两个list中分别装有相同的对象数据. ...

最新文章

  1. linux什么命令只显示ip,linux ip命令
  2. having 与where 的异同点
  3. 【前端统计图】echarts实现属性修改
  4. 程序的跟踪debug
  5. 力扣(LeetCode)763
  6. you *might* want to use the less safe log_bin_trust_function_creators variable
  7. STL8-string容器
  8. 常见的爬虫分析库(1)-Python3中Urllib库基本使用
  9. python中的异或操作_Python中的异或和位操作的反转
  10. Ubuntu下解压缩文件
  11. 筛选数据库_网络药理学(2)| 使用TCMSP数据库检索中药成分并基于ADME参数进行成分筛选...
  12. Unity3D 插件大全
  13. 输出2—1000的所有同构数c语言详解
  14. 代码复杂度问题,coverity代码静态分析工具检查
  15. RADIUS服务器介绍
  16. 【修真院JAVA小课堂】redis缓存集群简单介绍
  17. 介绍计算机硬件的英语作文,电脑各部分英文介绍
  18. 一直空中三角测量计算失败
  19. 记事本改字体的代码java_求java记事本代码(带字体设置功能)?
  20. 施密特正交化(Schmidt)

热门文章

  1. python卸载pip_Python pip的安装及卸载
  2. 3d样式的button按钮
  3. csdn设置自己的博客代码和博客的背景颜色
  4. core-js介绍及安装使用
  5. 英语作文 计算机能否取代老师,雅思写作思路:电脑是否会取代老师
  6. 什么是账号关联(防止账号关联的方法有哪些)
  7. 持续集成:Jenkins pipeline全局变量
  8. EasyExcel基于2.2.6版本自定义合并单元格自定义样式下载多个sheet
  9. 泰坦尼克号生还情况数据分析
  10. MT6177 RF_datasheet资料介绍