[读书笔记3]《C语言嵌入式系统编程修炼》
第五章 性能优化
5.1 使用宏定义
在 C 语言中,宏是产生内嵌代码的唯一方法。对于嵌入式系统而言,为了能达到性能要求,宏是一种很好的代替函数的方法。
写一个"标准"宏 MIN ,这个宏输入两个参数并返回较小的一个:
错误做法:
#define MIN(A,B) ( A <= B ? A : B )
正确做法:
#define MIN(A,B) ((A)<= (B) ? (A) : (B) )
对于宏,我们需要知道三点:
(1)宏定义"像"函数;
(2)宏定义不是函数,因而需要括上所有"参数";
(3)宏定义可能产生副作用。
下面的代码:
least = MIN(*p++, b);
将被替换为:
( (*p++) <= (b) ?(*p++):(b) )
发生的事情无法预料。 因而不要给宏定义传入有副作用的"参数"。
5.2 使用寄存器变量
当对一个变量频繁被读写时,需要反复访问内存,从而花费大量的存取时间。为此,C 语言提供了一种变量,即寄存器变量。这种变量存放在 CPU 的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写,从而提高效率。寄存器变量的说明符是 register。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量,而循环计数是应用寄存器变量的最好候选者。
(1) 只有局部自动变量和形参才可以定义为寄存器变量。因为寄存器变量属于动态存储方式,凡需要采用静态存储方式的量都不能定义为寄存器变量,包括:模块间全局变量、模块内全局变量、局部static变量;
(2) register 是一个"建议"型关键字,意指程序建议该变量放在寄存器中,但最终该变量可能因为条件不满足并未成为寄存器变量,而是被放在了存储器中,但编译器中并不报错。
下面是一个采用寄存器变量的例子:
/* 求1+2+3+….+n的值 */
WORD Addition(BYTE n)
{
register i,s=0;
for(i=1;i<=n;i++)
{
s=s+i;
}
return s;
}
本程序循环 n 次,i 和 s 都被频繁使用,因此可定义为寄存器变量。
5.3 内嵌汇编
程序中对时间要求苛刻的部分可以用内嵌汇编来重写,以带来速度上的显著提高。但是,开发和测试汇编代码是一件辛苦的工作,它将花费更长的时间,因而要慎重选择要用汇编的部分。
在程序中,存在一个 80-20 原则,即 20% 的程序消耗了 80% 的运行时间,因而我们要改进效率,最主要是考虑改进那 20% 的代码。
嵌入式 C 程序中主要使用在线汇编,即在C程序中直接插入 _asm{ } 内嵌汇编语句:
/* 把两个输入参数的值相加,结果存放到另外一个全局变量中 */
int result;
void Add(long a, long *b)
{
_asm
{
MOV AX, a
MOV BX, b
ADD AX, [BX]
MOV result, AX
}
}
5.4 利用硬件特性
首先要明白 CPU 对各种存储器的访问速度,基本上是:CPU内部RAM > 外部同步RAM > 外部异步RAM > FLASH/ROM。
对于程序代码,已经被烧录在 FLASH 或 ROM 中,我们可以让 CPU 直接从其中读取代码执行,但通常这不是一个好办法,我们最好在系统启动后将 FLASH 或 ROM 中的目标代码拷贝入 RAM 中后再执行以提高取指令速度;
对于 UART 等设备,其内部有一定容量的接收 BUFFER,我们应尽量在 BUFFER 被占满后再向 CPU 提出中断。例如计算机终端在向目标机通过 RS-232 传递数据时,不宜设置 UART 只接收到一个 BYTE 就向 CPU 提中断,从而无谓浪费中断处理时间;
如果对某设备能采取 DMA 方式读取,就采用 DMA 读取,DMA 读取方式在读取目标中包含的存储信息较大时效率较高,其数据传输的基本单位是块,而所传输的数据是从设备直接送入内存的(或者相反)。DMA 方式较之中断驱动方式,减少了 CPU 对外设的干预,进一步提高了 CPU 与外设的并行操作程度。
5.5 活用位操作
使用 C 语言的位操作可以减少除法和取模的运算。在计算机程序中数据的位是可以操作的最小数据单位,理论上可以用"位运算"来完成所有的运算和操作,因而,灵活的位操作可以有效地提高程序运行的效率。举例如下:
/* 方法1 */
int i,j;
i = 879 / 16;
j = 562 % 32;
/* 方法2 */
int i,j;
i = 879 >> 4;
j = 562 - (562 >> 5 << 5);
对于以 2 的指数次方为 "*"、"/" 或 "%" 因子的数学运算,转化为移位运算 "<< >>" 通常可以提高算法效率。因为乘除运算指令周期通常比移位运算大。
C语言位运算除了可以提高运算效率外,在嵌入式系统的编程中,它的另一个最典型的应用,而且十分广泛地正在被使用着的是位间的与(&)、或(|)、非(~)操作,这跟嵌入式系统的编程特点有很大关系。我们通常要对硬件寄存器进行位设置,譬如,我们通过将 AM186ER 型 80186 处理器的中断屏蔽控制寄存器的第低 6 位设置为 0(开中断 2),最通用的做法是:
#define INT_I2_MASK 0x0040
wTemp = inword(INT_MASK);
outword(INT_MASK, wTemp &~INT_I2_MASK);
而将该位设置为 1 的做法是:
#define INT_I2_MASK 0x0040
wTemp = inword(INT_MASK);
outword(INT_MASK, wTemp | INT_I2_MASK);
判断该位是否为1的做法是:
#define INT_I2_MASK 0x0040
wTemp = inword(INT_MASK);
if(wTemp & INT_I2_MASK)
{
… /* 该位为1 */
}
上述方法在嵌入式系统的编程中是非常常见的,我们需要牢固掌握。
5.6 总结
在性能优化方面永远注意 80-20 准备,不要优化程序中开销不大的那 80%,这是劳而无功的。
宏定义是C语言中实现类似函数功能而又不具函数调用和返回开销的较好方法,但宏在本质上不是函数,因而要防止宏展开后出现不可预料的结果,对宏的定义和使用要慎而处之。很遗憾,标准 C 至今没有包括 C++ 中 inline 函数的功能,inline 函数兼具无调用开销和安全的优点。
使用寄存器变量、内嵌汇编和活用位操作也是提高程序效率的有效方法。
除了编程上的技巧,为提高系统的运行效率,我们通常也需要最大可能地利用各种硬件设备自身的特点来减小其运转开销,例如减小中断次数、利用 DMA 传输方式等。
[读书笔记3]《C语言嵌入式系统编程修炼》的更多相关文章
- HTTP权威指南读书笔记
HTTP权威指南笔记 读书有两种境界,第一种境界是将书读薄,另一种是读厚.本篇文章就是HTTP权威指南的读书笔记,算是读书的第一重境界,将厚书读薄.文章对HTTP的一些关键概念做了比较详细的概述,通读 ...
- css权威指南读书笔记
今天翻手机,翻到了许久之前看css权威指南时的笔记,遂移到博客中来. 1.属性选择器p.one class名为one的p元素p[class][name] 含有class和name属性的p元素p[cla ...
- 经典的性能优化最佳实践 web性能权威指南 读书笔记
web性能权威指南 page 203 经典的性能优化最佳实践 无论什么网络,也不管所用网络协议是什么版本,所有应用都应该致力于消除或减 少不必要的网络延迟,将需要传输的数据压缩至最少.这两条标准是经典 ...
- css权威指南读书笔记-第10章浮动和定位
这一章看了之后真是豁然开朗,之前虽然写了圣杯布局和双飞翼布局,有些地方也是模糊的,现在打算总结之后再写一遍. 以下都是从<css权威指南>中摘抄的我认为很有用的说明. 浮动元素 一个元素浮 ...
- Hadoop权威指南读书笔记
本书中提到的Hadoop项目简述 Common:一组分布式文件系统和通用I/O的组件与接口(序列化.javaRPC和持久化数据结构). Avro:一种支持高效.跨语言的RPC以及永久存储数据的序列化系 ...
- JavaScript权威指南读书笔记
JavaScript 1.变量 变量是一个表示值的符号,是一个名字,他的本质是值: var x; //----声明一个变量: 值通过等号“=”赋给变量,x = 16; 对象是名/值对的集合,或字符串到 ...
- Java性能优化权威指南-读书笔记(五)-JVM性能调优-吞吐量
吞吐量是指,应用程序的TPS: 每秒多少次事务,QPS: 每秒多少次查询等性能指标. 吞吐量调优就是减少垃圾收集器消耗的CPU周期数,从而将更多的CPU周期用于执行应用程序. CMS吞吐调优 CMS包 ...
- Java性能优化权威指南-读书笔记(四)-JVM性能调优-延迟
延迟指服务器处理一个请求所花费的时间,单位一般是ms.s. 本文主要讲降低延迟可以做的服务器端JVM优化. JVM延迟优化 新生代 新生代大小决定了应用平均延迟 如果平均Minor GC持续时间大于应 ...
- Java性能优化权威指南-读书笔记(三)-JVM性能调优-内存占用
新生代.老年代.永久代的概念不多说,这三个空间中任何一个不能满足内存分配请求时,就会发生垃圾收集. 新生代不满足内存分配请求时,发生Minor GC,老年代.永久代不满足内存分配请求时,发生Full ...
- Java性能优化权威指南-读书笔记(二)-JVM性能调优-概述
概述:JVM性能调优没有一个非常固定的设置,比如堆大小设置多少,老年代设置多少.而是要根据实际的应用程序的系统需求,实际的活跃内存等确定.正文: JVM调优工作流程 整个调优过程是不断重复的一个迭代, ...
随机推荐
- POJ 1741 Tree【Tree,点分治】
给一棵边带权树,问两点之间的距离小于等于K的点对有多少个. 模板题:就是不断找树的重心,然后分开了,分治,至少分成两半,就是上限为log 然后一起统计就ok了 #include<iostream ...
- codevs——6220 ZHR吃好吃的
6220 ZHR吃好吃的 时间限制: 1 s 空间限制: 1000 KB 题目等级 : 白银 Silver 题解 查看运行结果 题目描述 Description 有一个人名字叫ZHR, ...
- JVM定位程序假死或cpu占用高的线程
linux系统: 参考:https://blog.csdn.net/qq_40197576/article/details/80287515 1>使用top命令查看占用cpu进程情况,得到jav ...
- Setting up Storm and Running Your First Topology
http://www.haroldnguyen.com/blog/2015/01/setting-up-storm-and-running-your-first-topology/ --------- ...
- iPhone 3gs 5.0.1降級到4.3.3 昨晚搞定(有shsh備份)
經過昨天白天一天的學習和準備,終於一次降級成功. 手機未降級時狀態: 無鎖港版 3GS 16G 固件:5.0.1 基帶:05.16.05 記錄且分享降級完整步驟: 準備以下軟件.工具 官網固件 ...
- Erlang 又生虫了
好久不玩Erlang了.近期想鼓捣Eresye,下了个最新版OTP 17,结果.发现了问题. 安装这个最新版的Erlang (erl 6.0)后,用erlc编译了Eresye 1.2.5,并放入其li ...
- [Spring] Bean Scope Singleton cs Prototype
We can define a class to be Singleton or Prototype. If the class was defined as Prototype, then ever ...
- 总结react中遇到的坑和一些小的知识点
在使用react 中经常会遇到各种个样的问题,如果对react不熟悉则会对遇到的问题感到莫名其妙而束手无策,接下来分析一下react中容易遇到的问题和注意点. 1.setState()是异步的this ...
- kvc VS kvo
Kvo是Cocoa的一个重要机制,它主要是用于对一个属性的新旧值的监控. 例如说依据A(数 据类)的某个属性值变化,B(view类)中的某个属性做出对应变化.对于MVC,kvo应用的地方很广泛. 使用 ...
- 项目实战之poi导出excel
所需jar包 官方下载地址:http://mirrors.hust.edu.cn/apache/poi/release/bin/poi-bin-3.17-20170915.zip 1.前端调用方法: ...