cpufreq 代码分析
cpufreq 代码分析
基础知识:
1.cpufreq 的五种模式
2.cpufreq 的框架
cpufreq 代码分析
从 drivers\cpufreq\Makefile 开始,(注:我的是linux-4.14.63)
# SPDX-License-Identifier: GPL-2.0
# CPUfreq core
obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o # cpufreq core 代码# CPUfreq stats
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o # cpufreq stats # CPUfreq governors
obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o # 对应于cpufreq 五种模式
obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o
obj-$(CONFIG_CPU_FREQ_GOV_ATTR_SET) += cpufreq_governor_attr_set.oobj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o # cpufreq_driver dt 表示设备树版
obj-$(CONFIG_CPUFREQ_DT_PLATDEV) += cpufreq-dt-platdev.o
//....
驱动入口:
cpufreq-dt.c:
static struct platform_driver dt_cpufreq_platdrv = {.driver = {.name = "cpufreq-dt",},.probe = dt_cpufreq_probe,.remove = dt_cpufreq_remove,
};
module_platform_driver(dt_cpufreq_platdrv);
可以看出这是个平台驱动,与之对应的平台设备的添加在cpufreq-dt-platdev.c:
static int __init cpufreq_dt_platdev_init(void)
{create_pdev:of_node_put(np);return PTR_ERR_OR_ZERO(platform_device_register_data(NULL, "cpufreq-dt",-1, data,sizeof(struct cpufreq_dt_platform_data)));
}
device_initcall(cpufreq_dt_platdev_init);
device_initcall(cpufreq_dt_platdev_init); 表示该函数在内核启动过程中会被调用。
继续看 probe 函数,dt_cpufreq_probe:
ret = cpufreq_register_driver(&dt_cpufreq_driver);
dt_cpufreq_driver 的定义
static struct cpufreq_driver dt_cpufreq_driver = {.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,.verify = cpufreq_generic_frequency_table_verify,.target_index = set_target,.get = cpufreq_generic_get,.init = cpufreq_init,.exit = cpufreq_exit,.ready = cpufreq_ready,.name = "cpufreq-dt",.attr = cpufreq_dt_attr,.suspend = cpufreq_generic_suspend,c
};
继续跟踪 cpufreq_register_driver
int cpufreq_register_driver(struct cpufreq_driver *driver_data){ cpufreq_driver = driver_data; // 1.给 cpufreq_driver 赋值 ret = subsys_interface_register(&cpufreq_interface); // 2.注册 cpufreq_interface // ...
}
cpufreq_interface 的定义
static struct subsys_interface cpufreq_interface = {.name = "cpufreq",.subsys = &cpu_subsys,.add_dev = cpufreq_add_dev,.remove_dev = cpufreq_remove_dev,
};
subsys_interface_register 函数会调用 sif->add_dev 函数 ,即 cpufreq_add_dev
int subsys_interface_register(struct subsys_interface *sif)
{ if (sif->add_dev) { sif->add_dev(dev, sif); }
}
cpufreq_add_dev:
static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
{if (cpu_online(cpu)) {ret = cpufreq_online(cpu); }
}
cpufreq_online:
static int cpufreq_online(unsigned int cpu)
{/* call driver. From then on the cpufreq must be able* to accept all calls to ->verify and ->setpolicy for this CPU*/ret = cpufreq_driver->init(policy); // 1.调用 cpufreq_driver->init 函数 初始化policy down_write(&policy->rwsem); if (new_policy) {ret = cpufreq_add_dev_interface(policy); // 创建 sys 节点 cpufreq/scaling_cur_freq 等if (ret)goto out_exit_policy;cpufreq_stats_create_table(policy); // 创建 cpufreq/sys stats 节点write_lock_irqsave(&cpufreq_driver_lock, flags);list_add(&policy->policy_list, &cpufreq_policy_list); //write_unlock_irqrestore(&cpufreq_driver_lock, flags);}ret = cpufreq_init_policy(policy); // 初始化policy 的 governorup_write(&policy->rwsem);kobject_uevent(&policy->kobj, KOBJ_ADD);/* Callback for handling stuff after policy is ready */if (cpufreq_driver->ready)cpufreq_driver->ready(policy); // cpufreq_driver->ready , 创建了cpufreq_cooling_dev,// 与 thermal 系统关联pr_debug("initialization complete\n");return 0;}
cpufreq_driver->init -----------------> cpufreq_init ,主要是填充policy结构体中的 freq_table
static int cpufreq_init(struct cpufreq_policy *policy)
{ dev_pm_opp_of_cpumask_add_table(policy->cpus); // 从dts 中读取 opp cpufreq tablepriv = kzalloc(sizeof(*priv), GFP_KERNEL);if (!priv) {ret = -ENOMEM;goto out_free_opp;}priv->reg_name = name;priv->opp_table = opp_table;ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table); //取出 freq_tableif (ret) {dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);goto out_free_priv;}priv->cpu_dev = cpu_dev;policy->driver_data = priv;policy->clk = cpu_clk;policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000;ret = cpufreq_table_validate_and_show(policy, freq_table); // freq_table 填入 policytransition_latency = dev_pm_opp_get_max_transition_latency(cpu_dev);if (!transition_latency)transition_latency = CPUFREQ_ETERNAL;policy->cpuinfo.transition_latency = transition_latency;policy->dvfs_possible_from_any_cpu = true;return 0;}
小结:cpufreq_driver 注册时序图:
接上面:cpufre_online -> cpufreq_init_policy , 继续跟踪
cpufreq_init_policy:
static int cpufreq_init_policy(struct cpufreq_policy *policy)
{new_policy.governor = gov; /* set default policy */return cpufreq_set_policy(policy, &new_policy); // cpufreq_set_policy
}
cpufreq_set_policy:
static int cpufreq_set_policy(struct cpufreq_policy *policy,struct cpufreq_policy *new_policy)
{ /* start new governor */policy->governor = new_policy->governor;ret = cpufreq_init_governor(policy);if (!ret) {ret = cpufreq_start_governor(policy); // start_governor } return ret;
}
cpufreq_start_governor:
static int cpufreq_start_governor(struct cpufreq_policy *policy)
{int ret;if (cpufreq_suspended)return 0;if (!policy->governor)return -EINVAL;pr_debug("%s: for CPU %u\n", __func__, policy->cpu);if (cpufreq_driver->get && !cpufreq_driver->setpolicy)cpufreq_update_current_freq(policy);if (policy->governor->start) {ret = policy->governor->start(policy); // governor->start if (ret)return ret;}if (policy->governor->limits)policy->governor->limits(policy); // governor->limitsreturn 0;
}
governor->start , 以 ondemand 为例
static struct dbs_governor od_dbs_gov = {.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("ondemand"),.kobj_type = { .default_attrs = od_attributes },.gov_dbs_update = od_dbs_update,.alloc = od_alloc,.free = od_free,.init = od_init,.exit = od_exit,.start = od_start,
};
#define CPUFREQ_DBS_GOVERNOR_INITIALIZER(_name_) \{ \.name = _name_, \.dynamic_switching = true, \.owner = THIS_MODULE, \.init = cpufreq_dbs_governor_init, \.exit = cpufreq_dbs_governor_exit, \.start = cpufreq_dbs_governor_start, \.stop = cpufreq_dbs_governor_stop, \.limits = cpufreq_dbs_governor_limits, \}
governor->start 就对应于cpufreq_dbs_governor_start
int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
{gov->start(policy); // gov->start ----- od_startgov_set_update_util(policy_dbs, sampling_rate);return 0;
}
static void gov_set_update_util(struct policy_dbs_info *policy_dbs,unsigned int delay_us)
{for_each_cpu(cpu, policy->cpus) {struct cpu_dbs_info *cdbs = &per_cpu(cpu_dbs, cpu);cpufreq_add_update_util_hook(cpu, &cdbs->update_util,dbs_update_util_handler); // dbs_update_util_handler}
}
dbs_update_util_handler
static void dbs_update_util_handler(struct update_util_data *data, u64 time,unsigned int flags)
{irq_work_queue(&policy_dbs->irq_work); // irq_work
}
init_irq_work(&policy_dbs->irq_work, dbs_irq_work);INIT_WORK(&policy_dbs->work, dbs_work_handler);
static void dbs_irq_work(struct irq_work *irq_work)
{struct policy_dbs_info *policy_dbs;policy_dbs = container_of(irq_work, struct policy_dbs_info, irq_work);schedule_work_on(smp_processor_id(), &policy_dbs->work); //---> dbs_work_handler
}
static void dbs_work_handler(struct work_struct *work)
{ gov_update_sample_delay(policy_dbs, gov->gov_dbs_update(policy)); //---> od_dbs_update
}
static unsigned int od_dbs_update(struct cpufreq_policy *policy)
{od_update(policy); // od_updatereturn dbs_data->sampling_rate * policy_dbs->rate_mult;
}
od_update
/** Every sampling_rate, we check, if current idle time is less than 20%* (default), then we try to increase frequency. Else, we adjust the frequency* proportional to load.*/
static void od_update(struct cpufreq_policy *policy)
{/* Check for frequency increase */if (load > dbs_data->up_threshold) { // 根据负载来动态调整cpu频率/* If switching to max speed, apply sampling_down_factor */if (policy->cur < policy->max)policy_dbs->rate_mult = dbs_data->sampling_down_factor;dbs_freq_increase(policy, policy->max);} else {/* Calculate the next frequency proportional to load */unsigned int freq_next, min_f, max_f;min_f = policy->cpuinfo.min_freq;max_f = policy->cpuinfo.max_freq;freq_next = min_f + load * (max_f - min_f) / 100;/* No longer fully busy, reset rate_mult */policy_dbs->rate_mult = 1;if (od_tuners->powersave_bias)freq_next = od_ops.powersave_bias_target(policy,freq_next,CPUFREQ_RELATION_L);__cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_C);}
}
小结:cpu_policy 时序图
cpufreq 代码分析相关推荐
- 20145236《网络攻防》Exp4 恶意代码分析
20145236<网络攻防>Exp4 恶意代码分析 一.基础问题回答 如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些 ...
- C#中类的继承 override virtual new的作用以及代码分析
继承中override virtual new的作用 virtual 父类中需要注明允许重写的方法: override 子类中必须显示声明该方法是重写的父类中的方法: new 子类中忽略父类的已存在的 ...
- 2017.4.18 静态代码分析工具sonarqube+sonar-runner的安装配置及使用
配置成功后的代码分析页面: 可以看到对复杂度.语法使用.重复度等等都做了分析,具体到了每一个方法和每一句代码. 四种使用方式: sonarqube + sonar-runner sonarqube + ...
- lighttpd1.4.18代码分析
lighttpd1.4.18代码分析(八)--状态机(2)CON_STATE_READ状态 posted @ 2008-09-24 10:50 那谁 阅读(2225) | 评论 (1) 编辑 lig ...
- Device Tree(三):代码分析
2019独角兽企业重金招聘Python工程师标准>>> 一.前言 Device Tree总共有三篇,分别是: 1.为何要引入Device Tree,这个机制是用来解决什么问题的?(请 ...
- 使用Hadoop和ELK进行业务代码分析!分分钟捉到Bug!
大数据是计算领域的新高地,它有望提供一种方法来应对二十一世纪不断增长的数据生成.越来越多的大数据爱好者正在涌现,越来越多的公司正在采用各种大数据平台,并希望提出以客户为中心的解决方案,帮助他们在竞争激 ...
- 20145328 《网络对抗技术》恶意代码分析
20145328 <网络对抗技术>恶意代码分析 ------看到这句话说明还没写完-------- 实践内容: 使用schtasks指令监控系统运行 使用sysmon工具监控系统运行 使用 ...
- starGAN原理代码分析
下载: git clone https://github.com/yunjey/StarGAN.git 1 cd StarGAN/ 1 下载celebA训练数据: bash download.sh 1 ...
- tensorflow笔记:多层CNN代码分析
tensorflow笔记系列: (一) tensorflow笔记:流程,概念和简单代码注释 (二) tensorflow笔记:多层CNN代码分析 (三) tensorflow笔记:多层LSTM代 ...
- ARM裸机篇---启动代码分析
ARM裸机篇---启动代码分析 先搞清楚启动代码和Bootloader的区别,启动代码是指CPU复位后到进入C语言的main函数之前需要执行的那段汇编代码. 下面的代码先暂且这样吧,没啥注释的,时间关 ...
最新文章
- 微信小程序Java登录流程(ssm实现具体功能和加解密隐私信息问题解决方案)
- VTK:PolyData之EmbedPointsIntoVolume
- AR与大数据 珠联璧合带来的无限想象空间
- 不属于前后端分离的Vue+Django的例子
- 需求奇葩不可怕,可怕的是变幻无常
- 正则化、归一化含义解析(一)
- iPhone降价后销量惊人 库克本周将再度访华
- Vagrant:将装在C盘的虚拟机移动到别的目录
- IMEI,手机号,身份证号格式有效性校验
- 华为OD(外包)社招技术二面,总结复盘
- FTP 通过cmd命令上传下载文件
- 厦门大学计算机系夏令营考什么,2018年厦门大学全校33个学院保研夏令营信息汇总,读研不止一条路...
- 《暗时间》读后感(一)——确实需要学习一些心理学有关的内容
- 2021:Check it again:Progressive Visual Question Answering via Visual Entailment通过视觉暗示进行渐进式视觉问答
- # Linux学习笔记
- python找素数程序_求素数python
- 快手视频艾特实操教学分享,什么是艾特脚本,评论区艾特引流脚本讲解!
- XSL中特殊符号详解
- java endpoint原理_Endpoint
- 大学内的云计算解决方案
热门文章
- 我们一起追逐过的大肥猫——tomcat部署
- Error Client wants topic A to have B, but our version has C. Dropping connection.
- linux:为xamp添加mysql的环境变量
- c#语言小括号里面的逗号是什么意思
- gin框架下参数的自定义验证小示例
- 对数似然比LLR公式的问题
- MySql安装 Staring the server出错
- 苹果公司的iPhone产品以及其历史
- requestLayout() improperly called by
- nuxt实现服务端渲染查看源代码显示动态接口数据