Linux 2.6内核,嵌入式系统的福音?陷阱?
Linux 2.6内核性能评估报告

作者 Ray

RTEMS版权所有,转载请注明:来源 http://www.rtems.net,作者 ray@rtems.net

        笔者受公司委托对 2.6 的内核作了一个性能评估,评测的对象包括进程切换性能,线程切换性能,网络性能,内存读取速度,文件系统性能几个方面。结果表明,在工作站的模式下 2.6 的内核大多数指标比不上 2.4 内核的性能。在服务器模式下, 2.6 内核才开始有优势。同时,本文使用 FreeBSD 作为参照比较对象。

   

Linux2.6 内核的新特性

网上不少文章介绍了2.6内核的新特性,这里我就照搬过来。

内存管理

1 .抢占式内存

2.6 版本以前的 Linux 内核是不允许对一个被系统调用并处于运行状态的进程进行调度的。这意味着一旦系统调用中有某个任务正在执行,那么该任务会控制处理器直到系统调用结束,而 不管其使用处理器时间的长短。(2.4是分时的,为什么网上的系统说“直到系统调用结束” ??)

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

实际上,测试表明抢占内核使工作站环境下的应用程序速度变慢。

2 .引入内存池机制

2.6 版内核的开发过程引入了内存池以满足不间断地进行内存分配。其思想是预先分配一个内存池,并保留到真正需要的时候。 哈哈,其结果是系统一启动,大量的内存就没有了。

3 .改善虚拟内存

2.6 版内核改善了虚拟内存在一定程度负载下的性能。 通过反向地址映射减少了系统的开销。

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 版内核中,驱动程序如果要从一个设备上发出中断需要返回 IRQ_HANDLED ,否则返回 IRQ_NONE 。这样可以帮助内核的 IRQ 层清楚地识别出哪个驱动程序正在处理哪个特定的中断。 如果一个中断请求不断到来,而且没有注册那个设备的处理程序,内核就会忽略来自该设备的中断。

2 .驱动程序移植

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

内核模块加载器也在 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 AMD XP 2500+ / Intel PV 3G (HT支持)

2 DDR RAM 256M 333Mhz

2 硬盘 Maxtor 40G 7200rpm/s

2 主板 MSI KT4AV

2 100M 以太网卡

软件

2 GCC 3.4.2

2 Slackware 10.1

2 文件系统 ReiserFS

参考平台

FreeBSD5.3

比较对象;

2 kernel 2.4.29

2 kernel 2.6.10

2 FreeBSD 5.3

说明:

所有内核都根据平台属性重新编译

测试工具

2 lmbench 用于系统性能整体测试

2 forkbomb 进程压力测试

2 Netperf 网路性能测试

Linux 2.6 编译

首先获取最新的 kernel 代码

linux-2.6.10.tar.bz2

解压源代码

tar zjvf linux-2.6.10.tar.bz2

进行配置:

make xconfig

测试使用 SSH 客户端在字符界面下进行。

比较结果

内核的大小

根据机器的硬件状况重新编译了内核,编译的结果如下:(未压缩)

启动内存大小

系统启动后,开启了12路的VoIP网关程序。结果,内存的消耗状况如下,大家不要害怕,这还能称为嵌入式系统吗?

线程创建速度

pthread 线程创建测试, BSD 是绝对的赢家,几乎不需要时间

内存访问速度

内存访问测试,三者速度差多,整体来看 2.4 快于 bsd 快于 2.6

文件访问

文件访问速度 BSD>2.4>2.6

网络流量

网络速度: BSD 明显优势

socket 创建速度

socket 函数创建的时间: BSD 优于 2.6 优于 2.4

bind 函数访问时间

在小负载下,三者表现比较接近,时间是常数在大负载下 2.4.29 变慢

bind 函数平均时间 ()

(3000socket)

(10000socket)

2.4.29

O(1)

O(n)

2.6.10

O(1)

O(1)

FreeBSD5.3

O(1)

O(1)