schedtune

11 篇文章 2 订阅
8 篇文章 2 订阅

目录

关键数据结构

CPU boost 

    更新cpu的boost和ts

    cpu的boost和ts在什么时候更新?

    cpu的boost和ts在什么时候使用?

    group[idx].boost和group[idx].ts在什么时候更新?

task boost

cpu和task 通过boost值计算margin

Question?


kernel4.14


  • 关键数据结构
     

  • CPU boost 

    更新cpu的boost和ts

调用 schedtune_cpu_update更新cpu的boost和ts

140 static void
141 schedtune_cpu_update(int cpu, u64 now)
142 {  
143     struct boost_groups *bg = &per_cpu(cpu_boost_groups, cpu);
144     int boost_max;
145     u64 boost_ts;
146     int idx;
147    
148     /* The root boost group is always active */
149     boost_max = bg->group[0].boost;
150     boost_ts = now;
151     for (idx = 1; idx < BOOSTGROUPS_COUNT; ++idx) {
152         /*
153          * A boost group affects a CPU only if it has
154          * RUNNABLE tasks on that CPU or it has hold
155          * in effect from a previous task.
156          */
157         if (!schedtune_boost_group_active(idx, bg, now))
158             continue;     
159    
160         /* This boost group is active */
161         if (boost_max > bg->group[idx].boost)
162             continue;
163    
164         boost_max = bg->group[idx].boost;
165         boost_ts =  bg->group[idx].ts; 
166     }
167     bg->boost_max = boost_max;
168     bg->boost_ts = boost_ts;
169 }  

即更新cpu的boost_max和boost_ts。方法是找到cpu上当前active group中boost值最大的group,把这个group的boost和ts作为cpu的boost_max和boost_ts。
--什么是active的group?即group中有task,或者group中之前task的boost没超时。137行,因为bg->group[idx].ts只有在rt task入队时才会被更新,所以对于其它非rt task,基本都是超时的。可以理解如果group中没有task,group就是非active的。除非此刻前50ms内有rt task曾入队运行,更新过ts。也就是说rt task入队后,其所在group的boost会持续active 50ms,如果rt task在top-app中,top-app 的boost值最大,就会在50ms内影响cpu的boost util。

131 static inline bool
132 schedtune_boost_group_active(int idx, struct boost_groups* bg, u64 now)
133 {
134     if (bg->group[idx].tasks)
135         return true;
136 
137     return !schedtune_boost_timeout(now, bg->group[idx].ts);
138 }
​

----什么是“group中之前task的boost没超时”?即task enqueue时boost开始生效,boost有效时间50ms,task在20ms时dequeue了,20ms后group中虽然没有task,但group的boost值仍然对cpu有效。

    cpu的boost和ts在什么时候更新?

1. 调用函数cpufreq_update_util更新cpu util时,使用、检查更新 cpu的boost和ts。cfs/rt/deadline都会调用cpufreq_update_util函数。以cfs为例:
    enqueue_task_fair->schedtune_enqueue_task->schedtune_tasks_update;
                                  ->enqueue_entity->...->cpufreq_update_util->sugov_update_single{share}->sugov_get_util->boosted_cpu_util->schedtune_cpu_margin->schedtune_cpu_boost->schedtune_cpu_update
   
当cpu的util发生变化,更新cpu的util时,会重新计算boost util,此时:
    如果cpu当前的boost超时,(now - bg->boost_ts) > SCHEDTUNE_BOOST_HOLD_NS(50ms),则update cpu的boost和ts;
    如果cpu当前boost没超时,返回bg->boost_max。
2. enqueue_task_fair{rt}->schedtune_enqueue_task->schedtune_tasks_update
    247~249行,task入队被加入cpu上一个非active的group时,此时因为task的加入,active了一个group,同时也会对cpu的boost_max产生影响,需要更新

task_count={ENQUEUE_TASK  1
                     DEQUEUE_TASK -1}

