现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

关于优化的一点小总结

2013-08-30 22:35 工业·编程 ⁄ 共 1195字 ⁄ 字号 暂无评论

编译器必须假设不同的指针可能会指向存储器中的同一个位置。这造成了一个主要的妨碍优化的因素。

例如:

void twiddle1(int *xp, int *yp)

{

*xp += *yp;

*xp += *yp;

}

void twiddle2(int *xp, int *yp)

{

*xp = 2 * (*yp);

}

看起来twiddle1与twiddle2实现的是同样的功能,并且twiddle2应该是twiddle1的优化版,因为twiddle2只需要访问一次xp和一次yp,而twiddle1却用了两次。

但是,考虑下面一种情况:

int t;

twiddle1(&t, &t);

twiddle2(&t, &t);

它们得到的结果是一样的吗,不!这也就是编译器在做优化的时候必须要考虑到的问题,编译器并不能完全了解编程者的意图,所以只能对当前的代码保守的优化。

同样的例子还有:

int counter = 0;

int f(int x)

{

return (counter+x);

}

int f1(int x)

{

return f(x)+f(x);

}

int f2(int x)

{

return 2*f(x);

}

如何表示程序的性能—CPE/

CPE: cycles per element, 每元素的同期数。

如何理解,比如一个数组int array[50],它在函数f()中被用于计算,最后f()所用去的cpu clock为100, 那么函数f()的CPE为100/50=2.0;

为什么不采用每次循环的周期数而是采用每元素的同期数呢,因为可能会出现循环展开的情况。

如何消除循环的低效率

Ø 减少不必要的函数调用:

如for (i = 0; i < vec_length(v) i++)中的vec_length完全可以放在循环体的外面。

Ø 消除不必要的存储器引用

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

{

*dest = *dest + data[i];

}

可以先用局部变量进行运算,最后才赋值到dest中去。

Ø 作循环展开,让软件流水

注意,让软件能流水的前提条件是在循环体中不能有判断语句,一个if也不行。所以要想让代码执行得更快,就要尽量想办法把判断语句搬移到循环体外面去。

减少浮点运算所带来的开销

一般来说,处理器作定点运算的速度会比作浮点运算的速度快(专用的浮点处理器例外)。如在DM642上,作定点运算的速度是作浮点运算速度的10倍。所以在处理浮点数之间,先将其转化为定点后运算再赋值将会获得很大的性能提升。

是否应该将数组转化为指针代码

根据经验,数组代码将会比指针代码更可取,我们已经看到过的编译器,它们对数组代码应用非常高级的优化,而对指针代码只应用最小限度的优化。并且数组代码具有更好的可读性。

合理利用CACHE

对于DM642而言,L2 Cache的大小是可以设定的,但如果Cache全开,将会用尽所有的L2 SRAM。这样就不能使用如DMA two buffer的技术了。但如果一点都不开,那对程序的运行速度是有非常大的影响的。

给我留言

留言无头像?