设为首页 收藏本站
查看: 1816|回复: 0

[经验分享] Linux KVM代码之美

[复制链接]

尚未签到

发表于 2015-4-10 19:18:33 | 显示全部楼层 |阅读模式
  edited as an essey for 程序语言设计原理
  
  在程序的编写上,我认为编程的难度,也就是可写性是一个次要的角色,而代码的可读性,可维护性一直软件生命周期中的主要部分,尤其是对于大型项目而言,软件的维护绝对是项目管理人员首先要考虑的问题,成本的控制,人月量的降低。在这一点上更为突出表现的我想应该是对于开源项目来说,人员的流动性大,项目时间的不确定性,还有对开发人员的吸引力。开源项目应该关注的不止是软件功能性的强大,思维理念的超前,更应该是代码的可读性,可维护性。毕竟没有人愿意在垃圾场上重新盖一栋漂亮的大楼。所以开源项目应该从一开始就在可读性,可维护性上下工夫,并且需要有一些自己的理念,开发标准在里面,这样可以引导后来的开发人员遵循这些原则,保证代码的可读性,可维护性,避免出现破窗效应。
那么如此看来,代码之美又应该包括哪些方面呢,我想应该需要有程序的可读性,可维护性,另外还需要有一些设计准则。这里就以Linux内核中的KVM代码部分为例,谈谈这些原则。

一、可读性、可维护性
在Github上打开Linux内核代码,涉及KVM的主要有两个目录,virt和arch/x86/kvm,我们主要研究的是arch/x86/kvm。文件夹下的Makefile和Kconfig文件可以将程序的脉络显得极为的清晰。
现在查看的是emulate.c文件,程序大概有4000多行,这也是C语言代码中值得诟病的地方,因为程序代码超过2页屏幕大小后,会影响人们对程序的理解,难于找到需要注意的地方,并且纠结于大量的方法和结构体之间。
emulate.c的文件头注释表明只是一个X86架构(32位或者64位)指令的译码器和模拟器,并且表明程序的作者,来源,程序具体涉及的方面。代码是遵循Linux编码规范的。
包括8个字符缩进,把长的行和字符串打散,大括号和空格的放置,命名规范等。在Linux内核中Documentation/CodingStyle文件中有句话表明这些规范的用处“代码风格的意义就在于使用平常使用的工具来维持代码的可读性和可维护性”,无需特别的编辑器,只需要一个普通的文本编辑器就可以了。这些规范十分有利于读者理解和修改代码,例如不超过80列的代码长度使得函数体中的形式参数不会显得拥挤不堪,分不清个数。如图1中这样的例子在这4000行代码中俯拾皆是,极大的提高了可读性。
DSC0000.png
  图1
可能是得益于C语言设计的简单性和正交性,我在Linux代码中很少看到有3层以上的嵌套,代码的逻辑大多数可以在最多2层的嵌套中完成。并且程序的控制语句可以将代码的逻辑部分清晰的展现出来,无需过多的升入理解。另外,程序中的注释部分所占的比例也不会很大,不会出现注释数量比代码数量还要多的情况,并且注释部分十分的简短精细。这表明对程序片段的理解无需额外的添加注释,只是凭借代码的逻辑结构和命名就可以很好的理解代码,而且注释的语言不会显得赘述,只是简单扼要的解释片段功能或逻辑。例如图2中的情形,复杂的位操作尽管提高了效率,可是难以理解,这时就需要注释来帮助解释。
DSC0001.png
图 2
可读性在很多的时候是与可维护性相关联的,程序写出来很大一部分原因就是为了维护,而强可读性对于程序的理解至关重要,特别是人员流动性强的时候,而语言的特性和优秀的代码规范是可读性的保证,Linux内核代码在这两方面都做得非常好,拥有Documentation/CodingStyle这样的编程规范,还有C语言这样的高级程序设计语言。从另一方面来说,可读性强也同时意味着可写性强,因为在编写程序的过程中,编程人员需要不断地阅读已经编写的程序部分。

二、设计准则

1. 频度准则
越常用越简单,包括命名,和函数体。例如在模拟器的缓存表写入时有两个函数体,一个reg_write,另外一个为writeback_registers。表示的意思一个为写入,另外一个是回写,这个是对应于Cache的不同存取机制的,显然第一个较为常用,所以在命名上面会比第二个简略一些。
而对于更为常用的函数来说,例如一些简单的位运算,kvm将这些函数当做预编译的部分,放在函数开头。如下图3,就表示一个栈的指令移动,在代码中频繁的出现则用预编译函数来表示。并且有一些函数使用了内联的方法来提高性能,这些函数往往是另外一个复杂或者多次使用的函数的一部分,所以内联的函数函数体都比较简单,拥有一个描述性的名字,并且作用通常是作为辅助函数。
DSC0002.png
图 3

2. 结构一致
结构一致表示的是程序结构和计算的逻辑结构一致。Kvm代码可以体现出自顶向下、逐步求精的思想,复杂问题,往往有一个总体的引导性函数,然后会由一些子函数,辅助函数来作为过渡,逐步细化地解决问题。上文提到的一些预编译函数,内联函数就是起到这样的作用的。
并且在程序中使用了大量的条件语句,循环语句,返回语句,可以很容易的把握程序结构和计算的逻辑结构的一致性。另外不得不提的一点是,kvm代码中并没有摒弃goto语句的使用,一开始基于老师们和专家们的建议“不要使用goto语句”,我对这些代码有着很大的反感,但是仔细阅读后发现使用GOTO语句,会使程序流程更清楚、效率更高。
例如图4中,代码清晰的表示了获取操作数后处理器将要做得事情,程序的结构和计算逻辑是一致的,并不存在什么晦涩难懂的部分。
DSC0003.png
图 4
3. 局部性
C语言是不鼓励使用全局变量的。在emulator.c的代码中我也并未有发现全局变量的使用。代码规范里头对全局变量的描述是“只有当你真正需要它们的时候再用它”。并且对于局部变量的使用它是有标准的:“函数的另外一个衡量标准是本地变量的数量。此数量不应超过5-10个,否则你的函数就有问题了”。
kvm代码中函数的局部变量都很少,并且命名十分的简洁,一般为2-3个字母,是放在一块儿申明的。声明完后空一行,开始函数的逻辑部分。
4. 词法内聚
词法内聚是变量在使用处就近声明。这一点要看使用处的定义,因为kvm中变量的声明是放在一块的,对于函数来说,是在使用处定义。但如果把使用处定义为使用变量的具体位置,表达式或判断赋值语句,那么kvm代码中的变量声明就不是词法内聚了。
三、总结
总的来说Linux内核代码所带来的标准已经影响了很多从业人员,并且正在成为C语言代码的标准规范。这个规范是从Brian Kernighan和Dennis Ritchie开始的,也就是著名的经典C,并且经历了C90、C99标准,根据不同的需求在变化着,修改着。我所看到的这个CodingStyle是在两天前 Joe Perches提交的,添加了网络块的评论规范。
但是这些修改变化,有一个共同的目标就是使linux内核代码能够看起来更加的舒适,理解起来更容易,并最终做到可写性和维护性。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-55831-1-1.html 上篇帖子: disable the kvm 下篇帖子: kvm 虚拟机
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表