实验总结分析报告
——从系统的角度分析影响程序执行性能的因素
1、请您根据本课程所学内容总结梳理出一个精简的Linux系统概念模型,最大程度统摄整顿本课程及相关的知识信息,模型应该是逻辑上可以运转的、自洽的,并举例某一两个具体例子(比如读写文件、分配内存、使用I/O驱动某个硬件等)纳入模型中验证模型。
2、然后将一个应用程序放入该系统模型中系统性的梳理影响应用程序性能表现的因素,并说明原因。
一、精简的Linux系统概念模型
Linux系统概念模型可以分为四部分:内核,shell,系统调用,用户程序。
(一)Linux内核
Linux内核,主要有以下几个功能模块:中断管理,时钟管理,进程管理、内存管理、文件系统等
1.中断管理
(1)中断概念
简而言之,中断就是CPU把当前的任务先放一放,然后去执行其他任务,完成后再返回执行原来的任务。
(2)中断类型
1. 外部中断:外设引起的中断
2. 内中断:也称为异常,可分为陷入和故障。
2.时钟管理
x86体系的Linux中,主要用到了三种时钟:实时时钟RTC、时间戳计数器TSC及可编程间隔定时器PIT。其主要作用是:
1. 记录系统时间。很多应用程序需要知道日期和时间、由日期和时间构成的时间戳也会被打在文件上面、等等;
2. 统计功能。如top之类的用户程序可以查看一段时间内的系统负载、以及各个进程占用CPU的时间、等等;
3. 定时功能。很多用户程序会使用到定时器,比如sleep一段时间后做某件事情、比如给select设置一个超时时间、等等;
3.进程管理
(1)进程的概念
简而言之,进程就是程序执行的过程。数据结构struct task_struct是描述进程的,保存了程序执行过程中的一些必要信息,如进程的id,进程的状态,堆栈等。
(2)进程的创建
⽗进程通过fork系统调⽤进⼊内核 do_fork函数,复制进程描述符及相关进程资源(采⽤写时复制技术)、分配⼦进程的内核堆栈并对内核堆栈和thread等进程关键上下⽂进⾏初始化,最后将⼦进程 放⼊就绪队列,fork系统调⽤返回;
⽽⼦进程则在被调度执⾏时根据设置的内核堆栈和thread等进程关键上下⽂开始执⾏。
(3)进程切换
1. 切换⻚全局⽬录(CR3)以安装⼀个新的地址空间,这样不同进程的虚拟地 址如0x8048400(32位x86)就会经过不同的⻚表转换为不同的物理地址。
2. 切换内核态堆栈和进程的CPU上下⽂,因为进程的CPU上下⽂提供了内核执 ⾏新进程所需要的所有信息,包含所有CPU寄存器状态。
(4)进程调度
进程调度的时机:
1. 进程状态发生变化时。
2. 当前进程时间片用完。
3. 进程从系统调用返回到用户态。
4. 中断处理后,进程返回到用户态。
4.内存管理
Linux把进程地址空间分成内核区和用户区两部分。
当在内核态申请内存时直接给分配,而进程在用户态申请内存时,只是给了一个新的线性地址空间的一个使用权,真的要用的时候会产生缺页异常,然后再真的分配。
请求调页是一种动态内存分配技术,它把页框的分配推迟到不能再推迟为止。
与之相关的分配页框的方式为写时复制:父子进程是共享页框的,当读的时候,不分配新的页框。当写的时候,谁写就给谁分配,两者各自过运行一段时间都就都有了自己的空间。
5.文件系统
```text
Linux采用了虚拟文件系统(VFS)的形式,实现“一切皆文件”。
向上,对应用层 (的System Call) 提供一个标准的文件操作接口 (如read/write);
对下,对文件系统提供一个标准的接口,兼容多种文件系统可以方便的移植到Linux上;
当进程要读某个文件时,进行系统调用read,产生一个中断INT80,对应第120个中断向量,找到中断处理程序,带上系统调用号。访问文件系统中的文件。
```
6.Linux内核的启动过程
1. 启动引导加载程序BootLoader
2. 由BootLoader引导启动内核kernel
3. 由kernel检查和初始化硬件设备,载入设备的驱动程序模块,安装root文件系统
4. kernel启动一个名为init的进程,在init进程运行完成并启动其他必要的后续进程后,系统开始运行,引导进程结束
(二)shell
1.概念
1. shell是操作系统的最外层,shell可以合并编程语言以控制进程和文件,以及启动和控制其他程序。
2. 简单来说:shell就是一个用户跟操作系统之间交互的命令解释器。
3. Linux常用的shell解释器:/bin/bash
2.常见操作命令
1. 目录相关的:ls, cd, mkdir, cp等
2. 查看文件相关的:find, cat, head, tail, more, less, vim, awk等
3. 其他:ifconfig, iptables, netstat, snap等
(三)系统调用
1.概念
Linux系统总体上可以划分为内核态和用户态,也可以说是内核和应用程序,系统调用就是提供给用户程序的一组可以访问内核的接口。
2.过程
1. 程序调用libc库的封装函数。
2. 调用软中断int 0x80进入内核。
3. 在内核中首先执行system_call函数(首先将系统调用号(eax)和可以用到的所有CPU寄存器保存到相应的堆栈中(由SAVE_ALL完成),接着根据系统调用号在系统调用表中查找到对应的系统调用服务例程。
4. 执行该服务例程。
5. 执行完毕后,转入ret_from_sys_call 例程,从系统调用返回
(四)用户程序
1.概念
用户程序就是面向用户的一些程序,最简单的比如用C语言编写的`HelloWorld.c`程序,复杂的比如系统中的浏览器等。
2.可执行程序的工作原理
1. 源代码是如何变成可执行文件的
(1)预编译:处理源代码中的伪指令和一些特殊字符,并对一些相关的代码进行替换
(2)编译:检查语法并对代码进行优化,将文本文件 .i 翻译成 .s 文件,得到汇编语言程序。
(3)汇编:将 .s 文件转换成机器语言指令也就是二进制代码,并将结果保存在目标文件 .o 中
(4)链接:将所有的目标文件链接到一起形成可执行文件,分为动态链接和静态链接。
2. 可执行文件是如何变成进程的
(1)调用execve加载可执行程序
(2)调用execve陷入内核
(3)系统调用execve返回用户态
(4)被execve加载的可执行程序
二、一个实例——open函数
open的执行过程
1. open执行去C库里面,找到Int80 05指令封装。80为中断向量号,05为系统调用号
2. 从idtr寄存器中读取中断向量表的基地址,找到IDT。
3. trap-init调用set_system_gate等函数对中断向量表中的每一项进行初始化,并将指令所在地址的cs、eip、DPL以及门类型和中断向量号进行绑定。
4. 根据中断向量号128找到第128项,其中包括cs和eip,再根据gdtr、cd、eip找到所要执行指令的地址,再进行系统调用。
5. 进入系统调用,保存现场,对指令进行分析得到系统调用号05根据系统调用号,找到系统调用表中的sysopen的入口,即sysopen的函数指针。
6. sysopen对文件进行查找,得到文件控制块和文件类型。
7. 根据文件类型调用相应系统的文件打开函数,并在系统文件打开表中创建一个file,根据文件控制块向其中填充file_operation以及偏移量等项
8. 返回到进程,进入进程文件打开表,其中有一个fd数组,将fd数组未使用的最低索引指向系统文件打开表中的相应项,然后将fd数组的下标返回给open。
三、影响程序执行性能的因素
1.CPU
CPU 是操作系统稳定运行的根本,CPU 的速度与性能很大一部分决定了系统整体的性能,因此 CPU 数量越多、主频越高,服务器性能也就相对越好。
但事实也并非完全如此,目前大部分 CPU 在同一时间内只能运行一个线程,超线程的处理器可以在同一时间运行多个线程,因而可以利用处理器的超线程特性提髙系统性能。
可以使用top, uptime, vmstat
等工具查看分析CPU,负载等情况。
2.内存
内存太小,系统进程将被阻塞,应用也将变得缓慢,甚至失去响应;内存太大,会导致资源浪费。
Linux 系统采用了物理内存和虚拟内存的概念,虚拟内存虽然可以缓解物理内存的不足,但是占用过多的虚拟内存,应用程序的性能将明显下降。要保证应用程序的高性能运行,物理内存一定要足够大,但不应过大,否则会造成内存资源的浪费。
可以使用free, vmstat
等工具查看分析内存占用情况。
3.磁盘I/O
在一个需要频繁读写的应用中,如果磁盘 I/O 性能得不到满足,就会导致应用的停滞。
不过,好在现今的磁盘都采用了很多方法来提高 I/O 性能,比如常见的磁盘 RAID 技术。
可以使用fdisk, iostat
等工具查看分析磁盘使用情况。
4.网络带宽
低速的、不稳定的网络将导致网络应用程序的访问阻塞;而稳定、高速的带宽,可以保证应用程序在网络上畅通无阻地运行。
可以使用ping, netstat
等工具查看分析网络性能
5.应用程序本身
如果应用程序本身时间复杂度、空间复杂度等太高,会直接影响程序执行的性能。另外,应用程序使用的编程语言也会影响程序执行的性能,比如python、Java等,通常情况下程序性能是不如C/C++编程语言的。
四、总结
1. Linux精简模型
内核、shell、系统调用、用户程序
2. 影响应用程序性能的因素
CPU,内存、磁盘I/O,网络带宽、应用程序本身
五、致谢
非常感谢李老师和孟老师的辛勤教学与指导,使我学到很多Linux的知识!