嵌入式系统中的优化技巧

电子说

1.2w人已加入

描述

在嵌入式系统中由于资源比较有限,特别是内存资源,因此对程序运行的性能要求比较高。对执行效率高的程序段所占用的空间和运行效率进行全方位的优化,可以对程序运行的整体效率将产生可观的提升。

1、循环缓冲区

在一些嵌入式的系统中,常常需要开辟一块缓冲区保存数据。例如:对于数据采集系统,需要将一定时间段内的数据放入一个内存区域中。这个内存区域的放置方法是从低地址开始放置,如果放满了(到达了最高的地址),则需要从头部的低地址开始重新放置。这样的内存结构就组成了一个循环缓冲区。

在一般的嵌入式处理器中没有硬件自动完成循环放置的功能,通常的做法是在程序的每次循环中都判断缓冲区是否放满了,显然这样的开销很大。

如果要在程序中执行缓冲区类型的操作,这些操作一般需要占用一块连续的内存。在栈上分配的内存,一般只能在函数内部使用,函数退出的时候就会被释放,因此不适合作为缓冲区使用。而在堆上的内存和静态内存都可以作为缓冲区内存使用。

我们举例来看下:

#define  BUFFERSIZE 256

int x[BUFFERSIZE];

unsigned int k;

unsigned int i;

while(1)

{

k = i & (BUFFERSIZE-1);

x[k] = ImputData();

/*……*/

i++;

}

从程序中可见,数组x[]是作为程序的缓冲区使用的,而由于开始并没有进行数组的初始化,x[]是一个建立在BSS段上的数组,其大小由BUFFERSIZE确定。

我们看循环内的操作,可以完成自动循环的过程,这个例程中,当i增加到256的时候,k作为数组下标,又会返回为0,i本身增加到最大值的时候也会变为0。

那么大家很容易看出来,由于不需要使用if做判断,可以节省几条程序指令的时间。对于这几条指令看似节省的时间不多,但是由于上述语句执行的频率非常高,所以这些时间的节省占程序总运行时间的权重还是比较大的。尤其对于实时采样处理问题,程序必须在指定时间内完成一系列的操作。所以对于执行效率比较高的指令,哪怕只节省一条指令,对运行效率的提高都是很有意义的。

从以上的例子中可以看出,当进行程序优化的时候,不仅需要考虑程序段运行的绝对时间,还应该考虑程序段运行的频率。对于运行频率非常高的程序,对其进行优化会在很大的程度上提高系统的性能。

2、查表法

由于资源有限,程序的运行效率在嵌入式系统上比在PC上的程序开发更为重要。程序的运行速度和所占用的存储器空间这两个效率问题都是必须考虑的。嵌入式系统程序的运行速度与处理器频率有关系;而程序所能占用的存储器空间与ROM或RAM的大小有关系。

在当前的嵌入式系统中,程序的运行速度比程序所占用的存储器空间显得更重要,一是存储器方便扩展,二是存储器的容量是比较容易控制,程序运行占用的处理器时间比较难控制。

在设计过程中,程序的容量和速度在很多时候是有些矛盾的,在程序中牺牲一定的存储容量换取程序的运行速度,这对于嵌入式系统来说是有一定好处的。典型的例子就是查表法。

例如:在一个4位的二进制数中,确定有几位为1,也就是要统计0x0~0xf中的任何一个数,中间有几个1。

典型的思路就是使用循环的方法让程序在这个4位的数中依次查找各个位是否为1,最后累加得出1的数目。那么在实现这个简单的功能的过程中,需要进行4次循环、4次判断,这是有一定开销的,占用了不少处理器的时间。从程序需要实现的功能考虑,输入是一个4位的数,范围是0x0~0xf,输出数的范围是0~4,这实际上是完成了一种映射功能,可以换成第二种查表法的思路,就是构造一个16个元素的数组,可以通过数组得到结果。实际上数组的下标就是输入的数值,而数组的元素就是输出的数值。

那么很容易看出来,这种做法的优点是每个数值的获取非常快,代价则是增加了一个有16个元素的数组。数组是预先固化好的常量,而不是程序动态生成的,这种利用静态空间换取程序执行时间的方式转换后的程序执行效率非常高。如果把它应用在使用频率很高的程序中,就可以节省很多的系统开销。

同样,大家可以考虑一下如果是查找8位数中的1的个数怎么做?16位呢?如果变通。

3、针对循环执行效率的优化

循环是C语言程序中的常用语法功能,由于循环执行的次数较多,占程序执行时间的权重大,所以对循环的优化是提高程序效率的关键点。

例如,

void change_list_value()

{

int i,count;

POSITION pos;

CPtrList* plist;

plist = get_start(pos);

for(i = 0; i < get_count(); i++)     count = get_count();      

{          for(i = 0; i < count ; i++)

plist = get_next(pos);     {}

set_val (plist);

}

return 0;

}

上面这个循环代码左边是原始写法,右边是改进的。可以发现循环中执行的函数减少了,原来的get_count()函数从原来的内部转移到了循环外部,也就是说这个循环函数改进后只执行一次,如果这个链表中的元素有几千个至几万个,那么第一段代码比第二段代码多执行了几千条几万条的语句,这样会导致时间上巨大的开销。

总结:在循环系统中,针对于循环条件,应该尽可能地使用临时变量来替代函数调用,这样可以在循环次数较多的情况下,减少大量不必要的函数调用。

你有没有更好的优化技巧也分享出

责任编辑:haq

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分