打印
[应用相关]

DSP程序结构优化技巧

[复制链接]
770|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
handleMessage|  楼主 | 2019-10-19 12:58 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
DSP的内部结构具有特殊性,如果程序的编写能够在一定程度上与DSP的结构相适应,利用C编译器的优化功能就可以在程序级的基础上大大提高算法的性能[1~5]。具体如下:

       (1) 尽量使用int 类型中间变量

       在图像处理程序中,数据通常为8bit的变量,而C6XDSP的内部寄存器和数据通道为32bit,在图像处理的滤波、卷积等过程中,需要较多的中间变量,如果采用8bit的中间变量存储方式,势必迫使编译器使用额外的数据调整指令,因此采用32bit的中间变量具有最好的效率。

(2) 使用移位代替除法运算

       ①DSP中的移位运算具有硬件支持,由一条指令完成,而除法运算使用程序实现,比较复杂耗时。

       ②DSP的浮点运算往往采用调用子函数方法,效率低,编译器无法进行软件流水优化,而采用移位运算可以代替一些定值的浮点运算,如:
for(I=0;I<1000;I++)          for(I=0;I<1000;I++)
{                                       {
     b+=35*0.325;                  b+=((35*333)>>10);
}                                        }

       以上两条程序完成同样的功能,但是第一条含有浮点数的乘法,运行时间为222 775;第二条只有定点数的乘法和移位运算,运行时间仅为881,可见效率差距非常大。
(3) 使用C6x内联函数

       C6x编译器内部提供了许多指令,可以在单周期内完成许多复杂的函数功能,从而提高了代码的运行速度。如:
“饱和加法”:
int sadd(int a, int b)
{
    int result;
    result = a + b;
    if (((a ^ b) & 0x80000000) == 0)
    {
        if ((result ^ a) & 0x80000000)
        {
            result = (a < 0) ? 0x80000000 : 0x7fffffff;
        }
    }
    return (result);
}

       这样一个复杂的算法可以用一条内联函数_sadd( a,b)实现。

(4) 使用32bit数据类型访问16bit数据

       由于C6x系列DSP具有32位的寄存器和内部通道,在操作16bit的数据如short类型时,往往浪费一半的寄存器空间和通道带宽。为了充分利用这些资源,编译器设置了一些内联函数同时对两个16bit的数据进行操作,如_add2、_sub2。
short in1[]、 short in2[] 是两个short类型的数组,具有N项,以下是将两者对应项相加的操作。
for (i = 0; i < (N/2); i++)
_amem4(&sum[i]) = add2(_amem4_const(&in1[i]), _amem4_const(&in2[i]));
程序中,_amem4_const、_amem4将in1、in2和sum进行了32bit的对齐操作,然后同时进行两个short数据的加法运算和读取存储运算,从而提高了运算效率。
(5) 使用restrict关键字消除内存关联

       为提高代码效率,C6x编译器总是尽可能多地安排指令并行,而指令能否并行取决于指令之间的相关性。对于编译器而言,内存读写指令之间是否独立是很难判断的,如下列程序:
void vecsum(short *sum, short *in1, short *in2, unsigned int N)
{
    int i;
    for (i = 0; i < N; i++)
    sum[i] = in1[i] + in2[i];
}

       程序中,sum的存储对于in1、in2的读取地址产生影响,只有等到sum存储完毕以后,才可以再次进行in1、in2的读取操作。这个问题叫做“别名问题”,因为sum可能和in1是一个地址,使其无法将读取数据和写结果的操作并行起来。
为了让编译器放心地将读取源数据和写结果数据两者并行操作,可以利用restrict变量申明当前数组名(或指针)是指向这段内存的惟一变量,如下列程序所示:
void vecsum(short *sum, short * restrict  in1, short * restrict in2, unsigned int N)
{
    int i;
    for (i = 0; i < N; i++)
    sum[i] = in1[i] + in2[i];
}
这样就可以消除以上的内存相关性,提高流水线效率。

使用特权

评论回复
沙发
bbapple| | 2019-10-19 12:58 | 只看该作者
这样运行效率能有明显的提升?

使用特权

评论回复
板凳
bbapple| | 2019-10-19 12:59 | 只看该作者
不影响执行速度的情况下,可以使用c或c/c++语言提供的函数库,也可以自己设计函数,这样更易于使用“裁缝师”优化处理。。

使用特权

评论回复
地板
zhouhuanの| | 2019-10-19 13:02 | 只看该作者
通过编译器选项设置-o2及以上

使用特权

评论回复
5
wanglaojii| | 2019-10-19 13:03 | 只看该作者
DSP程序生成的可执行文件按段的方式进行存储,不同的段存储于不同的区域,而这会在影响内核访存的基础上进一步影响程序执行的效率  。。

使用特权

评论回复
6
laozhongyi| | 2019-10-19 13:06 | 只看该作者
可通过配置DSP/BIOS实现的。  

使用特权

评论回复
7
Edisons| | 2019-10-19 13:06 | 只看该作者
使用这些库,能够明显提高DSP的运算效率。  

使用特权

评论回复
8
_gege| | 2019-10-19 13:10 | 只看该作者
对于DSPc6000系列,可以采用IQmath库函数  。。

使用特权

评论回复
9
Mozarts| | 2019-10-19 13:11 | 只看该作者
DSP算法关键在于移植和优化 。。

使用特权

评论回复
10
Listate| | 2019-10-19 13:14 | 只看该作者
选择C还是选择ASM进行DSP编程  。。。

使用特权

评论回复
11
xia00| | 2019-10-19 13:15 | 只看该作者
需要对程序编译工具进行合理配置 。

使用特权

评论回复
12
hfdy01| | 2019-10-19 13:18 | 只看该作者
楼主最好给一些程序设计方面的资料。

使用特权

评论回复
13
CallReceiver| | 2019-10-19 13:18 | 只看该作者
预处理指令#pragma MUST_ITERATE()的使用,将大量的一种循环以及内循环为常数次的二重循环展开。

使用特权

评论回复
14
boy1990| | 2019-10-19 13:22 | 只看该作者
可以将浮点运算转换为定点运算计算。

使用特权

评论回复
15
sourceInsight| | 2019-10-19 13:22 | 只看该作者
可以优化设置各个段的存放位置,提升程序执行效率  

使用特权

评论回复
16
feiqi1| | 2019-10-19 13:26 | 只看该作者
代码指令的并行是软件自动优化得到的。。。

使用特权

评论回复
17
androidbus| | 2019-10-19 13:26 | 只看该作者
需要注意的是在使用IQmath库时需要对使用IQ数据类型的精度和支持数据范围进行权衡,从而获得较好的效果。  

使用特权

评论回复
18
litengg| | 2019-10-19 13:30 | 只看该作者
有些烧写程序指定.test代码长度,升级后的代码长度可能超出烧写指定范围。

使用特权

评论回复
19
wowu| | 2019-11-15 12:07 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
20
wakayi| | 2019-11-15 12:11 | 只看该作者
非常不错的资料

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

166

主题

1689

帖子

4

粉丝