对照ftrace跟踪cpufreq 的结果,分析cpufreq工作过程
AUTHOR: Joseph Yang (杨红刚) <ganggexiongqi@gmail.com>
CONTENT: 对照ftrace跟踪cpufreq 的结果,分析cpufreq工作过程
NOTE: linux-3.0
LAST MODIFIED:09-19-2011
-----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (分布式嵌入式系统实验室,兰州大学)
//说明: 有些函数或宏无法跟踪到,
结构:
1. 操作步骤
2. 跟踪结果
3.跟踪结果分析
4. func_list_latest
=========================================================================
1 ------------------ 操作步骤
Snail:/home/snail/Desktop# mount -t debugfs nodev /sys/kernel/debug
Snail:/home/snail/Desktop# cd /sys/kernel/debug/tracing/
Snail:/sys/kernel/debug/tracing# cat /tmp/func_list_latest > set_ftrace_filter
Snail:/sys/kernel/debug/tracing# echo function_graph > current_tracer
Snail:/sys/kernel/debug/tracing# sysctl kernel.ftrace_enabled=1
kernel.ftrace_enabled = 1
Snail:/sys/kernel/debug/tracing# echo 1 > tracing_enabled
Snail:/sys/kernel/debug/tracing# cat trace_pipe > /tmp/result&
[1] 4618
//do sth
Snail:/sys/devices/system/cpu/cpu0/cpufreq# cat scaling_governor
performance
Snail:/sys/devices/system/cpu/cpu0/cpufreq# cat affected_cpus
0
Snail:/sys/devices/system/cpu/cpu0/cpufreq# cat related_cpus
0
Snail:/sys/devices/system/cpu/cpu0/cpufreq# cat scaling_available_governors
conservative ondemand userspace powersave performance
Snail:/sys/devices/system/cpu/cpu0/cpufreq# echo userspace > scaling_governor
Snail:/sys/devices/system/cpu/cpu0/cpufreq# cat scaling_available_frequencies
350000 700000 1050000 1400000 1750000 2100000 2450000 2800000
Snail:/sys/devices/system/cpu/cpu0/cpufreq# echo 2450000 > scaling_setspeed
Snail:/sys/devices/system/cpu/cpu0/cpufreq# cat stats/total_trans
1
//end trace
Snail:/sys/kernel/debug/tracing# echo 0 > tracing_enabled
Snail:/sys/kernel/debug/tracing#
[1]+ Done cat trace_pipe > /tmp/result
Snail:/sys/kernel/debug/tracing# vim /tmp/result
Snail:/sys/kernel/debug/tracing# cat /tmp/result > /home/snail/Desktop/cpufreq-trace/result_latest
2 -------------------跟踪结果
//cat scaling_governor
0) | show() {
0) 2.492 us | cpufreq_cpu_get();
0) 3.528 us | show_scaling_governor();
0) 0.170 us | unlock_policy_rwsem_read();
0) 0.873 us | cpufreq_cpu_put();
0) + 13.733 us | }
------------------------------------------
0) cat-4950 => cat-4975 // cat affected_cpus
------------------------------------------
0) | show() {
0) 2.742 us | cpufreq_cpu_get();
0) | show_affected_cpus() {
0) 4.386 us | show_cpus();
0) 5.438 us | }
0) 0.169 us | unlock_policy_rwsem_read();
0) 0.769 us | cpufreq_cpu_put();
0) + 15.400 us | }
------------------------------------------
0) cat-4975 => cat-4985 // cat related_cpus
------------------------------------------
0) | show() {
0) 2.571 us | cpufreq_cpu_get();
0) | show_related_cpus() {
0) 3.999 us | show_cpus();
0) 5.074 us | }
0) 0.167 us | unlock_policy_rwsem_read();
0) 0.827 us | cpufreq_cpu_put();
0) + 14.607 us | }
------------------------------------------
0) cat-4985 => cat-5013 //cat scaling_available_governors
------------------------------------------
0) | show() {
0) 2.667 us | cpufreq_cpu_get();
0) 5.805 us | show_scaling_available_governors();
0) 0.161 us | unlock_policy_rwsem_read();
0) 0.850 us | cpufreq_cpu_put();
0) + 15.648 us | }
------------------------------------------
0) cat-5013 => bash-4850 //echo userspace > scaling_governor
------------------------------------------
0) | store() {
0) 2.506 us | cpufreq_cpu_get();
0) | store_scaling_governor() {
0) | cpufreq_get_policy() {
0) 0.223 us | cpufreq_cpu_get();
0) 0.832 us | cpufreq_cpu_put();
0) 3.395 us | }
0) 1.398 us | __find_governor();
0) | __cpufreq_set_policy() {
0) 0.469 us | __cpufreq_governor();
0) | __cpufreq_governor() {
0) 1.050 us | cpufreq_register_notifier();
0) 4.993 us | }
0) | __cpufreq_governor() {
0) 0.777 us | __cpufreq_driver_target();
0) 3.198 us | }
0) + 16.492 us | }
0) + 26.564 us | }
0) 0.284 us | unlock_policy_rwsem_write();
0) 0.237 us | cpufreq_cpu_put();
0) + 35.884 us | }
------------------------------------------
0) bash-4850 => cat-5092 //cat scaling_available_frequencies
------------------------------------------
0) | show() {
0) 2.736 us | cpufreq_cpu_get();
0) 0.160 us | unlock_policy_rwsem_read();
0) 1.063 us | cpufreq_cpu_put();
0) + 16.599 us | }
------------------------------------------
0) cat-5092 => bash-4850 //echo 2450000 > scaling_setspeed
------------------------------------------
0) | store() {
0) 2.583 us | cpufreq_cpu_get();
0) | store_scaling_setspeed() {
0) | __cpufreq_driver_target() {
0) | cpufreq_notify_transition() {
0) 0.330 us | adjust_jiffies();
0) 7.025 us | }
0) | cpufreq_notify_transition() {
0) 0.170 us | adjust_jiffies();
0) 5.439 us | }
0) + 19.767 us | }
0) + 24.867 us | }
0) 0.300 us | unlock_policy_rwsem_write();
0) 0.979 us | cpufreq_cpu_put();
0) + 35.445 us | }
------------------------------------------
0) bash-4850 => cat-5153 //cat stats/total_trans
------------------------------------------
0) | show() {
0) 3.269 us | cpufreq_cpu_get();
0) 0.190 us | unlock_policy_rwsem_read();
0) 0.925 us | cpufreq_cpu_put();
0) + 17.763 us | }
3 ----------------------跟踪结果分析
我们分析下切换governor的过程:
用户空间用户设置参数,内核空间要调用 store(),
在store()中,
调用cpufreq_cpu_get() 取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
对cpufreq_cpu_data引用计数增一。然后要调用lock_policy_rwsem_write取得
获取写锁cpu_policy_rwsem。
再调用ret = fattr->store(policy, buf, count);根据我们使用ftrace跟踪的结果可以看出,
实际调用了 store_scaling_governor()。该函数 为指定的CPU存储 policy。
该函数调用cpufreq_get_policy()取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
对cpufreq_cpu_data引用计数增一。再把从用户空间传递过来的governor的名字
存入局部变量str_governor中。
之后调用cpufreq_parse_governor对保存在str_governor中的
governor名字进行解析,如果名字为performance或者powersave,则在入口参数policy中
返回相应指示。否则,调用__find_governor将str_governor与cpufreq_governor_list上各个\
governor比较,有跟str_governor相同的governor则返回它对应的结构的指针到入口
参数governor。
接着,调用__cpufreq_set_policy设置新的policy [1],它复制旧policy 的
cpuinfo域到新的policy的cpuinfo域。检查如果频率参数设置。再检查cpu的运行频率
可以设定到新policy的指定的范围内。通知链上的各个事件监听者根据自己的特殊
要求调整policy(CPUFREQ_ADJUST)。通知链上的各个事件监听者,如果硬件不兼容
的话,可以调整policy(CPUFREQ_INCOMPATIBLE)。再检查cpu的运行频率可以设定
到新policy的指定的范围内。通知链上的各个事件监听者新的policy启用。这时
不兼容的硬件将会被停止,并向用户通知。
接下来,如果定义了cpufreq_driver->setpolicy方法,则调用。否则,调用__cpufreq_governor
(CPUFREQ_GOV_STOP), 即,停止governor对相应cpu的管理。
设置新的governor,调用__cpufreq_governor(CPUFREQ_GOV_START)。在__cpufreq_governor
中,间接调用了cpufreq_register_notifier,通知监听者
CPUFREQ_POLICY_NOTIFIER --- policy改变。 再次调用__cpufreq_governor(CPUFREQ_GOV_LIMITS),
通知链上的各个事件监听者cpu的频率范围已经改变。间接调用了
__cpufreq_driver_target 用于执行cpufreq_driver->target。
调用unlock_policy_rwsem_write释放锁cpu_policy_rwsem。调用cpufreq_cpu_put,
对cpufreq_policy* 类型data所指向的结构的引用计数减一。store执行完毕,返回。
[1] : policy由三部分组成: "policy,governor,min,max"
再次,分析下频率切换的处理(这里,governor已经切换为 userspace)
用户空间用户设置参数,内核空间要调用 store(),
在store()中,
调用cpufreq_cpu_get() 取得cpufreq_policy 类型的cpufreq_cpu_data的副本,
对cpufreq_cpu_data引用计数增一。然后要调用lock_policy_rwsem_write取得
获取写锁cpu_policy_rwsem。
调用store_scaling_setspeed用于设置新的频率。
policy->governor->store_setspeed(policy, freq),该语句,间接调用了
__cpufreq_driver_target, 在__cpufreq_driver_target执行期间,
cpufreq_notify_transition两次被调用(可能CPUFREQ_PRECHANGE/CPUFREQ_POSTCHANGE)。
cpufreq_transition_notifier_list链上的监听者, 被通知频率的改变。并调用,
adjust_jiffies,重新计算更新loops_per_jiffy值。
调用unlock_policy_rwsem_write释放锁cpu_policy_rwsem。调用cpufreq_cpu_put,
对cpufreq_policy* 类型data所指向的结构的引用计数减一。
4 -------------func_list_latest
unlock_policy_rwsem_read
unlock_policy_rwsem_write
cpufreq_cpu_get
cpufreq_cpu_put
adjust_jiffies
cpufreq_notify_transition
__find_governor
show_cpuinfo_cur_freq
show_scaling_governor
store_scaling_governor
show_scaling_driver
show_scaling_available_governors
show_cpus
show_related_cpus
show_affected_cpus
store_scaling_setspeed
show_scaling_setspeed
show_bios_limit
show
store
cpufreq_sysfs_release
cpufreq_add_dev
cpufreq_remove_dev
cpufreq_get
cpufreq_bp_suspend
cpufreq_bp_resume
cpufreq_register_notifier
cpufreq_unregister_notifier
__cpufreq_driver_target
cpufreq_driver_target
__cpufreq_driver_getavg
__cpufreq_governor
cpufreq_register_governor
cpufreq_unregister_governor
cpufreq_get_policy
__cpufreq_set_policy
cpufreq_update_policy
cpufreq_register_driver
cpufreq_unregister_driver
更多推荐
所有评论(0)