然后将一个应用程序放入该系统模型中系统性的梳理影响应用程序性能表现的因素,并说明原因。
精简Linux系统概念模型
Linux 是一个基于POSIX的多用户、多任务、支持多线程和多CPU的操作系统。Linux系统一般有这几主要部分:内核、shell、文件系统。它们一起形成了基本的操作系统结构,使得用户可以运行程序、管理文件并使用系统。
1. 内核是操作系统的核心,具有很多最基本功能,它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。内核由如下几部分组成:内存管理、进程管理、设备驱动程序、文件系统、网络管理 等。
2. shell是系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行,是一个命令解释器。另外,shell编程语言具有普通编程语言的很多特点,用这种编程语言编写的shell程序与其他应用程序具有同样的效果。
3. 文件系统是文件存放在磁盘等存储设备上的组织方法。Linux的一大特点就是 万物皆可看作文件,即使是硬件资源也看做文件进行操作。
文件系统
由一个单独的实体来代表。Linux采用树型结构。最上层是根目录,其他的所有目录都是从根目录出发生成。完整的目录树可划分为小的部分,这些小部分又可以单独存放在自己的磁盘或分区上。
文件系统通常会将“文件权限(rwx)”与“文件属性(拥有者、群组、时间参数等)”这两部份的数据分别存放在不同的区块,权限与属性放置到 inode 中,实际数据放置到 data block 。
超级块(Superblock): 这是整个文件系统的第一块空间。包括整个文件系统的基本信息,如块大小,inode/block的总量、使用量、剩余量,指向空间 inode 和数据块的指针等相关信息。
inode块(文件索引节点) : 文件系统索引,记录文件的属性。它是文件系统的最基本单元,是文件系统连接任何子目录、任何文件的桥梁。每个子目录和文件只有唯一的一个 inode 块。它包含了文件系统中文件的基本属性(文件的长度、创建及修改时间、权限、所属关系)、存放数据的位置等相关信息. 在 Linux 下可以通过 “ls -li” 命令查看文件的 inode 信息。硬连接和源文件具有相同的 inode 。
数据块(Block) :实际记录文件的内容,若文件太大时,会占用多个block。为了提高目录访问效率,Linux还提供了表达路径与inode对应关系的dentry结构。它描述了路径信息并连接到节点inode,它包括各种目录信息,还指向了inode和超级块。
Linux 将新的文件系统通过一个称为“挂装”或“挂上”的操作将其挂装到某个目录上,从而让不同的文件系统结合成为一个整体。 Linux 支持许多不同的文件系统,并且将它们组织成了一个统一的虚拟文件系统(VirtualFileSystem,VFS):隐藏了各种硬件的具体细节,把文件系统操作和不同文件系统的具体实现细节分离了开来,为所有的设备提供了统一的接口。虚拟文件系统可以分为逻辑文件系统和设备驱动程序。逻辑文件系统指Linux所支持的文件系统,如ext2,fat等,设备驱动程序指为每一种硬件控制器所编写的设备驱动程序模块。VFS在用户和文件系统之间提供了一个交换层。因此,用户和进程不需要知道文件所在的文件系统类型,而只需要象使用 Ext2 文件系统中的文件一样使用它们。
在 VFS 之上是,是对诸如 open、close、read 和 write 之类的函数的一个通用 API 抽象。在 VFS 下面是文件系统抽象,它定义了上层函数的实现方式。它们是给定文件系统(超过 50 个)的插件。文件系统的源代码可以在 ./linux/fs 中找到。
Linux内核的VFS子系统可以图示如下:file、dentry、inode、super_block这几个结构体组成了VFS的核心概念。
每个进程在PCB(Process Control Block)中都保存着一份文件描述符表,每个表项都有一个指向已打开文件的指针:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。
进程管理
进程是某特定应用程序的一个运行实体。Linux 能通过在短时间间隔内轮流运行这些进程而实现“多任务”。这一短的时间间隔称为“时间片”,让进程轮流运行的方法称为“进程调度” ,完成调度的程序称为调度程序。
Linux的进程有6种状态:new(初始状态,刚创建的一个进程,需要等待被调度)Runnable(就绪状态)RUNNING(可执行状态)Sleeping(睡眠状态)STOPPED(暂停状态)ZOMBIE(退出状态,进程成为僵尸进程)
进程调度有几种常用方法:先来先服务,短作业优先,高优先权优先,高响应比优先
进程的切换大概有两步组成:1.切换页全局目录以安装一个新的地址空间。2.切换内核态堆栈和硬件上下文。
内存管理
Linux 采用“虚拟内存”的内存管理方式。将内存划分为容易处理的“内存页”(对于大部分体系结构来说是 4KB)。页面可以移出内存并放入磁盘中。这个过程称为交换。Linux 包括了管理可用内存的方式,以及物理和虚拟映射所使用的硬件机制。内存管理的源代码可以在 ./linux/mm 中找到。
设备驱动
设备驱动程序实际控制操作系统和硬件设备之间的交互,是 Linux 内核的主要部分,运行在高特权级的处理器环境中,从而可以直接对硬件进行操作。
网络接口
Linux内核的网络部分由BSD套接字、网络协议层和网络设备驱动程序组成。提供了对各种网络标准的存取和各种网络硬件的支持。网络协议部分负责实现每一种可能的网络传输协议。支持 BSD 套接字,支持全部的TCP/IP协议。
中断
CPU的指令中有危险的’特权指令‘,这些指令只有在’内核态‘才有权限执行(否则可能造成不可预料的灾难)。中断 就是从用户态进入内核态的主要方式。
中断可分为外部中断和内部中断,其中内部中断主要是在用户进程执行时,硬件中断信号到达,导致进入内核态,执行对应的中断服务程序,内部中断主要是包括故障和陷阱两部分。
中断执行过程:
中断源发出中断请求
确定与中断或异常相关联的向量 i
读取 idtr 寄存器的值,找到 IDT 的基址,通过查询 IDT,找到 第 i 项对应的内容。
从 gdtr 寄存器获得 GDT的基地址,并在 GDT 中查找,以读取 IDT 表项中的段选择符所标识的段描述符。
确定中断是由授权的发生源发出的。
中断:需要比较 CPL 和 GDT中的 DPL。中断处理程序的特 权不能低于引起中断的程序的特权。
编程异常:需要比较 CPL 和 IDT中的 DPL。
检查是否发生了特权级的变化,一般指的是用户态陷入内核 态。
如果是用户态陷入内核态,控制单元要使用新的特权级堆栈。
保存 ss和 esp,并用新的堆栈的值填充。
如果是故障,用引起故障的指令修改 cs 和 eip,以便异常处理 后再次执行。
在堆栈中保存 eflags/cs/eip 的内容。
如果有硬件出错码,则保存。
使用 IDT 中第 i 项中的段描述符和偏移量填充 cs 和 eip。
最后恢复被保护的状态,执行“中断返回”指令回到被中断的程序或转入其他程序。
举例:
文件的读写过程:
进程调用库函数发起读写文件请求,内核检查进程的文件描述符,定位到虚拟文件系统的已打开文件列表表项。调用sys_read()函数,找到该文件的inode。在inode中,通过文件内容偏移量计算出要读取的页,找到文件对应的address_space。
如果是读取,且页缓存命中,直接返回文件内容。如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页;重新进行 查找页缓存。
如果是写入,且页缓存命中,直接把文件内容修改更新在页缓存的页中。这时候文件修改位于页缓存,还没有写回到磁盘文件中去。如果页缓存缺失,那么产生一个页缺失异常,创建一个页缓存页,同时通过inode找到文件该页的磁盘地址,读取相应的页填充该缓存页。此时缓存页命中,可以写入了。最后,一个页缓存中的页如果被修改,就会被标记成脏页。脏页需要写回到磁盘中的文件块。有两种方式:1. 手动调用sync()或者fsync()系统调用把脏页写回。2. pdflush进程会定时把脏页写回到磁盘
影响应用程序性能表现的因素
计算机系统的硬件层面:
硬盘与内存互相读写时,硬盘的持续传输速度,随机小文件(4K)传输速度,延迟等。
内存的容量,频率,时序,带宽,延迟等。
CPU的频率,IPC(Instruction Per Clock),核心数,缓存等。以及程序可能用到的各种额外计算硬件如GPU,TPU,乃至各种专用集成电路ASIC的性能,延迟等。
连接各硬件的PCI总线接口的速度也很可能成为瓶颈。
网卡的吞吐量,网络的带宽和延迟等。
软件层面:
操作系统对于各种硬件资源的调度的合理性,各硬件的驱动程序对硬件性能的发挥,
在多核心CPU上,实现了多线程运行的程序会比单线程要快,使用的处理器指令集会影响性能表现,程序本身的代码的优化(包括编译器的优化)在数据的组织和计算处理上会影响性能表现。
对于一个特定的程序,操作系统给它的优先级不同也会影响性能表现。它的性能瓶颈往往出现在这个程序会大量使用的资源上,比如cpu计算密集,或网络带宽敏感,或硬盘IO密集等