栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

linux-cpu 调度

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

linux-cpu 调度

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

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

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

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

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

每个cpu rq 对应cfs_rq 和rt_rq

 ps -AT  -o  cmd,pid,sched,nice,rtprio,pri   

查看调度信息


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  
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  
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      
790      cpumask_var_t        rto_mask;
791      struct cpupri        cpupri;
792  
793      
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  
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      
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
95      
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 确定最低优先级

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

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

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

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

设置重新调度的标志位:

1. 分配时间片用完;

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

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

pick_next_task_rt 选择任务

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

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

选择list 头的任务

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

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

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

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

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

频率影响性能与功耗

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020053.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号