rt 调度

调度域与调度组(CFS 负载均衡)

根域(ld/rt 负载均衡)

腾讯云原生:Linux 内核调度器源码分析 - 初始化 _ 【IIS7站长之家】

Linux内核调度器源码分析 - 初始化

调度周期:预期多长时间会执行一次

时间片:在调度周期内分配的运行时间

/proc/sys/kernel 下面有对应的时间

调度延迟:从挂入队列到获得cpu资源的等待时间

最小调度粒度:在调度周期内保证的最小运行时间

每个cpu rq 对应cfs_rq 和rt_rq

RT 


scheduler中的RT调度器,其中有看到一个cpupri,作为选核的一部分,
暂把一个cpu中正在排队以及正在running的所有rt task最高的优先级叫做此cpu的优先级。
根据这个优先级可以对CPU进行排序,

对于RT调度器来讲,其重要任务是保证优先级高的task优先执行,优先级高的task的响应时间也要最快。
假定一个task上面已经有比较高优先级的Task在排队或者run的话,这时候一个就绪的优先级比较低的task加入就得等待,
那么这个task 就会排队,造成runnable,即便是其他cpu上面所有task的优先级都比这个task还低。这样显然不合理。

而cpupri则负责跟踪记录各个cpu中所有task的最高优先级情况,方便后面寻找优先级最低的cpu出来,供RT调度器进行选择。


kernel-4.19/kernel/sched/cpupri.h 
1  /* SPDX-License-Identifier: GPL-2.0 */
2  
3  #define CPUPRI_NR_PRIORITIES    (MAX_RT_PRIO + 2)
4  
5  #define CPUPRI_INVALID        -1
6  #define CPUPRI_IDLE         0
7  #define CPUPRI_NORMAL         1
8  /* values 2-101 are RT priorities 0-99 */
9  
10  struct cpupri_vec {
11      atomic_t        count;
12      cpumask_var_t        mask;
13  };
14  
15  struct cpupri {
        //有多少个RT优先级就有多少个元素。每个元素记录吧这个优先级分别是哪些个cpu的最高优先级。所以理论上讲最多只有8个元素是有值的,假定有8个cpu的话。
        //102个元素,见convert_prio(),invalid:-1,idle:0,cfs:1,rt:101-prio(0-99)
16      struct cpupri_vec    pri_to_cpu[CPUPRI_NR_PRIORITIES];
        //一个有多少个cpu就有多少个元素的数组。每个元素代表对应cpu中当前最高优先级的值。
17      int            *cpu_to_pri;
18  };
19  
20  #ifdef CONFIG_SMP
21  int  cpupri_find(struct cpupri *cp, struct task_struct *p,
22           struct cpumask *lowest_mask);
23  int  cpupri_find_fitness(struct cpupri *cp, struct task_struct *p,
24               struct cpumask *lowest_mask,
25               bool (*fitness_fn)(struct task_struct *p, int cpu));
26  void cpupri_set(struct cpupri *cp, int cpu, int pri);
27  int  cpupri_init(struct cpupri *cp);
28  void cpupri_cleanup(struct cpupri *cp);
29  #endif

RT进程唤醒选核
1. 选择运行优先级最低cpu;
2. 选的核上如果curr优先级比唤醒的低,则会设置TIF_NEED_RESCHED

kernel-4.19/kernel/sched/sched.h 

struct root_domain {

786      /*
787       * The "RT overload" flag: it gets set if a CPU has more than
788       * one runnable RT task.
789       */
790      cpumask_var_t        rto_mask;
791      struct cpupri        cpupri;
792  
793      /* Maximum cpu capacity in the system. */
794      struct max_cpu_capacity max_cpu_capacity;
795  

}


static int init_rootdomain(struct root_domain *rd){

512      init_dl_bw(&rd->dl_bw);
513      if (cpudl_init(&rd->cpudl) != 0)
514          goto free_rto_mask;
515  
516      if (cpupri_init(&rd->cpupri) != 0)
517          goto free_cpudl;
518  
519      init_max_cpu_capacity(&rd->max_cpu_capacity);


}


