作者 kernelchina | 2011-05-23 08:54 | 类型 行业动感 |
43条用户评论 »
性能优化这个话题可大可小。从大的方面来说,在系统设计之初,需要考虑硬件的选择,操作系统的选择,基础软件平台的选择;从小到方面来说,每个子系统的设计,算法选择,代码怎么写,如何使用编译器的选项,如何发挥硬件的最大性能等等。本系列关注的是在给定硬件平台,给定操作系统和基础软件平台的情况下,如何优化代码,简而言之,就是关注小的方面。
在给定硬件平台的情况下,如何发挥硬件的最大效能?前提是需要对硬件平台很熟悉。如何分离硬件相关代码和硬件无关的代码是一个很重要的技能。针对某一硬件平台优化固然是好,但是如果代码都是硬件相关的,就失去了可移植性,软件的性价比不一定高。
性能优化只是系统的一个方面,它会和系统的其他要求有冲突,比如
- 可读性:性能优化不能影响可读性,看起来不怎么漂亮的代码,没有人愿意维护
- 模块化:性能优化往往需要打破模块的边界,想想这是否值得
- 可移植:隔离硬件相关的代码,尽量使用统一的API
- 可维护:许多性能优化的技巧,会导致后来维护代码的人崩溃
需要在性能优化和上述的几个要求之间做出tradeoff,不能一意孤行。
性能优化的目标是什么?不外乎两个:
- 时间性能:减小系统执行的时间
- 空间性能:减小系统占用的空间
那么我们优化的策略,首先就是对系统进行分解,测量:
- 分解:系统包含的子系统,执行路径,函数,指令等等
- 测量:每个子系统,执行路径,函数,指令所花费的时间和空间
然后,选取执行次数最多,消耗时间最长的函数进行优化(这里需要指出的是,消耗时间最长的函数并不一定就是优化的对象,这个需要放到某个执行路径上去考察,优化最常使用的执行路径)。
对于单核和多核的优化,有什么不同?以cache miss为例,在单核上
- I-cache miss的原因是什么?一是代码路径太长,以至于超出了cache的容量,cache需要替换;二是 多个执行路径之间相互交替,cache需要替换;三是I-cache, D-cache互相踩。(对于i-cache的优化,基本上没有什么可遵循的规则。最有效的还是:一,减少无用的代码;二,减少冗余的代码;三,减少函数调用的开销;4,快速路径短小精干,相关代码相邻;5,相关代码放到一个段里面等等)
- D-cache miss的原因是什么?一是数据结构太大,超出了cache的容量(大数组,长链表都会有这个问题,比较之下,还是数组更让人放心一点);二是多个数据结构之间相互踩(问题是一个执行路径,需要访问那么多数据吗?如果是,这个路径是不是太复杂了一点);三是D-cache和I-cache的冲突(这个不好说,系统里面会出现这种模式的cache miss吗?)
在多核上,cache miss会有什么新的特点?
- I-cache miss:多核有独立的L1 cache,共享的L2/L3 cache。如果多条执行路径同时进行,cache的冲突几率就会增大。但是这是没办法的事情,总不能什么事都不做吧。所以,对i-cache的优化,关注快速路径就可以了,不要把精力都花费在这个上面
- D-cache miss:锁,原子操作,伪共享等都会引起多核上的D-cache miss。这是多核优化时需要关注的重点。优化的策略也很直接,就是尽量减少锁,原子操作,伪共享等。多核的所有冲突都是由共享引起的,所以要区分出哪些是必须共享的,哪些是可以per thread的。并行优化与应用有关,需要注意的是,优化是否对所有用例都有效?做不好,可能顾此失彼。
性能优化必备技能
- 熟悉系统执行路径:可以通过读代码或者使用profiling工具学习代码,要思考执行路径上不合理的地方,看看哪里可以减少,哪里可以合并。熟悉系统执行路径是性能优化的基础。
- 熟悉测量工具:顺手的工具必不可少
- 常用的代码优化技巧和策略:针对不同的语言,不同的平台,使用与之相应的技巧和策略
学习性能优化是一个不断积累的过程,在这个过程中,总结和学习自己用的顺手的工具和技巧,不断尝试,不断思考,就会有收获(感谢teltalk.org读者的评论,弯曲评论的精华在评论,思想碰撞才有火花)。
参考资料:
1: http://en.wikipedia.org/wiki/Program_optimization
2: http://www.agner.org/optimize/
3: Code Optimization – Effective Memory Usage
4: Hacker’s Delight
|
| |
雁过留声
写的很好,但有一点值得注意:
〉性能优化的目标是什么?不外乎两个:
■时间性能:减小系统执行的时间
■空间性能:减小系统占用的空间
我认为你现在所谈的都是有关时间方面的性能优化。 应该直接了当的说:要想减少执行时间, 就应该。。。
如何减小系统占用的空间是另外一套方法。
确是心得!
(sorry or using English here, I have no Chinese input at office)
Great article !
but, I do not understand the following point “D-cache miss:锁,原子操作,伪共享等都会引起多核上的D-cache miss”
I understand Lock latency is quite high, several hundreds of cycles at SUN server. but, why would it cause cache miss ?
would anybody please give more detail here ?
Thank you very much
lock is a special memory access, if you look into the lock implementation code
非常欣赏kenelchina同学的专业精神和无私奉献,一直都很关注你的文章,受益匪浅。不知能否从大的方面论述下性能优化呢?
“从大的方面来说,在系统设计之初,需要考虑硬件的选择,操作系统的选择,基础软件平台的选择”
Tony,关于锁,特别是spinlock在multicore上的分析,大概是这样,这样的。
你的问题很不错。感觉是个很sharp的年轻人。
Kernelchina在D-Cache Miss里去emphasize(强调)锁机制是不precise的,if I don’t say he should NOT.
锁机制的难度不是锁本身,而是锁的粒度(Granularity)。例如,Big Lock问题。。。
在锁的本身方面,有许多做法。我在工作中拿mem做过,拿chipset的register做过。也有许多NPU会设计许多锁。效果都差不多。高端CPU最后都是Cache-Cache的sync memory变量。
其实,这些latency最后都不是killer。杀死一个系统的是legacy system对细化锁粒度的局限。
换言之,革命容易,改革难。
首席能不能把这个系列归纳一下,做个序,评论什么的,这样读者可能会更有感觉一点,就像Pattern系列。对于cache miss部分,有了测量数据,有时就是想不明白原因是什么,也行想的方向有点问题。
看在你的面子上,我答应。。。
所以维新失败,革命成功,但伤害巨大;所以手术容易,中医很难,所以我们现在的改革其实很难很难
首席,kernel不就是用的大内核锁吗?难道也是某种trade off的结果?
看来是我理解错了,大内核锁是历史遗留问题,2.6内核用得也不多。内核里面的锁很多,我这个阶段用锁还停留在不要导致死锁上,还未意识到锁对性能的影响。理论上锁的粒度应该越细效率越高吧?但是粒度太细了会引入复杂度,确实很难trade off。
刚刚查了以下,有个lockmeter的工具可以度量在multiprocessor上的linux kernel的spin lock对性能的影响,回头找个时间研究一下。
GNU一直认为应该在某一天替换掉linux,而使用微内核的HURD之类。因为他们也不喜欢宏内核
理想是理想,现实是现实,如果linux一开始就走微内核的路,估计和hurd差不多的命运。
我不这么认为。linux没走微内核不是对其生存考虑的。而是linus根本没那个觉悟。再者后期开发是绝对的低技术人力密集型(相对而言),所以不再乎。到后来商业操作系统压榨下的厂商将linux作为战略投资,linux在技术各方面才开始有起色。
linux没走微内核,不是在胶片的基础上,在那冰天雪地的北欧,经过研发部长们的沙盘推演而得出的智慧决定。而是Linus在那个时候(估计现在也一样),其实就根本不懂Micro-Kernel。他当初也就一个大四的学生。。。
这就是bottom up的魅力。。。自由发展:-)。
嗯?linus应该懂微内核吧?那厮不是还为微内核宏内核谁更叼和写minix的那个知名教授论战过么?
那是被Tanenbaum戳了以后打嘴仗需要恶补的吧。lol
不懂linux,如果从前面内行的评论看,linus也不过尔尔,没有他,也会有别的xx出来,甚至更好,如果和ZZ横向比较,也就和老毛TG能得天下一个level
其实也没有这么糟糕了。linux的成长,也不是linus一个人的功劳。随着linux的发展,包括linus在内的参与其中的人都得到了发展。这大概算是草根的力量吧。
那次关于微内核的争论,我看是工程界的一次胜利。当时微内核有两个不利的问题:一是当时所有的微内核项目都暴露了性能的问题;二是因为前面的问题,没有多少软件想移植到微内核系统上,因而缺乏应用。至于大内核难以维护难以扩展的问题,凭着大市场的开发模式,凭着蚁多咬死象的战术,linux这些年也跌跌撞撞地发展到今天这样庞大的规模。现在L4 OS据说解决了性能的问题。但要证明这个问题,就必须要大量的应用在上面运行测试。但要是移植了应用过来,如果性能还是不行,那这移植工作就是无用功了,谁也不想干。这鸡和蛋的问题,错过了时机,就成了无解的问题。
所以性能问题还真是开发的头等大事。一力降十会,野蛮才能生长。
早就解决性能问题了……在process id硬件出来的那一天。主流商业系统哪个不是micro啊。不是mciro..人力成本伤不起啊。。伤不起。像linux那样公司玩不得亏成非洲啊。
外行人看到的,似乎从服务器到网络设备,大部分都是基于Linux,为什么不用micro呢?还是Linux也micro了?
it’s free… lol
至于linux的用途……F35不用 高档汽车不用 医疗器器械不用 波音NASA不用 思科,Juniper也没用。。能打星际的示波器也不用。
可能……只有服务器和一些网络设备用。还有巨型计算机
linux不是micro kernel,虽然它从微内核那里借鉴了很多思想。
micro kernel有一个特征是不同的模块运行在不同的地址空间,它们之间需要通过message交换数据。除了message system,其它模块都可以运行在用户空间。这样能造成系统死机的模块就很小,就容易维护。其它模块死了,就还可以再次启动,这样整个软件系统就足够坚强。
相似的思想在其它地方应用得很多。例如MS DCOM,或者是linux上的DBUS。这种系统的性能受制于message system的性能。像L4 OS,就是对mailbox指令直接绑定到汇编指令以提高性能。
linux的所有模块都运行在同一个地址空间,包括后来动态加载的模块。只要有一个模块死了,大家都死。linux的可维护性是通过不断修改接口,抽象接口来提高的。但是要死一块死的缺点,是大内核无法改变的问题。
但是linux系统也在尝试用户空间驱动,在USB系统那块应用得最多。只不过没有特别的需求,大家都没有动力把驱动移植到用户空间了。所以,如果不从原教义的角度看问题,linux可以做成micro kernel,就看有没有需求了。L4 OS在尝试进入虚拟化的领域,从更大的角度看,Linux / Window Mobile / WebOS,只不过是更大一点,更容易崩溃一点的TASK罢了。所以,改良,总不会呈现令人激动的颠覆时刻。只有方向正确,只要时间足够,事情总会向着互相融合,互相共存的方案演变。
er…DBUS好像不是linux上的吧。。。如果说借鉴了micro kernel应该是指那个可加载模块?这个就有点幽默了。
难道linux未来的方向就和Intel CISC演化类似?微内核真核心,模拟的宏内核表现?
内核模块的好处在于升级方便吧,虽然很多人还没意识到这个好处,主要原因是linux没有稳定的api。
不是最好的就能发展起来,而是要看历史选择了谁。
DBUS的例子只是说明它们之间的设计思路是相通的。server / client都运行在不同的地址空间,之间通过消息传递数据,少了谁系统照样跑。
动态加载模块不算micro kernel的特点。但用户空间的驱动应该是。应该说,有了用户空间驱动的机制,linux就有了变成micro kernel的可能。但现在大家都没有动力往这方面发展,因为现在的问题用现在的技术和工程方法都能cover住,多一事不如少一事。
我在前面的文章或者评论中谈过:OS最新的发展就是:虚拟化技术。虚拟化技术会使得各种OS的界限和谐化。
学习了。
Linux做不到不同模块/进程用不同的地址空间,隔离故障吗?
Linux和micro在性能上大体有多大差距?
linux kernel就是一打个可执行映像么……单内核就是这样,因为是同一个进程,kernel内的调用通过内存映射之类的方法就可以,而microkernel的就要通过message来进行
在linux kernel space,所有的模块都是运行在同一个地址空间,各自都可以通过函数调用访问接口,可以直接访问数据。动态模块加载,实质上是ELF loading,把所有的符号表解决了,后来的模块就可以直接调用原有模块的函数。这种设计思想是相信开发者的能力而简化了设计。出了故障,那只有kernel panic了。
micro kernel的性能,是个热门的话题。有个L4linux的项目,号称经过L4的改造,linux系统比原来要快。但是除开实验室里的人,有几人敢实际用到产品里?
shuyong:这里模块的概念是指一个进程里的不同模块,还是不同的进程?还是一个模块同时也包含了多个进程?
早期的microkernel似乎性能耗费在20%~30%吧?现在的l4据说可以做到5%~10%
Linus 当时怎么可能不知道micro kernel? 不是整个世界都和咱们的网络一样封闭。 Linus 91年出第一版就说了是山寨 Minix,第二年初,也就92年就和反动权威Tanenbaum在新闻组里单挑,论战头条就是Microkernel vs Monolithic System。 Tanenbaum可能是研究搞多了一根筋,到了2006年,形势都已经明朗的不能再明朗了,还要跳出来自己找打。纯micro比较流行的只有QNX吧,NT及以降/OS X都算是hybrid。
另外,我理解的虚拟化难道不是为了(共享|分配|兜售)硬件资源么?OS界限的和谐化这种工作恐怕还是交给java们去做吧。
to Lucifer:也就是micro性能会降低,但可靠性大大提高?
我所说的模块不是一个严格的定义,只是大家约定俗成的一种说法。所说的模块,都是指linux的一个可以分割的组成部分。
从动态转载的角度,linux可以划分为一个巨大的开机后就在内存的部分,包括调度/MMU/底层硬件接口等部分,还有多个可以动态加载的模块。这些模块大多是设备驱动,也有部分是和硬件不紧密的功能模块,例如ppp protocol。
这些模块都运行在kernel space,有kernel thread的概念。所有的user space的程序有process id >= 1。所以我们也可以认为模块是在process id = 0里面的众多threads。
明白了,是kernel里的模块,非用户态的模块。个人感觉对军工航天航空等一些对可靠性超过6西格玛的,应该micro更好,对民用,包括电信IT等,不一定需要micro,除非非micro的OS搞得很差,必须要micro来解决,因为系统可靠性概念不单单是内核,要E2E,这里有木桶原理,你把一片做得很长很长有两个问题,一个是成本,一个是效果,具体处理参考首席trading off理论
linux module相当于动态库,不能独立运行。
》》》我在前面的文章或者评论中谈过:OS最新的发展就是:虚拟化技术。虚拟化技术会使得各种OS的界限和谐化。
首席的意思是说,课本上的os将消失,将向两个方向进化,一个是现在虚拟机的hypervisor(负责协调硬件资源),另一个就是application aware os?
hybrid是在早期的硬件上折中方案。现在已经没有什么关系了。只不过成型的东西不想动而已。所有商业系统都扯上micro,足以说明微内核理念在节省人力和增强稳定性上的功效。
linus早期也就是想山寨一个unix,借鉴了minix的文件系统而已。至于懂不懂那就很难说了。
看来虚拟化还是很有前景的,去看看。谢首席方向性指引lol
几天没来了哦……
to 35。是这样
看一看 UNIX内核程序员的SMP 和cache 一直性
这本书, 这个帖子就可以结了
42楼,此言差矣!
如果我没有记错的话,记得两三年前,园区的国际科技园内就家做手机搜索的,不知道现在咋样了。苏州距离南京、上海、杭州都不算远,只要机会合适或者离家近,到苏州的同学还是大大的有的 :)