简析 Linux 的 CPU 时间( 二 )


Linux 的调度策略是抢占式的,每个线程都有优先级prirority的概念,并按照优先级高低分为两种:

  • 实时进程(优先级 0~99)
  • 普通进程(优先级 100~139)
每个 CPU 都有自己的运行队列 runqueue,需要运行的线程会被加入到这个队列中 。
简析 Linux 的 CPU 时间

文章插图
每个队列可以进一步细分为 3 个队列以及 5 种调度策略:
  • dl_rq
    • SCHED_DEADLINE 选择 deadline 距离当前时间点最近的任务执行
  • rt_rq —— 可以互相抢占的实时任务
    • SCHED_FIFO 一旦抢占到 CPU 资源,就会一直运行直到退出 , 除非被高优先级抢占
    • SCHED_RR 当 CPU 时间片用完,内核会把它放到队列末尾,可以被高优先级抢占
  • cfs_rq —— 公平占用 CPU 时间的普通任务
    • SCHED_NORMAL 普通进程
    • SCHED_BATCH 后台进程
Linux 内核在选择下一个任务执行时,会按照该顺序来进行选择 , 也就是先从 dl_rq 里选择任务,然后从 rt_rq 里选择任务,最后从 cfs_rq 里选择任务 。所以实时任务总是会比普通任务先得到执行 。
实时进程的优先级总是高于普通进程,因此当系统中有实时进程运行时 , 普通进程几乎是无法分到时间片的 。
nice 值为了保证 cfs_rq 队列的公平性,Linux 采用完全公平调度算法 CFS Completely Fair Scheduler进行调度,保证每个普通进程都尽可能被调度到 。
CFS 引入了 vruntime 作为衡量是否公平的依据:
  • vruntime 与任务占用的 CPU 时间成正比
  • vruntime 与任务优先级成反比(优先级越高vruntime增长越慢)
如果一个任务的 vruntime 较小,说明它以前占用 CPU 的时间较短,受到了不公平对待 , 因此该进程会被优先调度,从而到达所谓的公平性 。
为了实现可控的调度,Linux 为普通进程引入了 nice 值的概念 。其的取值其范围是 -20 ~ +19,调整该值会改变进程的优先级:prirority += nice
与此同时 vruntime 计算也会受到影响:
进程的 nice 值越小, 优先级越高, 所能分到的运行时间也越多当用户进程设置了一个大于 0 的 nice 值时,其用户态的运行时间将被统计为nice time 而不是 user time 。简单来说,nice time 表示 CPU 花了多少时间用于运行低优先级的任务 。
nice time 占比比较高时,通常是某些定时任务调度器导致的:它们会为后台任务进程设置一个较大的 nice 值,避免这些进程与其他线程争抢 CPU 资源 。
软中断中断就是一种插队机制,可以让操作系统优先处理一些紧急的任务 。当硬件设备(例如 , 网卡)需要向 CPU 发出信号时(例如,数据已到达),就会产生硬件中断 。
CPU 接收到中断时 , 会切换到内核态执行特定的中断服务,并且期间不允许其他中断抢占(关中断) 。当中断服务需要执行较长时间时,可能会导致且其他的中断得不到及时的响应 。
为了提高中断处理效率,操作系统在之前的基础上把中断处理分成两部分:
  • 上半部top half:在屏蔽中断的上下文中运行,用于完成关键性的处理动作
  • 下半部bottom half:不在中断服务上下文中执行 , 主要处理不那么急迫但耗时的任务
内核在处理完中断上半部后,可以延期执行下半部 , 该机制被称为软中断softirq 。软中断处理的过程是不会关中断的,因此当有硬中断到来的时候,可以及时响应 。
构成软中断机制的核心元素包括:
  • 注册: 软中断状态寄存器 irq_stat
  • 处理: 软中断向量表 softirq_vec
  • 触发: 软中断守护线程 daemon

简析 Linux 的 CPU 时间

文章插图
  1. 调用open_softirq()将软中断服务程序注册到软中断向量表softirq_vec(可?。?
  2. 调用raise_softirq()触发软中断事务