打印

DSP程序优化

[复制链接]
1777|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dingy|  楼主 | 2012-10-10 19:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
dingy|  楼主 | 2012-10-10 19:39 | 只看该作者
我先分享一个使用并行代码

尽可能把长的有依赖的代码链分解成几个可以在流水线执行单元中并行执行的没有依赖的代码链。很多高级语言,包括 C++ ,并不对产生的浮点表达式重新排序,因为那是一个相当复杂的过程。需要注意的是,重排序的代码和原来的代码在代码上一致并不等价于计算结果一致,因为浮点操作缺乏精确度。在一些情况下,这些优化可能导致意料之外的结果。幸运的是,在大部分情况下,最后结果可能只有最不重要的位(即最低位)是错误的。

不好的代码:

double a[100] , sum ;

int i ;

sum = 0.0f ;

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

sum += a ;



推荐的代码:

double a[100] , sum1 , sum2 , sum3 , sum4 , sum ;

int i ;

sum1 = sum2 = sum3 = sum4 = 0.0 ;

for (i = 0 ; i < 100 ; i += 4)

{

   sum1 += a ;

   sum2 += a[i+1] ;

   sum3 += a[i+2] ;

   sum4 += a[i+3] ;

}

sum = (sum4+sum3)+(sum1+sum2) ;

使用特权

评论回复
板凳
houcs| | 2012-10-10 20:08 | 只看该作者
对,要注意的是: 使用 4 路分解是因为这样使用了 4 段流水线浮点加法,浮点加法的每一个段占用一个时钟周期,保证了最大的资源利用率。

使用特权

评论回复
地板
ousj| | 2012-10-10 20:09 | 只看该作者
避免没有必要的读写依赖

当数据保存到内存时存在读写依赖,即数据必须在正确写入后才能再次读取。虽然 AMD Athlon 等 CPU 有加速读写依赖延迟的硬件,允许在要保存的数据被写入内存前读取出来,但是,如果避免了读写依赖并把数据保存在内部寄存器中,速度会更快。在一段很长的又互相依赖的代码链中,避免读写依赖显得尤其重要。如果读写依赖发生在操作数组时,许多编译器不能自动优化代码以避免读写依赖。所以推荐程序员手动去消除读写依赖,举例来说,引进一个可以保存在寄存器中的临时变量。这样可以有很大的性能提升。

使用特权

评论回复
5
dousfoulexd| | 2012-10-10 20:11 | 只看该作者
看看

使用特权

评论回复
6
liuzaiy| | 2012-10-10 20:11 | 只看该作者
能举个例子吗?

使用特权

评论回复
7
yinxiangh| | 2012-10-10 20:11 | 只看该作者
不好的代码:

float x[VECLEN] , y[VECLEN] , z[VECLEN] ;

。。。。。。

for ( unsigned int k = 1 ; k < VECLEN ; k ++)

{

   x[k] = x[k-1] + y[k] ;

}

for (k = 1 ; k <VECLEN ; k++)

{

   x[k] = z[k] * (y[k] - x[k-1]) ;

}

推荐的代码:

float x[VECLEN] , y[VECLEN] , z[VECLEN] ;

。。。。。。

float t(x[0]) ;

for ( unsigned int k = 1 ; k < VECLEN ; k ++)

{

   t = t + y[k] ;

   x[k] = t ;

}

t = x[0] ;

for (k = 1 ; k < ; VECLEN ; k ++)

{

   t = z[k] * (y[k] - t) ;

   x[k] = t ;

}

使用特权

评论回复
8
morrisk| | 2012-10-10 20:13 | 只看该作者
循环不变计算

对于一些不需要循环变量参加运算的计算任务可以把它们放到循环外面,现在许多编译器还是能自己干这件事,不过对于中间使用了变量的算式它们就不敢动了,所以很多情况下你还得自己干。

使用特权

评论回复
9
morrisk| | 2012-10-10 20:14 | 只看该作者
对于那些在循环中调用的函数,凡是没必要执行多次的操作通通提出来,放到一个 init 函数里,循环前调用。

使用特权

评论回复
10
栩栩如生| | 2012-10-10 20:17 | 只看该作者
对,另外尽量减少喂食次数,没必要的话尽量不给它传参

使用特权

评论回复
11
栩栩如生| | 2012-10-10 20:17 | 只看该作者
需要循环变量的话让它自己建立一个静态循环变量自己累加,速度会快一点。

使用特权

评论回复
12
zyf部长| | 2012-10-10 20:23 | 只看该作者
还有就是结构体访问,东楼的经验,凡是在循环里对一个结构体的两个以上的元素执行了访问,就有必要建立中间变量了

使用特权

评论回复
13
zyf部长| | 2012-10-10 20:23 | 只看该作者
结构这样,那 C++ 的对象呢 ? 想想看

使用特权

评论回复
14
llljh| | 2012-10-10 20:26 | 只看该作者
有例子说明吗?

使用特权

评论回复
15
ousj| | 2012-10-10 20:27 | 只看该作者
旧代码 :

total =

a->b->c[4]->aardvark +

a->b->c[4]->baboon +

a->b->c[4]->cheetah +

a->b->c[4]->dog;

新代码 :

struct animals * temp = a->b->c[4];

total =

temp->aardvark +

temp->baboon +

temp->cheetah +

temp->dog;

一些老的 C 语言编译器不做 聚合优化 ,而符合 ANSI 规范的新的编译器可以自动完成这个优化,看例子 :

float a , b , c , d , f , g;

。。。

a = b / c * d;

f = b * g / c;

这种写法当然要得,但是没有优化

float a , b , c , d , f , g;

。。。

a = b / c * d;

f = b / c * g;

如果这么写的话,一个符合 ANSI 规范的新的编译器可以只计算 b/c 一次,然后将结果代入第二个式子,节约了一次除法运算。

使用特权

评论回复
16
司徒老鹰| | 2012-10-10 20:29 | 只看该作者
学习了

使用特权

评论回复
17
dingy|  楼主 | 2012-10-10 20:31 | 只看该作者
内容真是丰富,多谢大家了

使用特权

评论回复
18
yanzi0700| | 2012-10-10 21:03 | 只看该作者
学习了!

使用特权

评论回复
19
好吧你赢了| | 2012-10-11 16:25 | 只看该作者
学习了

使用特权

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

本版积分规则

745

主题

10920

帖子

6

粉丝