cnhnln 发表于 2004-5-10 23:14:12

开发人员眼中的Linux 2.6内核

开发人员眼中的Linux 2.6内核
作者:李庆明 张静 发文时间:2004.05.10

Linux 2.6内核的推出,无论是巩固Linux在服务器领域的主流地位,还是推进它在桌面操作系统领域的推广进程,都将起到不可估量的作用。开发人员更应从深层次的角度来考察Linux 2.6内核为应用开发带来的新变化。

内核是一个操作系统最核心的部分,它完成操作系统最基本的功能,包括进程调度、磁盘管理、设备管理、网络管理等,其实现算法或方式的优劣将直接影响到整个操作系统的性能,甚至未来在该操作系统上开发的应用程序的性能。

那么对于开发人员,新内核中的哪些特性需要特别关注呢?

内存

1.抢占式内存

和其它大多数操作系统一样,2.6版本以前的Linux内核是不允许一个被系统调用并处于运行状态的进程进行调度的。这意味着一旦系统调用中有某个任务正在执行,那么该任务会控制处理器直到系统调用结束,而不管其使用处理器时间的长短。这种设计简单,但在很多时候会导致一些重要任务在等待系统调用完成的过程中被耽搁。

2.6版内核中内存是可抢占的。这将显著地降低用户交互式应用程序、多媒体应用程序等类似程序的延迟。这一特性对实时系统和嵌入式系统来说特别有用。

可抢占式内存使Linux 2.6内核在一些时效性较强的事件中比2.4版内核具有更好的响应能力。为实现抢占式内存,Linux 2.6内核中的代码被设置了抢占点,这意味着调度程序会中止正在运行的进程,而来执行优先级更高的进程。在系统调用过程中,Linux 2.6内核会定时地检查抢占点,以避免不合理的延迟发生。而在检查过程中,调度进程很可能就会中止当前进程来让另一个进程运行。

不是所有的内核代码段都可以被抢占。用户可以锁定内核代码的关键部分,不允许其被抢占。锁定可以确保每个CPU的数据结构和状态始终受到保护而不被抢占。

2.引入内存池机制

2.6版内核的开发过程引入了内存池以满足不间断地进行内存分配。其思想是预先分配一个内存池,并保留到真正需要的时候。

3.改善虚拟内存

2.6版内核融合了Rik van Riel的r-map(Reverse Mapping,反向映射)技术,将显著改善虚拟内存在一定程度负载下的性能。

Linux内核工作于虚拟内存模式时,每一个虚拟页对应一个相应系统内存的物理页。虚拟页和物理页之间的地址转换由硬件页表来完成。但是这种“虚拟到物理”的页映射不总是一一对应的,多个虚拟页有可能指向同一个物理页。这种情况下,内核想要释放特定的物理页就必须遍历所有的进程页表记录来查找指向这个物理页的引用,只有在引用数达到0时才能释放该物理页。负载较高时,这会让虚拟内存变得非常慢。

反向地址映射补丁通过在结构页引入一个叫做pte_chain的数据结构来解决这一问题。

不过,这种方法存在一个指针开销问题。系统中的每一个结构页都必须有一个额外的、用于pte_chain的结构。一个256MB内存的系统有64K个物理页,这就需要有64KB*(sizeof(struct pte_chain))的内存被分配用于pte_chain的结构,这是一个很可观的数字。

尽管如此,r-map的性能,尤其是高负载的高端系统,相对于2.4版内核的虚拟内存系统还是有了显著地提高。

4.共享内存的改进

对于嵌入式系统开发人员而言,嵌入式系统往往是一个有多个处理器的设备,比如电信网络或大型存储系统中都是如此。不论是均衡或是松散连接的多处理器,一般都是共享内存的。均衡多进程的设计使所有的处理器都对内存有均等使用权,而限制使用内存的决定性因素是进程的效率。

Linux 2.6内核为多程序提供了一种不同的途径,即NUMA(Non Uniform Memory Access)。这种方法中,内存和处理器是相互连接的,但对于每一个处理器,某些内存是“关闭”的,而某些内存则“更远”。这意味着当内存竞争出现时,“更近”的处理器对就近的内存有更高的使用权。2.6版内核提供了一套功能来定义内存和处理器之间的拓扑关系。调度程序可以利用这些信息来为任务分配本地内存。这样将减少内存竞争造成的瓶颈,提高吞吐量。

驱动程序

1.中断例程的改进

2.6版内核的中断处理程序内部经历了许多变化,但是绝大部分对于普通的驱动程序开发者来说没有影响。不过,还是有一些重要的变化会影响到驱动程序开发者。在2.6版内核中,驱动程序如果要从一个设备上发出中断需要返回IRQ_HANDLED,否则返回IRQ_NONE。这样可以帮助内核的IRQ层清楚地识别出哪个驱动程序正在处理哪个特定的中断。

如果一个中断请求不断到来,而且没有注册那个设备的处理程序,内核就会忽略来自该设备的中断。

