MTK schedplus CPU Governor

一,代码分析

定义 CONFIG_CPU_FREQ_GOV_SCHEDPLUS=y

1. @LINUX/android/kernel-4.9/drivers/misc/mediatek/sched/Kconfig

config CPU_FREQ_DEFAULT_GOV_SCHEDPLUS bool "To make sched+ as default governor" select CPU_FREQ_GOV_SCHEDPLUS help Use the CPUfreq governor 'schedplus' as default. This scales cpu frequency using CPU utilization estimates from the scheduler not only but also support some of platform dependent features.

 

config CPU_FREQ_GOV_SCHEDPLUS bool "'sched+' cpufreq governor" depends on CPU_FREQ select CPU_FREQ_GOV_COMMON help 'sched+' - this governor scales cpu frequency from the scheduler as a function of cpu capacity utilization. It does not evaluate utilization on a periodic basis (as ondemand does) but instead is event-driven by the scheduler and support below additional features. 1) platform dependent(micro controller). 2) sched-assistant (a assistnat for major governor). 3) hotplug (cpu on/off). If in doubt, say N.

 

2. @LINUX/android/device/mediatek/mt6761/init.mt6761.rc

on property:sys.boot_completed=1

# switch to sched-dvfs write /sys/devices/system/cpu/cpufreq/policy0/scaling_governor "schedplus" write /sys/devices/system/cpu/cpufreq/policy4/scaling_governor "schedplus"

 

3. @Cpufreq_schedplus.c (kernel\sched)

/* next throttling period expiry if increasing OPP */

#define THROTTLE_DOWN_NSEC 4000000 /* 4ms default */ 降频的最小时间间隔

/* next throttling period expiry if decreasing OPP */

#define THROTTLE_UP_NSEC 0 /* 0us */ 及时提频无最小时间间隔限制

#define THROTTLE_NSEC 2000000 /* 2ms default */

 

late_initcall(cpufreq_sched_init);

static int __init cpufreq_sched_init(void)

{

for (i = 0; i < MAX_CLUSTER_NR; i++) {

g_gd[i] = kzalloc(sizeof(struct gov_data), GFP_KERNEL);

if (!g_gd[i]) {

WARN_ON(1);

return -ENOMEM;

}

g_gd[i]->up_throttle_nsec = THROTTLE_UP_NSEC; //0

g_gd[i]->down_throttle_nsec = THROTTLE_DOWN_NSEC; //4ms, 被eas重新设为0

g_gd[i]->up_throttle_nsec_bk = THROTTLE_UP_NSEC;

g_gd[i]->down_throttle_nsec_bk = THROTTLE_DOWN_NSEC;

g_gd[i]->throttle_nsec = THROTTLE_NSEC; //2ms

g_gd[i]->last_freq_update_time = 0;

/* keep cid needed */

g_gd[i]->cid = i;

}

cpu_hotplug.notifier_call = cpu_hotplug_handler;

register_hotcpu_notifier(&cpu_hotplug);

cpu_pm_register_notifier(&cpu_pm_notifier_block);

 

return cpufreq_register_governor(&cpufreq_gov_sched);//注册cpu governor

}

 

down_throttle_nsec 被EAS设置为0, 为了能快速降频而省电

@kernel-4.9/drivers/misc/mediatek/performance/boost_ctrl/eas_ctrl/eas_ctrl.c

update_schedplus_down_throttle_ns(int kicker, int nsec)会调用

void schedplus_set_down_throttle_nsec(unsigned long val) //val = 0

{

for (cid = 0; cid < MAX_CLUSTER_NR; cid++) {

gd = g_gd[cid];

if (!gd)

return;

gd->down_throttle_nsec = val;

gd->down_throttle_nsec_bk = val;

}

}

 

如何触发CPU调度?

scheduler_tick@Core.c (kernel\sched) //每tick调用一次, CONFIG_HZ=500表示每2ms调用一次

sched_freq_tick

sched_freq_tick_pelt

set_cfs_cpu_capacity@Sched.h (kernel\sched)

set_rt_cpu_capacity

set_dl_cpu_capacity

update_cpu_capacity_request@Cpufreq_schedplus.c (kernel\sched)

update_fdomain_capacity_request

static void update_fdomain_capacity_request(int cpu, int type)

{

policy = cpufreq_cpu_get(cpu);

cpu_max_freq = policy->cpuinfo.max_freq;

 

arch_get_cluster_cpus(&cls_cpus, cid);

/* find max capacity requested by cpus in this policy */

for_each_cpu(cpu_tmp, &cls_cpus) {

/* In schedplus, util is scaling by capacity_orig_of*/

uclamp_min = (uclamp_min << SCHED_CAPACITY_SHIFT) /

capacity_orig_of(cpu_tmp);

/* convert IO boosted freq to capacity */

boosted_util = (sg_cpu->iowait_boost << SCHED_CAPACITY_SHIFT) /

cpu_max_freq;

 

scr = &per_cpu(cpu_sched_capacity_reqs, cpu_tmp);

 

/*

* If the CPU utilization was last updated before the previous

* frequency update and the time elapsed between the last update

* of the CPU utilization and the last frequency update is long

* enough, don't take the CPU into account as it probably is

* idle now (and clear iowait_boost for it).

*/

delta_ns = gd->last_freq_update_time - cpu_rq(cpu_tmp)->clock;

 

if (delta_ns > TICK_NSEC * 2) {/* 2tick */ 该CPU有可能已经IDLE

sg_cpu->iowait_boost = 0;

sg_cpu->idle = 1;

continue;

}

/* check if IO boosting */

if (boosted_util > scr->total)

capacity = max(capacity, boosted_util);

else

capacity = max(capacity, scr->total); //获取一个Cluster里CPU的最大负载

 

capacity = uclamp_min > capacity ? uclamp_min : capacity;

}

/* get real world frequency */ 根据负载计算需要的新频率

freq_new = capacity * cpu_max_freq >> SCHED_CAPACITY_SHIFT;

/* to get frequency in real world */ 从CPU支持的频率中找打最匹配的一个

freq_new = mt_cpufreq_find_close_freq(cid, freq_new);

 

/* get throttling type */

throttle = freq_new < cur_freq ?

gd->down_throttle : gd->up_throttle;

gd->thro_type = freq_new < cur_freq ?

DVFS_THROTTLE_DOWN : DVFS_THROTTLE_UP;

 

/* No throttling in time? Bail and return. */

if (ktime_before(now, throttle))

goto out;

//重新设置CPU频率

cpufreq_sched_try_driver_target(cpu, policy, freq_new, type);

}

 

static void cpufreq_sched_try_driver_target(int target_cpu, struct cpufreq_policy *policy,

unsigned int freq, int type)

{

mt_cpufreq_set_by_wfi_load_cluster(cid, freq);

/ * update throttle time:

* avoid inteference betwewn increasing/decreasing OPP. */

gd->up_throttle = ktime_add_ns(cur_time, gd->up_throttle_nsec);

gd->down_throttle = ktime_add_ns(cur_time, gd->down_throttle_nsec);

gd->throttle = ktime_add_ns(cur_time, gd->throttle_nsec);

 

}

 

二,DEBUG

cat /sys/devices/system/cpu/cpufreq/policy0/sched/down_throttle_nsec

0

cat /sys/devices/system/cpu/cpufreq/policy0/sched/up_throttle_nsec

0

#cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors

schedplus ondemand userspace powersave interactive performance

 

三,小结

1. MT6761的CPU频率可以快速调整,不需要创建线程做慢速调整

2. 可以调高down_throttle_nsec = 10ms, 减少CPU降频的频度,由此提高性能

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值