31 static inline void
232 schedtune_tasks_update(struct task_struct *p, int cpu, int idx, int task_count)
233 {  
234     struct boost_groups *bg = &per_cpu(cpu_boost_groups, cpu);
235     int tasks = bg->group[idx].tasks + task_count;
236    
237     /* Update boosted tasks count while avoiding to make it negative */
238     bg->group[idx].tasks = max(0, tasks);
239    
240     /* Update timeout on enqueue */
241     if (task_count > 0) { 
242         u64 now = sched_clock_cpu(cpu);
243    
244         if (schedtune_update_timestamp(p))
245             bg->group[idx].ts = now;       
246    
247         /* Boost group activation or deactivation on that RQ */
248         if (bg->group[idx].tasks == 1) 
249             schedtune_cpu_update(cpu, now);
250     }
251                           
252     trace_sched_tune_tasks_update(p, cpu, tasks, idx,
253             bg->group[idx].boost, bg->boost_max,
254             bg->group[idx].ts);            
255 }

    241,行仅处理 task入队时的情况;248行表示active一个group。那如果一个group中唯一的task dequeue了,group被deactive了,需要调用schedtune_cpu_update更新cpu的boost和ts吗?
    答案是不需要。使用cpu boost的地方只有一处,即在计算cpu util的时候。而在return bg->boost_max前,已经做了schedtune_cpu_update。
    而条件schedtune_boost_timeout一般都是true,除了计算util时,只有在active group的时候会更新bg->boost_ts,而bg->boost_ts取决于group[idx].boost最大的ts,这个ts只有rt入队时才更新,在计算util前已经调用schedtune_enqueue_task进行了更新。如果前50ms内有rt task,则此处直接返回bg->boost_max,是受益rt task;如果50ms内没有rt task,计算util时超时,调用了schedtune_cpu_update更新了deactive group后的cpu groups[idx].boost。

       |        |      |              \--> boost = schedtune_cpu_boost(cpu)
       |        |      |                     |            \-->if (schedtune_boost_timeout(now, bg->boost_ts))    /*更新bg->boost_max和bg->boost_ts*/
       |        |      |                     |                      schedtune_cpu_update(cpu, now);
       |        |      |                     |                  return bg->boost_max
       |        |      |                     return schedtune_margin(util, boost)    /*根据boost值计算margin*/

3. schedtune_boostgroup_release 
                                    boost_write->schedtune_boostgroup_update(int idx, int boost)->schedtune_cpu_update
    通过sys节点修改group的boost值,或release 一个group时,更新cpu的boost。
    schedtune_boostgroup_update为每个cpu的idx group(如top-app)更新boost值,并检查新的group[idx].boost是否影响cpu当前的boost_max,如果影响则更新。

171 static int                
172 schedtune_boostgroup_update(int idx, int boost)
173 {  
174     struct boost_groups *bg;
175     int cur_boost_max;
176     int old_boost;
177     int cpu;
178     u64 now;
179 
180     /* Update per CPU boost groups */
181     for_each_possible_cpu(cpu) {   
182         bg = &per_cpu(cpu_boost_groups, cpu);
183    
184         /*
185          * Keep track of current boost values to compute the per CPU
186          * maximum only when it has been affected by the new value of
187          * the updated boost group
188          */
189         cur_boost_max = bg->boost_max; 
190         old_boost = bg->group[idx].boost;
191    
192         /* Update the boost value of this boost group */
193         bg->group[idx].boost = boost;  
194    
195         /* Check if this update increase current max */
196         now = sched_clock_cpu(cpu);    
197         if (boost > cur_boost_max &&   
198             schedtune_boost_group_active(idx, bg, now)) {
199             bg->boost_max = boost;         
200             bg->boost_ts = bg->group[idx].ts;
201    
202             trace_sched_tune_boostgroup_update(cpu, 1, bg->boost_max);
203             continue;
204         }
205    
206         /* Check if this update has decreased current max */
207         if (cur_boost_max == old_boost && old_boost > boost) {
208             schedtune_cpu_update(cpu, now);
209             trace_sched_tune_boostgroup_update(cpu, -1, bg->boost_max);
210             continue;
211         }
212                           
213         trace_sched_tune_boostgroup_update(cpu, 0, bg->boost_max);
214     }
215 
216     return 0;
217 }

    cpu的boost和ts在什么时候使用?

    当cpu的util发生变化,更新cpu的util时,会重新计算boost util,此时会使用cpu的bg->boost_max,是否需要更新参考上边解释。

sugov_get_util
\--> util = cpu_util_freq(cpu)
       util = boosted_cpu_util(cpu, util)
       |        \--> margin = schedtune_cpu_margin(util, cpu)
       |        |      |              \--> boost = schedtune_cpu_boost(cpu)
       |        |      |                     |            \-->if (schedtune_boost_timeout(now, bg->boost_ts))    /*更新bg->boost_max和bg->boost_ts*/
       |        |      |                     |                      schedtune_cpu_update(cpu, now);
       |        |      |                     |                  return bg->boost_max
       |        |      |                     return schedtune_margin(util, boost)    /*根据boost值计算margin*/
       |        |      trace_sched_boost_cpu(cpu, util, margin)
       |        |      return util + margin
       return min(util, max_cap)

    group[idx].boost和group[idx].ts在什么时候更新?