2.驱动程序移植

相对于2.4版内核来说,2.6版内核改进了内核编译系统,从而获得更快的编译速度。2.6版内核的编译系统加入了改进的图形化工具make xconfig(需要Qt库)和make gconfig(需要Gtk库)。

内核模块加载器也在2.6版内核中被完全实现,使得模块编译机制相对于2.4版内核有了很大的不同。原来2.4版内核中的模块工具不能用来加载或卸载2.6版内核的模块,需要一组新的模块工具来完成模块的加载和卸载。这个新的模块加载工具会尽量减少在一个设备仍被使用的情况下,相应的模块却被卸载的冲突发生,而是在确认这些模块已经没有任何设备在使用后再卸载掉。产生这种冲突的原因之一是,模块使用计数是由模块代码自己来控制的。在2.6版内核中,模块不再需要对引用计数进行加减,这些工作将在模块代码外部进行。

进程管理

1.新调度器算法

2.6版本的Linux内核使用了新的调度器算法,称为O(1)算法,它在高负载的情况下执行得非常出色,并在有多个处理器时能够很好地扩展。

2.4版本的调度器中,时间片重算算法要求在所有的进程都用尽它们的时间片后,新时间片才会被重新计算。在一个多处理器系统中,当进程用完它们的时间片后不得不等待重算,以得到新的时间片,从而导致大部分处理器处于空闲状态,影响SMP的效率。此外,当空闲处理器开始执行那些时间片尚未用尽的、处于等待状态的进程时,会导致进程开始在处理器之间“跳跃”。当一个高优先级进程或交互式进程发生跳跃时,整个系统的性能就会受到影响。

新调度器解决上述问题的方法是,基于每个CPU来分布时间片,并取消全局同步和重算循环。调度器使用了两个优先级数组,即活动数组和过期数组,可以通过指针来访问它们。活动数组中包含所有映射到某个CPU且时间片尚未用尽的任务。过期数组中包含时间片已经用尽的所有任务的有序列表。如果所有活动任务的时间片都已用尽,那么指向这两个数组的指针互换,包含准备运行任务的过期数组成为活动数组,而空的活动数组成为包含过期任务的新数组。数组的索引存储在一个64位的位图中,所以很容易找到最高优先级的任务。

新调度器的主要优点包括:

◆ SMP效率 如果有工作需要完成,所有处理器都会工作。

◆ 等待进程 没有进程需要长时间地等待处理器,也没有进程会无端地占用大量的CPU时间。

◆ SMP进程映射 进程只映射到一个CPU,而且不会在CPU之间跳跃。

◆ 优先级 非重要任务的优先级低,反之亦然。

◆ 负载平衡 调度器会降低那些超出处理器负载能力的进程的优先级。

◆ 交互性能 即使在高负载的情况下,系统花费很长时间来响应鼠标点击或键盘输入的情况也不会再发生。

2.高效的调度程序

2.6版内核中,进程调度经过重新编写,调度程序不需每次都扫描所有的任务,而是在一个任务变成就绪状态时将其放到一个名为“当前”的队列中。当进程调度程序运行时,只选择队列中最有利的任务来执行。这样,调度可以在一个恒定的时间里完成。当任务执行时,它会得到一个时间段,或者在其转到另一线程之前得到一段时间的处理器使用权。当时间段用完后,任务会被转移到另一个名为“过期”的队列中。在该队列中,任务会根据其优先级进行排序。

从某种意义上说,所有位于“当前”队列的任务都将被执行,并被转移到“过期”队列中。当这种事情发生时,队列就会进行切换,原来的“过期”队列成为“当前”队列,而空的“当前”队列则变成“过期”队列。由于在新的“当前”队列中,任务已经被排列好,调度程序现在使用简单的队列算法,即总是取当前队列的第一个任务进行执行。这个新过程要比老过程快得多。

3.新的同步措施

多进程应用程序有时需要共享一些资源,比如共享内存或设备。为了避免竞争的出现,程序员会使用一个名为互斥的功能来确保同一时刻只有一个任务在使用资源。到目前为止,Linux还是通过一个包含在内核中的系统调用来完成互斥的实现,并由该系统调用决定一个线程是等待还是继续执行。

Linux 2.6内核支持FUSM(Fast User-Space Mutex)。这个新功能会检查用户的空间,查看是否有等待的情况出现,并且只有在线程需要等待时才进行系统调用。这样当不需要等待时,就会避免不必要的系统调用,以节约时间。该功能也使用优先级调度,以便在出现竞争时决定哪一个线程可以被执行。

综上所述,2.6版内核对于开发人员提供了更加快捷、方便的接口,从而可以开发出更加快速、高效的应用。同时,2.6版内核也解决了一些在2.4版内核中因为内核瓶颈造成的不便,比如实时性问题等。Linux还会不断地发展,这也将促使应用开发不断地发展进步。
页: [1]
查看完整版本: 开发人员眼中的Linux 2.6内核