Linux 进程调度

  1. 策略
    1.1 I/O消耗型和处理器消耗型的进程
    进程的大部分时间用来提交I/O请求,等待请求,进程可以经常处于可运行状态,等待更多请求时会阻塞
    处理器消耗型大多放在执行代码上,调度策略是尽量降低他们的运行频率。
    调度策略通常要在两个矛盾的目标中间寻找平衡,进程响应迅速,最大系统利用率。倾向优先调度I/O消耗型进程
    1.2 进程优先级
    高优先级先运行,低的后运行,相同优先级的进程按轮转方式进行调度,如果一个进程在io等待上耗费时间多于其运行时间,属于io消耗型进程,相反一个进程的时间片一下被耗尽,属于处理器消耗型进程,它的优先级被动态地降低
    nice -20 – 19 默认是0 实时优先级,他是可配置的,默认情况下它的变化范围是0到99,任何实时进程的优先级都高于普通进程。
    1.3 时间片
    时间片表明进程在被抢占前所能维持运行的时间,处理器消耗型需要长的时间片,io消耗型不需要长的时间片
    1.4 进程抢占
    当一个进程进入task_running状态内核会检查它的优先级是否高于正在执行的进程,调度程序挥别唤醒,抢占当前正在运行的进程并运行新的可运行进程。
    1.5 调度策略的活动
    文字编辑程序和视频编码程序,文字编辑高优先级,视频编码可以在所有剩余时间中独享处理器,提高了应用的性能
  2. 调度算法
    实现调度目标:1.充分实现O1调度,实现smp的可拓展型,每个处理器拥有自己的锁和可执行队列
    加强交互性能,即使系统处于相当负载的情况下,也能保证系统的响应,并立即调度交互式进程。保证公平
    2.1 可执行队列
    调度程序中最基本的数据结构是运行队列,给定处理器上的可执行进程的链表每个处理器一个,
    struct runqueue{
    spinlock_t lock; 保护运行队列的自旋锁
    unsigned long nr_running; 可运行任务数目
    unsigned long nr_switches; 上下文切换数目
    unsigned long expired_timestamp; 队列最后被换出时间
    unsigned long nr_uninterruptible; 处于不可中断睡眠状态的任务数目
    unsigned long timestamp_last_tick; 最后一个调度程序的节拍
    struct task_struct *curr;当前运行任务
    struct task_struct *idle; 空任务
    struct mm_struct *prev_mm; 最后运行任务的结构体
    struct prio_array *active; 活动优先级队列
    struct prio_array *expired; 超时优先级队列
    struct prio_array *arrays[2];实际优先级数组
    struct task_struct *migration_thread;移出线程
    struct task_struct migration_queue;移出队列
    atomic_t nr_iowait;等待I/O操作的任务数目
    };
    cpu_rq(processor)返回给定处理器可执行队列的指针,this_rq返回当前处理器的可执行队列,task_rq(task)返回给定处理器可执行队列的指针
    按照执行队列地址从低向高的顺序释放添加锁
    2.2 优先级数组
    每个运行队列都有两个优先级数组,一个活跃的一个过期的,
    struct prio_array{
    int nr_array; 任务数目
    unsigned long bitmap[BITMAP_SIZE]; 优先级位图
    stuct list_head queue[MAX_PRIO]; 优先级队列
    };
    MAX_PRIO 定义了系统拥有优先级的个数,默认值为140,bitmap_size 是优先级位图数组的大小,长度32位,140个优先级需要5个长整型数才能表示 32
    5 160,优先级的个数是个定值,查找时间恒定,不受系统到底有多少可执行进程的影响,sched_find_first_bit();每个优先级数组还包含一个给定的优先级,每个链表都包含该处理器队列上相应优先级的全部可运行进程,对于给定的优先级按轮转方式调度任务
    2.3 重新计算时间片
    显示方式重新计算每个进程的时间片 重新计算优先级,计算时间片
    存在问题:耗费相当长的时间,n个进程的系统复杂度可能达到On,重新计算时间片的时机是不确定的,给确定性要求很高的实时程序带来麻烦,实现比较粗糙
    为每个处理器维护两个优先级数组,既有活动数组也有过期数组,活动数组内的可执行队列上的进程还有时间片剩余,过期数组内的可执行队列上的进程都耗尽了时间片,会被移至过期数组,重新计算时间片变得非常简单,在活动和过期数组之间来回切换就可以,
    struct prio_array *arry = rq->active;
    if(!array->nr_active){
    rq->active = rq->expired;
    rq->expired = array;
    }
    2.4 schedule()
    struct task_struct *prev,*next;
    struct list_head *queue;
    struct prio_array *array;
    int idx;
    prev = current;
    array = rq->active;
    idx = sched_find_first_bit(array->bitmap);
    queue = array->queue + idx;
    next = list_entry(queue->next, struct task_struct, run_list);
    如果prev和next不等,说明选中的进程不是当前进程,context-switch被调用,prev---->next
    2.5 计算优先级和时间片
    effctive_prio返回一个进程的动态优先级,举例,交互性强的nice可能优先级高,奖励机制
    当一个进程从休眠状态恢复到执行状态时,sleep_avg会根据它的休眠长短而增长,直到达到max_sleep_avg为止,
    2.6 睡眠和唤醒
    休眠的进程处于一个特殊不可执行状态,将自己标记成休眠状态,把自己移出可执行队列,放入等待队列,调用schedule选择和执行一个其他进程
    等待队列是由等待事件发生的进程组成的简单链表,内核用wake_queue_head_t来代表等待队列,DECLARE_WAITQUEUE静态创建,init_waitqueue_head动态创建,注意休眠和唤醒的实现。
    load_balance
    find busiest group
    find busiest queue
    if busiest->nr running > 1
    then double lock balance (rq,business)
    move tasks
    busiest->push_cpu = this_cpu
  3. 抢占和上下文切换
    3.1 用户抢占
    内核即将返回用户空间的时候,如果need_resched标志被设置,导致schedule被调用,发生用户抢占,从系统调返回用户空间,从中断处理程序返回用户空间
    3.2 内核抢占
    不支持抢占的内核中各任务是协作方式调度的,不具备抢占性
    什么时候可以重新调度?没有持有锁,锁是非抢占区域的标志,支持smp没有持有锁,正在执行的代码就是可重新导入的,也就是可抢占的。
    thread_info 引入preempt_count计数器,值为0则表示可以抢占,如果need_reched被设置,count为0则表示有个更重要的任务需要执行并且可以安全地抢占
    从中断处理程序在执行且返回内核空间之前
    当内核代码再一次具有可抢占性的时候
    内核显式的调用schedule
    内核中的任务阻塞
  4. 实时
    SCHED_FIFO 先入先出的调度算法,不使用时间片,可执行状态会一直执行,直到受阻或显式地释放处理器,他不基于时间片,只有高级别的进程才可以抢占
    SCHED_RR 在耗尽事先分配的时间就不再不再接着执行了,实时轮流调度算法,静态优先级,不为实时进程计算动态优先级。
    软实时工作方式,内核调度进程,使进程在它的限定时间到来前运行,硬实时可以严格满足时间要求
  5. 与调度相关的系统调用
    5.1 与调度策略和优先级相关的系统调用
    sched_setscheduler sched_getscheduler 设置和获取进程的调度策略和实时优先级,
    sched_setparam/getparam 设置和获取进程的实时优先级
    5.2 与处理器绑定有关的系统调用
    sched_setaffinity设置一个不同的一个或几个组合的位掩码,get返回cpus_allowd位掩码
    5.3 放弃处理器时间
  6. 调度程序小结
    NUMA机器功能变得越来越重要
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值