enqueue_task_fair{rt}->schedtune_enqueue_task->schedtune_tasks_update

244~245行,rt task入队,或配置SCHEDTUNE_BOOST_HOLD_ALL sched feature时,更新bg->group[idx].ts = now
190行,通过sys节点修改boost值,或release一个group时(boost=0),schedtune_boostgroup_update会更新bg->group[idx].ts = boost。

222 static inline bool
223 schedtune_update_timestamp(struct task_struct *p)
224 {  
225     if (sched_feat(SCHEDTUNE_BOOST_HOLD_ALL))
226         return true;
227    
228     return task_has_rt_policy(p);  
229 }  
  • task boost

select_idle_sibling_cstate_aware 
task_fits_capacity
find_best_target
get_eenv
\--> boosted_task_util
       \--> util = task_util_est(task)
             margin = schedtune_task_margin(task)
             |               \--> boost = schedtune_task_boost(task)
             |                     |             \-->st = task_schedtune(p)
             |                     |                  task_boost = st->boost
             |                     util = task_util_est(task)
             |                     margin = schedtune_margin(util, boost)
             trace_sched_boost_task(task, util, margin)
             return util + margin

  • cpu和task 通过boost值计算margin

    /*根据计算出的boost值,分为两种情况计算: margin=util*boost (boost<spc); margin=(1024-util)*boost (boost≥spc) */ 

 6756 unsigned int spc_threshold = 100;
 6757 static long
 6758 schedtune_margin(unsigned long signal, long boost)
 6759 {
 6760     long long margin = 0;
 6761  
 6762     /*
 6763      * Signal proportional compensation (SPC)
 6764      *
 6765      * The Boost (B) value is used to compute a Margin (M) which is
 6766      * proportional to the complement of the original Signal (S):
 6767      *   M = B * (SCHED_CAPACITY_SCALE - S)
 6768      * The obtained M could be used by the caller to "boost" S.
 6769      */
 6770     if (boost >= 0) {   
 6771         if (signal < spc_threshold)
 6772             margin = signal * boost;       
 6773         else {
 6774             margin  = SCHED_CAPACITY_SCALE - signal; 
 6775             margin *= boost;
 6776         }
 6777     } else
 6778         margin = -signal * boost;
 6779  
 6780     margin  = reciprocal_divide(margin, schedtune_spc_rdiv);
 6781  
 6782     if (boost < 0)      
 6783         margin *= -1;   
 6784     return margin;
 6785 }

Question?

  1. 具体某一个group的ts是在什么时候更新的,又是怎么判断失效的?
  2. Signal Proportional Compensation' (SPC)原理是什么?
    SPC补偿机制的原理是:
    margin=b\ \cdot\frac{\left(1024-x\right)}{100}
    b的意义是重定义信号x的基线值:
    1)当b=0时,margin=0,信号x的范围是:0 ≤ x ≤ 1024;
    2)当b=50时,信号x的基线是:
          margin=b\ \cdot\frac{\left(1024-x\right)}{100}=50\ \cdot\frac{\left(1024-0\right)}{100}=512
          信号x的范围是:512 ≤ x ≤ 1024
    从以上可知,b定义了信号x的基线:base=(b/100)*1024,把信号x从(0 ≤ x ≤ 1024)线性映射到(base ≤ x ≤ 1024)
  3. 关于SPC的缺陷
    应用程序往往由不同属组的task构成,比如MP3的主线程如果被放到top-app中,top-app又设置了boost=50,此线程的util很小,却被boost的很大,影响功耗。对小task的boost,我们做了优化(s=100):
    f_{1}\left(x\right)=x+b\cdot\frac{x}{100}\left\{0<x<s\right\}
    f_{2}\left(x\right)=x+b\ \cdot\frac{\left(1024-x\right)}{100}\left\{1024\ge x\ge s\right\}
    函数图形参考:STUNE
  4. 总结
    schedtune 作用于某一个cpu 的util,rt task会持续boost 50ms,其它task只在running时间boost有效,cpu的boost值取决于当前cpu所有active groups中boost的最大值。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值