268  /**
269   * cpupri_init - initialize the cpupri structure
270   * @cp: The cpupri context
271   *
272   * Return: -ENOMEM on memory allocation failure.
273   */
274  int cpupri_init(struct cpupri *cp)
275  {
276      int i;
277  
278      for (i = 0; i < CPUPRI_NR_PRIORITIES; i++) {
279          struct cpupri_vec *vec = &cp->pri_to_cpu[i];
280  
281          atomic_set(&vec->count, 0);
282          if (!zalloc_cpumask_var(&vec->mask, GFP_KERNEL))
283              goto cleanup;
284      }
285  
286      cp->cpu_to_pri = kcalloc(nr_cpu_ids, sizeof(int), GFP_KERNEL);
287      if (!cp->cpu_to_pri)
288          goto cleanup;
289  
290      for_each_possible_cpu(i)
291          cp->cpu_to_pri[i] = CPUPRI_INVALID;
292  
293      return 0;
294  
295  cleanup:
296      for (i--; i >= 0; i--)
297          free_cpumask_var(cp->pri_to_cpu[i].mask);
298      return -ENOMEM;
299  }


idle位于0元素,而normal task位于1元素,而后才是按照rt优先级排序的元素。
实际上由于只有rt调度器当中才会调用cpupri_set。所以,对于idle与normal来讲都是位于1元素位置,

75  void init_rt_rq(struct rt_rq *rt_rq)
76  {
77      struct rt_prio_array *array;
78      int i;
79  
80      array = &rt_rq->active;
81      for (i = 0; i < MAX_RT_PRIO; i++) {
82          INIT_LIST_HEAD(array->queue + i);
83          __clear_bit(i, array->bitmap);
84      }
85      /* delimiter for bitsearch: */
86      __set_bit(MAX_RT_PRIO, array->bitmap);
87  
88  #if defined CONFIG_SMP
89      rt_rq->highest_prio.curr = MAX_RT_PRIO;
90      rt_rq->highest_prio.next = MAX_RT_PRIO;
91      rt_rq->rt_nr_migratory = 0;
92      rt_rq->overloaded = 0;
93      plist_head_init(&rt_rq->pushable_tasks);
94  #endif /* CONFIG_SMP */
95      /* We start is dequeued state, because no RT tasks are queued */
96      rt_rq->rt_queued = 0;
97  
98      rt_rq->rt_time = 0;
99      rt_rq->rt_throttled = 0;
100      rt_rq->rt_runtime = 0;
101      raw_spin_lock_init(&rt_rq->rt_runtime_lock);
102  }
103  
 

1、try_to_wake_up 唤醒

2、select_task_rq_rt 选核

3、find_lowest_task_rt 确定最低优先级

     当一个任务被唤醒时候,需要根据任务的类型:uitask_demand_fit, boost等,确定起始的调度域,如ui可能优先从中核开始调度;

    根据任务特性选择是否走快速路径,如当前任务马上就要执行结束,满足一定条件将唤醒进程放在当前或者唤醒进程的prev_cpu上;

      根据能耗比,选择idle cpu,或者当前空闲算力最大的cpu

     根据线程类型,进一步修正如,ui选核时候会优先从cpu_cap 大的往小的选;除非当前选核时         候大核超大核全是pri<MAX_RT_PRI;ui线程会选大核

设置重新调度的标志位:

1. 分配时间片用完;

2. 分配时间片没用完但已经保证了最小调度粒度,当前的队列中有虚拟时间更小的任务;

3. set_next_buddy: 唤醒的线程虚拟时间大于curr一个时间片;

pick_next_task_rt 选择任务

判断当前进程运行结束后下一个进程的优先级比当前优先级低,就会触发一次pull_rt_task的操作;

寻找rt_rq的最高优先级,通过位图确认;

选择list 头的任务

每个优先级对应一个列表,里面是属于该优先级的任务,从而根据这些信息选择优先级最高任务执行。

 红黑树以虚拟时间为key值,每次选择虚拟时间最小的task_struct来执行;如果开启了next_buddyfeature,next满足条件会抢占left执行;

2. 普通进程的优先级影响是虚拟时间的计算;

3. 优先级影响了将实际时间片转化为虚拟时间片的比例;

4. 虚拟时间片最终影响(例外:next_buddy, ui)选择某个进程

频率影响性能与功耗

P = C * F * V2
在调频的时候一般需要增加电压,当频率增加,功耗增加更加明显;

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值