Linux实验总结分析报告:从系统的角度分析影响程序执行性能的因素
前言
感谢孟老师和李老师在这门课中对我的教导,让我受益匪浅,对Linux内核基本结构和工作原理有了更深层次的认识,
学到了很多,再次感谢两位老师。
一、精简的Linux系统的概念模型
冯·诺依曼体系结构如图所示,其中运算器、存储器、控制器、输入设备和输出设备5大基本类型部件组成了计算机硬件;
核心是CPU,与内存和输入输出(I/O)设备进行交互,是整个计算机的灵魂、大脑。内存则是存放了指令和数据,二者
皆以二进制形式存放。输入输出设备则包括鼠标、键盘、显示器与磁盘等等设备,是计算机与外界进行交互的工具。
二、计算机的“三大法宝”和操作系统的“两把宝剑”
- 三大法宝
-
存储程序:指令和数据以二进制形式存储在内存中
-
堆栈:函数调用是基于堆栈实现的,栈在程序运行中具有举足轻重的地位。栈保存了一个函数调用所需要的维护信息,被称之为堆栈帧或活动记录
-
中断:是实现程序并发执行的基础
-
- 两把宝剑
-
中断上下文:硬件通过中断触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。中断上文可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被中断的进程环境。
-
进程上下文:其是指进程由用户态切换到内核态是需要保存用户态时cpu寄存器中的值,进程状态以及堆栈上的内容,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。
-
三、Linux内核
-
Linux内核体系结构
-
简析
最上面是用户(或应用程序)空间。这是用户应用程序执行的地方。用户空间之下是内核空间,Linux 内核正是位于这里。GNU C Library (glibc)也在这里。它提供了连接内核的系统调用接口,还提供了在用户空间应用程序和内核之间进行转换的机制。这点非常重要,因为内核和用户空间的应用程序使用的是不同的保护地址空间。每个用户空间的进程都使用自己的虚拟地址空间,而内核则占用单独的地址空间。
Linux 内核可以进一步划分成 3 层。最上面是系统调用接口,它实现了一些基本的功能,例如 read 和 write。系统调用接口之下是内核代码,可以更精确地定义为独立于体系结构的内核代码。这些代码是 Linux 所支持的所有处理器体系结构所通用的。在这些代码之下是依赖于体系结构的代码,构成了通常称为 BSP(Board Support Package)的部分。这些代码用作给定体系结构的处理器和特定于平台的代码。
四、进程管理
进程状态转换图
进程管理的重点是进程的执行。在内核中,这些进程称为线程,代表了单独的处理器虚拟化(线程代码、数据、堆栈和 CPU 寄存器)。在用户空间,通常使用进程 这个术语,不过 Linux 实现并没有区分这两个概念(进程和线程)。内核通过 SCI 提供了一个应用程序编程接口(API)来创建一个新进程(fork、exec 或 Portable Operating System Interface [POSIX] 函数),停止进程(kill、exit),并在它们之间进行通信和同步(signal 或者 POSIX 机制)。
进程管理还包括处理活动进程之间共享 CPU 的需求。内核实现了一种新型的调度算法,不管有多少个线程在竞争 CPU,这种算法都可以在固定时间内进行操作。这种算法就称为 O(1) 调度程序,这个名字就表示它调度多个线程所使用的时间和调度一个线程所使用的时间是相同的。O(1) 调度程序也可以支持多处理器(称为对称多处理器或 SMP)。您可以在 ./linux/kernel 中找到进程管理的源代码,在 ./linux/arch 中可以找到依赖于体系结构的源代码。
五、中断和异常
中断何和异常是指明系统、处理器或当前执行程序(或任务)的某处出现一个事件,该事件需要处理器进行处理。通常,这种事情会导致执行控制器被强迫从当前运行程序转移到被称为终端处理程序或异常处理程序的特殊软件函数或任务中。处理器响应中断或异常所采取的行动称为中断/异常服务(处理)。
通常中断发生在程序执行的随机时刻,以响应硬件发出的信号。系统硬件使用中断来处理外部事件,例如要求为外部设备提供服务。当然,软件也能通过执行 INT n 指令产生中断。
异常发生在处理器执行一条指令时,检测到一个出错条件时发生,例如被0除出错条件。处理器可以检测到各种出错条件,包括违反保护机制。页错误以及机器内部错误。对应用程序来说,80x86的中断和异常处理机制可以透明地处理发生的异常和中断事件。当收到一个中断或检测到一个异常时,处理器会自动把当前正在正在执行的程序或任务挂起,并开始运行中断或异常处理程序。当处理程序执行完毕,处理器就会恢复并继续执行被中断的程序或任务。被中断程序的恢复过程并不会失去程序执行的连贯性,除非从异常中恢复是不可能的或者中断异常导致当前运行程序被终止。
六、内存管理
内核所管理的另外一个重要资源是内存。为了提高效率,如果由硬件管理虚拟内存,内存是按照所谓的内存页 方式进行管理的(对于大部分体系结构来说都是 4KB)。Linux 包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。不过内存管理要管理的可不止 4KB 缓冲区。Linux 提供了对 4KB 缓冲区的抽象,例如 slab 分配器。这种内存管理模式使用 4KB 缓冲区为基数,然后从中分配结构,并跟踪内存页使用情况,比如哪些内存页是满的,哪些页面没有完全使用,哪些页面为空。这样就允许该模式根据系统需要来动态调整内存使用。为了支持多个用户使用内存,有时会出现可用内存被消耗光的情况。由于这个原因,页面可以移出内存并放入磁盘中。这个过程称为交换,因为页面会被从内存交换到硬盘上。内存管理的源代码可以在 ./linux/mm 中找到。
七、虚拟文件系统
虚拟文件系统(VFS)是 Linux 内核中非常有用的一个方面,因为它为文件系统提供了一个通用的接口抽象。VFS 在 SCI 和内核所支持的文件系统之间提供了一个交换层
在 VFS 上面,是对诸如 open、close、read 和 write 之类的函数的一个通用 API 抽象。在 VFS 下面是文件系统抽象,它定义了上层函数的实现方式。它们是给定文件系统(超过 50 个)的插件。文件系统的源代码可以在 ./linux/fs 中找到。文件系统层之下是缓冲区缓存,它为文件系统层提供了一个通用函数集(与具体文件系统无关)。这个缓存层通过将数据保留一段时间(或者随即预先读取数据以便在需要是就可用)优化了对物理设备的访问。缓冲区缓存之下是设备驱动程序,它实现了特定物理设备的接口。
八、影响程序执行性能的因素
- 源代码因素
源代码因素主要指必须通过修改代码才可以解决或者缓解的问题。
- 全局变量初始化。这一部分在main函数之前完成,程序的全局变量或者其构造函数过多会占用大量的CPU时间。
- 代码自身消耗CPU。代码低效,或者IO问题,可以通过定位之后加以优化。
- 无用代码呆滞可执行文件过大,增加加载负荷。
- 动态链接库因素
系统加载一个动态链接库需要一个固定的时间消耗,所以库的数量越大,占用的这部分时间就越多;
系统的IO以页为单位,库的大小越大,从库总载入有效代码的准确性就越低,导致IO操作的几率就越高,占用的时间也越多;
启动过程的动态链接库个数越少越好,大小越小越好。
- 代码调用引发缺页导致IO。动态库函数按照物理顺序排列,而分散的调用将导致缺页从而引起IO操作。
- 动态链接库符号的可见性。动态链接库导出过多的课件符号,加载器在匹配时将消耗过多的IO/CPU。
- 配置文件/资源文件因素
启动部分的代码频繁访问配置文件/资源文件从而导致IO过多,或者不同时间分次访问这些文件从而导致IO操作分散而不能有效利用硬盘的连续访问,导致性能下降。