所有的操作系统在设计调度器的时候都追求两个目标中的一个,要么就是提高吞吐率,要么就是提高某些任务的相应,其实这两个目标之间有一定的矛盾,就像拔河的两个人一样,你往吞吐率这里多一点,响应就差一点,你往相应多一点,可能就牺牲吞吐率,什么是吞吐,就是我发一分钟去看这个linux,它把所有时间都用在解决负载,比如你有很多事情要做,你把时间花在有用功上,而不是无意义的上面,响应是指某些任务的响应要快,比如说我点了一下鼠标,马上去响应这个鼠标的事件,以牺牲其他任务为代价。所以实时系统特别强调一点,一个高优先级的马上就会把低优先级的抢掉,抢得越快越好,所以你时间不是花在有用功上,有的时间被用在上下文切换,虽然上下文切换时间比较短,比如我从微博切换到微信。
在你linux编译的时候有个编译选项
Kernel Features-> Preemption Model
这个是选择你linux内核的抢占模型的,这个抢占模型的选择会影响到你linux里面的调度算法
里面有三个选项,第一个选项 No Force Preemption 不强制抢占,后面打了个括号是server,Voluntary Kernel Preemption 后面打了个括号desktop,Preemptible kerbel后面打了个括号low-latency desktop,我们一般做手机的时候,或者桌面电脑一般选这最后一种,但是服务器的话我们选择前一种,你在做服务器的时候,你更多的追求他在服务的时间内服务更多的数据库,能够提供更大的流量,而不是谁要响应快,但是你作为手机和桌面电脑,我把触摸屏画一下,按键按一下,你就应该马上给我相应,对手机或桌面就选最后一个,对服务器就选第一个。你选第一个是基本没什么抢占调度,你选最后一个是内核也可以抢,你选中间一个是内核不能抢的,只能自己唤醒CPU。你知道你在网上下载ubuntu为什么有desttop板和server版,原因就在这里。
在一个典型的操作系统上面运行的进程是分I/O消耗性和CPU消耗性两种的,CPU消耗型是指我把时间基本发在CPU上了,拼命的进行运算,CPU要猛这个任务才跑得比较流畅,I/O消耗型指的是你的时间没有花在CPU上,你发在读I/O啊,比如说你在等一个串口啊,一个键盘被人按啊等等,CPU在里面占用的比例并不高,这个时候CPU强不强,对你性能没多大影响的。这个时候影响效率的就是你能够及时的把我调度到。比如我现在有一个SD卡,举个例子,CPU用1MS发一个指令,剩下100MS去做这个DMA,接下来CPU又用1MS去发指令,剩下100MS执行DMA,对于这样的任务来讲,其实你的CPU强不强,对最后这个IO的性能是非常非常小的,因为你1MS,CPU变慢,可能发指令要做两毫秒,本来你做整个的I/O 需要101MS,现在也只是需要102MS,
现在的ARM架构是big.LITTLE,很猛很耗电的CPU,还有几个不猛不耗电的CPU,这就是大的很小,小的很大,big.LITTLE注意不要写错,big很大但是是小写,LITTLE很小但是是大写,ARM这样做就可以把CPU利用率不高的调度到垃圾的CPU上,把那些CPU消耗高的放到大核上面去
现在来说调度器,早期的2.6的调度器是怎么设置的呢,它把整个调度器的优先级划分在0-139之间,Linu内核空间,内核空间数字越小,优先级越高。0~99是RT的,100-139是非RT的。早期策略,0-99采用的RT策略,RT策略分为两种,一个是SCHED_FIFO,就是不同优先级按照优先级高的先跑到睡眠,优先级低的再跑,同等优先级先进先出。这个就是我高优先级的先跑,一直跑到我放弃CPU,你优先级低的在跑
SCHED_RR(RR的意思是ROUND ROBIN的意思 循环),不同优先级按照优先级高的先跑到睡眠,优先级低的在跑,同等优先级轮转。
这两个的区别在于FIFO的是同等优先级的是先进先出,RR轮转就是你一下我一下你一下我一下。
等0-99跑完之后就会跑100-139的普通进程,普通进程是不霸气的,普通进程讲究的是NICE, 100对应这niced的-20,139对应着nice的19,普通进程没什么,不会因为你优先级高就调度你,而是不同优先级轮转,在这里优先级高和优先级低有什么区别呢,第一,你可以得到更多的时间片,第二在你刚刚醒来的那个时刻,比如说你睡眠态刚刚醒来,你可以去抢占优先级低的,你抢到之后在去跟优先级低的进行轮转。你越想睡觉,你优先级就越高。当我们给进程设置一个NICE值之后,比如说NICE值是0,在Linux里面执行一个什么样的裸机呢,有一个工程师,中午不睡觉继续干活,不好意思优先级降低,动态NICE值加1,下午继续干活优先级降低二,晚上还加班优先级降低5,Linux优先级越干越低,睡着睡着优先级越来越高。为什么Linux2.6内核要干这件事,就是让CPU消耗型的人和I/O消耗型的人同时刻竞争的时候,让I/O消耗型竞争过CPU型。Linux 优先照顾I/O型,有限照顾喜欢睡眠的。在Linux后期,做了两个很重要的变更,就是限制RT,也就是FIFO和RR的人占用的最大的时间比例,
第一个是指的周期,第二个是指的时间。这两个加起来的意思是在1000000微妙里面,你RT最多跑950000微妙。
Linux对普通进程提供了一个非常牛逼的算法,这个算法叫做CFS:完全公平调度
他用的最核心的数据结构就是用的红黑树,红黑树就是左边的节点永远小于右边的节点,右边的节点一定小于最右边的节点,这些 2,7,19是什么东东呢,这不是进程的PID,这是进程运行到目前为止vruntime最小的进程,什么叫virtual runtime呢,实际就是物理的runtime除以权重乘以系数,就是你task_struct跑的时间除以权重然后乘以系数,这个系数是1024,权重直接由你的NICE值决定,在Linux 调用VRUNTIME最小的那个进程,你一被调度到你就占用CPU,然后分子就变大,跑着跑着2就比7大了,下一次7就最小了,就调用7。、权重如上如,前面的-20表示nice值,喜欢睡的分子 小,什么普通进程是无敌的呢,就是又喜欢睡nice值又低,但是哪怕你nice值是-20的I/O消耗型,你在普通进程里面是无敌了,但是随便来一个RT的FIFO和RT的RR都可以瞬间秒杀你,因为人家不是普通进程。普通进程在这棵树上完全公平掉了,所谓完全公平就是要追求虚拟时间的最终相等
如果一个人的分母是一个人分母的3倍,那么分子也应该是3倍,这样才能相等。这样我们可以调整进程中运行时间。
运行如下代码
查看CPU占用率
可以看到CPU占用率大概为百分之200,因为我这个有3个线程,两个死循环,所以整个进程是占到了200的CPU的
如果你在启用一个这个进程,你会发现两个的CPU各接近100%
我们使用sudo renice -n -5 -g 12839 把这个进程所有的线程nice值设置为-5,-g的意思就是把进程里面的所有进程
为了完全均衡的调度,所以这里的运行时间会是3倍,所以这个进程CPU的占用率就是3倍 -p的话就设置一个线程
如果你是FIFO占用CPU的话 你电脑会很卡,因为你普通进程抢不赢FIFO
设置SCHED_FIFO和50 RT优先级
chrt -f -a -p 50 10576 -f 是FIFO -a就是所有的,-p后面是优先级
设置nice
renice -n -5 -g 9394
nice -n 5 ./a.out