从语句、函数这一级提高软件性能
2010-07-28 15:40
239 查看
从语句、函数这一级提高软件性能
作者: slowaction
我们能做的有限,不代表性能提升就有限,再不改变整体结构的情况下,我们也能做出惊人的成绩。下面分别从影响软件性能的各个角度分析一下提升性能的方法,
有的作用微乎其微,有的则效果显著,我的格言“蚂蚱也是肉“
1 ,减少机器指令数---当前主频下更有效的运算
cpu 主频是我们控制不了的,不过相关的我们能控制我们的语句复杂度,完成同样的功能,使用的机器指令可是有天壤之别。比如我们要一个hash
结构,hash 桶的大小是65535, 我们的key 是int 的,简单的做法就是int%65635 决定冲突链,殊不知这个%
可是慢得不得了,如果我们用int&0xffff, 效果是一样的,不过性能好很多。
hash key 对一个素数取模数的运算是很常见的,好多开源的程序也这么干,个人以为向2 的幂取整,然后按位运算要好。
2 ,cpu 字长
一般说来,32 位机做int32_t 或者更少 的运算最舒服,所以除非特别必要,不要再32 位机器作64 的运算,不用特别声明16 和8
长度的数据,16 位数据和32 位数据对总线的压力几乎一样的,64 位慢一倍
3 ,能不用系统调用就不用。
比如时间,尽量少用time之类的函数.用户态到内核态是由开销的,并且可能导致进程切换
4 ,能用指针的不要copy数据
Copy 数据是要申请总线的
5 ,用带缓冲的函数,不要动辄非阻塞
相信操作系统,他们能做得更好
6 ,需要多少空间申请多少。
不要总是 char buf[65536];
memset(buf,0x00,65535);
7, 不要破坏 流水线
志强的cpu 流水线是7 级,p4 是三级,从这个角度来说,志强确实比p4 彪悍。不过我们的程序是不是针对流水线作了优化呢?
流水线比较忌讳条件转移,尽量的发挥流水线的优势就要少一些if , 或者说把if
和运算分开,比如在函数入口一次判断完了所有的条件,比如空指针,长度不对等等。然后开始运算。不要随时使用随时判断。
likely 和unlikely 宏定义就是针对流水线的优化语句,编译器碰到likely 宏应该预读likely
分支的语句。这是我们给编译器的一点提示,至于人家领情不领情就不知道了。(只是希望如此,呵呵)。
8 ,const inline register
能const 的都给const 掉,你知道的一定要提醒编译器,立即数要比任何寻址要好很多。
Inline: 短小的函数inline. 注意inline 和register 是c
语言的建议性关键字,编译器自己决定怎么处理,所以不要再inline 中间写复杂的逻辑和循环,否则编译器不给你展开的。
Register: 建议性变量。用不用寄存器不是我们能决定的。我们把我们常用的变量声明成register 提醒一下就仁至义尽了。
9 ,进程通讯shm最快
Shm 的读写和读写自己的内存一样,远非文件之流的可比。Msg是可消耗资源,肯定有锁保护,效率就要差一点了。
10 ,大负荷的文件读取mmap
使用mmap 操作比传统的read 操作好处是减少了一次内核态到用户态的拷贝.
11, 不要分配4096的内存。
Malloc 和内核之间还有一个glibc,他要偷一点空间,如果malloc(4096)实际需要的空间比4096大,很可能申请两个页。
12 ,sched_setaffinity指定进程的cpu的亲密关系,减少cache miss
13 ,空间换时间
一般来说,上面带来的性能提升是很有限的,甚至根本看不出来,写一个likely
宏多半用来吓唬人。时间和空间不同了,这个可能带来成倍的提高。最近有个模块,要过滤不关心的端口,关心的端口不会超过100
个,并且是动态的添加删除的。 开始要用排序数组,二分发查找,我个人感觉插入删除略闲麻烦,更重要的是我感觉不够酷。
平衡二叉树如何,一堆指针,程序还不core 来core 去的。最后我用的方法是,声明一个65656
的数组,端口号作数组下标,关心的是0, 不关心的是-1,ok, 简单明了,想core 都困难,并且速度无出其右,当然我用了256k
内存,为什么是256k 不是64k 或者8k, 32 位机32 位最快么。这个是凑巧了,端口号在16 位以内,如果我们要过滤ip
地址怎么处理?考虑子网的情况,ip 地址的数量要远远超过端口,并且32 位的展开不太可能了。
其实考虑考虑实际环境,很少有0 位的掩码,16 位掩码已经很夸张了,一般是24 位,所以我们有了空间换时间的方案。按照我们关心的ip
地址的后16 位展开成65535 数组,子网展开成host 地址,判断ip
地址是不是我们关心的范围只要简单ip_array[ip&0xffff] 就ok
了。这比采用任何复杂的数据结构都要简单并且效率最好,就算有一些漏网之鱼也不足为患
如果用户非要设置 0.0.0.0 的掩码,那我们只能自认倒霉了。不过这就是小概率事件了。
14 ,深入理解malloc和free
注意保持正确的malloc和free的顺序,不要让内核建立很多的vma,不要让glibc私藏很多的内存,这个话题比较大,有机会我单独写一点资料。
按照栈的规则来申请释放内存一般比较合理。
共享内存,mmap之类的不要和malloc交叉
如果可能,请使用内存池。
作者: slowaction
我们能做的有限,不代表性能提升就有限,再不改变整体结构的情况下,我们也能做出惊人的成绩。下面分别从影响软件性能的各个角度分析一下提升性能的方法,
有的作用微乎其微,有的则效果显著,我的格言“蚂蚱也是肉“
1 ,减少机器指令数---当前主频下更有效的运算
cpu 主频是我们控制不了的,不过相关的我们能控制我们的语句复杂度,完成同样的功能,使用的机器指令可是有天壤之别。比如我们要一个hash
结构,hash 桶的大小是65535, 我们的key 是int 的,简单的做法就是int%65635 决定冲突链,殊不知这个%
可是慢得不得了,如果我们用int&0xffff, 效果是一样的,不过性能好很多。
hash key 对一个素数取模数的运算是很常见的,好多开源的程序也这么干,个人以为向2 的幂取整,然后按位运算要好。
2 ,cpu 字长
一般说来,32 位机做int32_t 或者更少 的运算最舒服,所以除非特别必要,不要再32 位机器作64 的运算,不用特别声明16 和8
长度的数据,16 位数据和32 位数据对总线的压力几乎一样的,64 位慢一倍
3 ,能不用系统调用就不用。
比如时间,尽量少用time之类的函数.用户态到内核态是由开销的,并且可能导致进程切换
4 ,能用指针的不要copy数据
Copy 数据是要申请总线的
5 ,用带缓冲的函数,不要动辄非阻塞
相信操作系统,他们能做得更好
6 ,需要多少空间申请多少。
不要总是 char buf[65536];
memset(buf,0x00,65535);
7, 不要破坏 流水线
志强的cpu 流水线是7 级,p4 是三级,从这个角度来说,志强确实比p4 彪悍。不过我们的程序是不是针对流水线作了优化呢?
流水线比较忌讳条件转移,尽量的发挥流水线的优势就要少一些if , 或者说把if
和运算分开,比如在函数入口一次判断完了所有的条件,比如空指针,长度不对等等。然后开始运算。不要随时使用随时判断。
likely 和unlikely 宏定义就是针对流水线的优化语句,编译器碰到likely 宏应该预读likely
分支的语句。这是我们给编译器的一点提示,至于人家领情不领情就不知道了。(只是希望如此,呵呵)。
8 ,const inline register
能const 的都给const 掉,你知道的一定要提醒编译器,立即数要比任何寻址要好很多。
Inline: 短小的函数inline. 注意inline 和register 是c
语言的建议性关键字,编译器自己决定怎么处理,所以不要再inline 中间写复杂的逻辑和循环,否则编译器不给你展开的。
Register: 建议性变量。用不用寄存器不是我们能决定的。我们把我们常用的变量声明成register 提醒一下就仁至义尽了。
9 ,进程通讯shm最快
Shm 的读写和读写自己的内存一样,远非文件之流的可比。Msg是可消耗资源,肯定有锁保护,效率就要差一点了。
10 ,大负荷的文件读取mmap
使用mmap 操作比传统的read 操作好处是减少了一次内核态到用户态的拷贝.
11, 不要分配4096的内存。
Malloc 和内核之间还有一个glibc,他要偷一点空间,如果malloc(4096)实际需要的空间比4096大,很可能申请两个页。
12 ,sched_setaffinity指定进程的cpu的亲密关系,减少cache miss
13 ,空间换时间
一般来说,上面带来的性能提升是很有限的,甚至根本看不出来,写一个likely
宏多半用来吓唬人。时间和空间不同了,这个可能带来成倍的提高。最近有个模块,要过滤不关心的端口,关心的端口不会超过100
个,并且是动态的添加删除的。 开始要用排序数组,二分发查找,我个人感觉插入删除略闲麻烦,更重要的是我感觉不够酷。
平衡二叉树如何,一堆指针,程序还不core 来core 去的。最后我用的方法是,声明一个65656
的数组,端口号作数组下标,关心的是0, 不关心的是-1,ok, 简单明了,想core 都困难,并且速度无出其右,当然我用了256k
内存,为什么是256k 不是64k 或者8k, 32 位机32 位最快么。这个是凑巧了,端口号在16 位以内,如果我们要过滤ip
地址怎么处理?考虑子网的情况,ip 地址的数量要远远超过端口,并且32 位的展开不太可能了。
其实考虑考虑实际环境,很少有0 位的掩码,16 位掩码已经很夸张了,一般是24 位,所以我们有了空间换时间的方案。按照我们关心的ip
地址的后16 位展开成65535 数组,子网展开成host 地址,判断ip
地址是不是我们关心的范围只要简单ip_array[ip&0xffff] 就ok
了。这比采用任何复杂的数据结构都要简单并且效率最好,就算有一些漏网之鱼也不足为患
如果用户非要设置 0.0.0.0 的掩码,那我们只能自认倒霉了。不过这就是小概率事件了。
14 ,深入理解malloc和free
注意保持正确的malloc和free的顺序,不要让内核建立很多的vma,不要让glibc私藏很多的内存,这个话题比较大,有机会我单独写一点资料。
按照栈的规则来申请释放内存一般比较合理。
共享内存,mmap之类的不要和malloc交叉
如果可能,请使用内存池。
相关文章推荐
- 关注内存 提高软件性能(3)
- 怎样写SQL语句可以提高数据库的访问性能【鸡蛋】
- 提高系统性能——对SQL语句优化的思考
- 关注内存 提高软件性能(2)
- 走向DBA[MSSQL篇] - 从SQL语句的角度提高数据库的访问性能
- 怎样快速估算热点函数的性能提高?
- 在程序开发中怎样写SQL语句可以提高数据库的性能
- sql语句性能提高
- 如何测试sql语句性能,提高执行效率
- 走向DBA[MSSQL篇] 从SQL语句的角度 提高数据库的访问性能
- sql语句性能提高
- final修饰函数在性能上提高的测试。
- 对多表联合查询的SQl语句的改进,大幅提高查询性能
- (走向DBA[MSSQL篇] - 从SQL语句的角度提高数据库的访问性能)一些SQL查询语句应加上nolock
- 利用函数参数和返回值提高嵌入式软件质量
- 在SQL语句中使用索引提示提高SQL性能
- 走向DBA[MSSQL篇] 从SQL语句的角度 提高数据库的访问性能
- 关注内存 提高软件性能(3)
- 如何测试sql语句性能,提高执行效率
- 怎么样写SQL语句能提高性能?