MTK平台CPU/GPU动态调频的实现之PerfService的源码分析
MTK fpsgo
FPSGO是一个降低power的模块,它采集UI、Game、Camera场景的fps;在先保证fps的前提下,根据策略压频节省功耗。它与FWK对接,只有Q到surfaceflinger的buffer才会被跟踪参与计算 。
PPM power 性能管理
fbt frame budget tuner 帧预测及调频
fstb 帧稳定
opp 操作cpu 频点
lpp 低功耗
fps go 是对用户 ux 和 优先 game 场景
fstb 根据显示模块fps 和 系统信息,确定目标fps ,发送给 pfs policy service;
fbt 根据目标fps 预估每帧需要最新系统能力,给到booter
cpu
整个CPU系统的拓扑结构。处理器发展到今天,在手机这种对于性能与功耗要求极高,同时电池容量又受到限制的产品类型上,一般都是采用了B-L(Big-Little)架构,即大小核架构。小核也被称为功耗核心(Power Core),其性能稍弱,但是耗电比较低,通常被用来处理诸如电子书、浏览器此类对性能要求较低的轻负载场景;大核也被称为性能核心(Performance Core),其性能较强,但是耗电也高,被用来处理MOBA(Multiplayer Online Battle Arena,多人在线战术竞技游戏)游戏、相机等对于性能要求较高的高负载场景。
以上图的这款8核心(4个功耗核心+4个性能核心)的CPU处理器为例,8个CPU核心被分为了2个簇(cluster),其中4个功耗核心在同一个簇上,另外4个性能核心在同一个簇上。基于成本考虑,一般同一个簇上的CPU都由同一个时钟源(clock)提供时钟输入,并由同一路regulator电源进行供电。
CPUfreq框架大体可以分为下面几个模块:
1) 驱动层:提供不同类型CPU的调节频率的驱动能力
2) Governor:提供动态调频的算法
3) 核心层:计算机领域的任何问题都可以通过增加一个间接的中间层来解决,CPUfreq核心层其实就是一个中间层,向下提供不同类型CPU驱动的框架接口(注册cpufreq_driver驱动),向上提供不同调频governor的算法接口(注册cpufreq_governor)。同时统一提供对外的API跟sysfs调试接口。我们在进行一些性能功耗的基础调试的时候,会用到了一些sysfs debug的的接口
/sys/module/cpufreq/parameters/
/sys/devices/system/cpu # ls
cpu0 cpu3 cpu6 cpuidle isolated offline possible sched_isolated
cpu1 cpu4 cpu7 eas kernel_max online power uevent
cpu2 cpu5 cpufreq hotplug modalias perf present vulnerabilities
/sys/devices/system/cpu # ls cpu0/cpufreq/
affected_cpus scaling_available_frequencies scaling_min_freq
cpuinfo_cur_freq scaling_available_governors scaling_setspeed
cpuinfo_max_freq scaling_cur_freq schedutil/
cpuinfo_min_freq scaling_driver stats/
cpuinfo_transition_latency scaling_governor
related_cpus scaling_max_freq
参考
CPUFreq简介_内核工匠的博客-CSDN博客
performance 具体的性能模式运行于最大频率
powersave 运行于最小频率
userspace 运行于用户指定的频率
ondemand 按需快速动态调整CPU频率, 一有cpu计算量的任务,就会立即达到最大频率运行,空闲时间增加就降低频率
conservative 按需快速动态调整CPU频率, 比 ondemand 的调整更保守
schedutil 基于调度程序调整 CPU 频率
fpsgo main
kernel-5.10\drivers\misc\mediatek\performance\fpsgo_v3\fpsgo_main.c
fpsgo_cpu_policy_init() 从cpufre 频率策略获取每个策略的频率点
fpsgo_sysfs_init() 创建对应sys fs节点
/sys #
./kernel/fpsgo
./kernel/tracing/events/fpsgo
./module/fpsgo
init_fpsgo_common() 创建common 目录及节点
/sys/kernel/fpsgo/common #
BQid force_onoff fpsgo_enable gpu_block_boost render_info stop_boost systrace_mask
fbt_cpu_init(); 这里会注册platform 设备 fpsgo 驱动,创建fbt 节点等
/sys/kernel/fpsgo/fbt #
boost_ta fbt_info limit_rfreq table
enable_switch_cap_margin light_loading_policy limit_rfreq_m ultra_rescue
enable_switch_down_throttle limit_cfreq llf_task_policy
enable_switch_sync_flag limit_cfreq_m switch_idleprefer
mtk_fstb_init(); 创建 fstb
/sys/kernel/fpsgo/fstb #
adopt_low_fps fstb_tune_error_threshold margin_mode margin_mode_gpu_dbnc_b
fpsgo_status fstb_tune_quantile margin_mode_dbnc_a set_render_max_fps
fstb_debug fstb_tune_window_size margin_mode_dbnc_b set_render_no_ctrl
fstb_fps_list jump_check_num margin_mode_gpu
fstb_soft_level jump_check_q_pct margin_mode_gpu_dbnc_a
init_gbe_common();
sys/kernel/gbe # 游戏加速
gbe2_fg_pid gbe2_max_boost_cnt gbe2_timer2 gbe_boost_list2 gbe_enable2
gbe2_loading_th gbe2_timer1 gbe_boost_list1 gbe_enable1 gbe_policy_mask
enum GBE_BOOST_DEVICE {
GBE_BOOST_UNKNOWN = -1,
GBE_BOOST_CPU = 0,
GBE_BOOST_EAS = 1,
GBE_BOOST_VCORE = 2,
GBE_BOOST_IO = 3,
GBE_BOOST_HE = 4,
GBE_BOOST_GPU = 5,
GBE_BOOST_LLF = 6,
GBE_BOOST_NUM = 7,
};
fbt 控制cpu
PM QoS 和 DVFS
为了提高电池的使用寿命,为了节省功耗,linux引入了DVFS。而为了应用程序的性能,Linux 又引入了PM QoS。下图是linux kernel power 管理中PM QOS和DVFS相关的架构图。
PM QoS 和 DVFS - 腾讯云开发者社区-腾讯云
根据上面2类constraint,Linux kernel提供了2个不同的QoS framework:
一个是系统级别的,用于cpu&dma latency、network latency、network throughput、memory bandwidth等场合,称作PM QoS classes framework。
另一个是device级别的,用于per-device场合,称作per-device PM QoS framework。
这2个framework有着共同的目标,即:向requestors提供request的add、modify、remove等接口,用于管理QoS requests;将QoS requests分门别类,计算出极值(简称value);向requestee提供request value的查询接口。其软件架构(非常简单)如下
PM QoS classes framework位于kernel/power/qos.c中,负责系统级别的PM QoS管理。per-device PM QoS framework位于drivers/base/power/qos.c中,负责per-device的PM QoS管理。Common header位于include/linux/pm_qos.h中,负责通用数据结构的抽象、函数声明等工作。
需要说明的是,PM QoS classes framework会通过misc设备,向用户空间程序提供PM QoS的request、modify、remove功能,以便照顾到它们对PM QoS的需求。
DVFS
功耗与性能系列之DVFS功能特性介绍_cpu
cpupower-utils
kernel-4.19/tools/power/cpupower/
perf tools
kernel-4.19/tools/perf/
linux perf tool的编译以及使用
fbt_cpu_ctrl.c
int fbt_cpu_ctrl_init(void)
{
int i, cpu_num;
pr_info("%s init\n", __func__);
if (fbt_cpu_topo_info() < 0)
return -EFAULT;
g_psCpuLoadingWorkQueue =
create_singlethread_workqueue("fpt_cpu_load_wq");
if (g_psCpuLoadingWorkQueue == NULL)
return -EFAULT;
/*timer init*/
hrtimer_init(&cpu_ctrl_hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
cpu_ctrl_hrt.function = &handle_cpu_loading_timeout;
g_psFbtCpuCtrlWorkQueue =
create_singlethread_workqueue("fpt_cpu_ctrl_wq");
if (g_psFbtCpuCtrlWorkQueue == NULL)
return -EFAULT;
fbt_cur_ceiling = kcalloc(policy_num,
sizeof(struct cpufreq_policy *), GFP_KERNEL);
fbt_last_ceiling = kcalloc(policy_num,
sizeof(struct cpufreq_policy *), GFP_KERNEL);
fbt_final_ceiling = kcalloc(policy_num,
sizeof(struct freq_qos_request), GFP_KERNEL);
fbt_cur_floor = kcalloc(policy_num,
sizeof(struct freq_qos_request), GFP_KERNEL);
for (i = 0; i < policy_num; i++) {
fbt_cur_ceiling[i] = fbt_max_freq[i];
fbt_last_ceiling[i] = -1;
fbt_final_ceiling[i] = fbt_max_freq[i];
fbt_cur_floor[i] = fbt_min_freq[i];
}
cpu_num = num_possible_cpus();
if (cpu_num <= 0)
return -EFAULT;
kcalloc(cpu_num, sizeof(struct cpu_info), GFP_KERNEL);
kcalloc(cpu_num, sizeof(struct cpu_info), GFP_KERNEL);
kcalloc(cpu_num, sizeof(struct cpu_info), GFP_KERNEL);
kcalloc(cpu_num, sizeof(struct cpu_info), GFP_KERNEL);
for_each_possible_cpu(i) {
prev_wall_time[i].time = cur_wall_time[i].time = 0;
prev_idle_time[i].time = cur_idle_time[i].time = 0;
}
cfp_onoff = 1;
cfp_enable = 0;
cfp_polling_ms = 64;
cfp_up_time = 1;
cfp_down_time = 16;
cfp_up_loading = 90;
cfp_down_loading = 80;
/* cfp request */
for (i = 0; i < CFP_KIR_MAX_NUM; i++) {
cfp_req_tbl[i].enabled = 0;
cfp_req_tbl[i].cb = NULL;
}
pr_info("%s done\n", __func__);
return 0;
}