cpufreq动态频率调节(Sofia3GR)浅析及应用层APK实现
2016-10-26 16:22
537 查看
cpufreq动态频率调节浅析
cpufreq核心部分的代码都在:/drivers/cpufreq/cpufreq.c中,本文章是基于SOFIA3GR 6.0的代码进行解析,linux内核版本3.14.0。具体cpufreq核心(core)架构与API可参考:http://blog.csdn.net/droidphone/article/details/9385745
这里主要针对cpufreq的sysfs接口进行解析及apk实现定频功能
所有与cpufreq相关的sysfs接口都位于/sys/devices/system/cpu下面:
其中:
cpu0到cpu7代表我们这个cpu是四核的,有四个cpu
online:代表正在工作的cpu
offline:代表未工作被关闭的cpu
present:代表主板上已经安装的cpu
其中:kernel_max,version,possible这三个看下面代码输出容易理解,我们现在测试的也是RK es2.0的芯片
但modalias搞不懂,uevent为空
至此,还有几个目录
cpu0-cpu3,cpufreq,cpuidle,power
主要针对cpu0说明一下,cpu0里面的参数决定cpu频率调整模式,cpu频率设置的一些节点,cpu1,cpu2,cpu3设置都是基于cpu0的 所以只许更改cpu0的相关配置参数即可
1.android中有一个动态调整cpu频率的模块,会生成一个文件夹/sys/devices/system/cpu/cpu0/cpufreq/
现在着重分析cpu动态频率调节相关的cpu0/cpufreq相关
1.1 其中:cpuinfo_cur_freq cpuinfo_max_freq cpuinfo_min_freq这三个分别代表cpu当前运行频率,最高运行频率和最低运行频率,前缀cpuinfo代表的是cpu硬件上支持的频率,而scaling前缀代表的是可以通过CPUFreq系统用软件进行调节时所支持的频率,
cpuinfo_cur_freq代表通过硬件实际上读到的频率值,而scaling_cur_freq则是软件当前的设置值,多数情况下这两个值是一致的,但是也有可能因为硬件的原因,有微小的差异。scaling_available_frequencies会输出当前软件支持的频率值,看看我的cpu支持那些频率
代表我这个cpu的可选频率有416000 728000 900000 1040000 1200000 5个档位
实际代码中对应(voltage-table-v2代表不同频率对应的cpu电压):
同时我们得注意:scaling-min-freq和scaling-max-freq只能写上面数字的频率其他数字都是无效的
1.2 scaling_governor代表cpu频率调整模式
上述可以看出我们cpu支持的模式有四种:
performance :CPU会固定工作在其支持的最高运行频率上;
Userspace:最早的cpufreq 子系统通过userspace governor为用户提供了这种灵活性。系统将变频策略的决策权交给了用户态应用程序,并提供了相应的接口供用户态应用程序调节CPU 运行频率使用。
ondemand:userspace是内核态的检测,效率低。而ondemand正是人们长期以来希望看到的一个完全在内核态下工作并且能够以更加细粒度的时间间隔对系统负载情况进行采样分析的governor。
interactived
此模式在与用户交互的时候,反应速度更快(即是频率调节的速度更快,更能随时对及时处理器的符合作出反应),由此,便可以提供更好地用户体验(conservative模式反应速度慢于此,因此有时候会出现稍卡的体验)
当然,为了达成这一点,interactive有更高的处理器负荷采样率,并且摒弃了上述两种调节方式在高负荷时候处理器频率不满足需求以后才进行调频,interactive保证了更快的反应,保留了频率调节器的高优先级,来更快地处理器负荷高起来的时候将频提高。
还有一个模式我们cpu没有:
powersave:CPU会固定工作在其支持的最低运行频率上。因此这两种governors 都属于静态governor,即在使用它们时CPU 的运行频率不会根据系统运行时负载的变化动态作出调整。这两种governors 对应的是两种极端的应用场景,使用performance governor 是对系统高性能的最大追求,而使用powersave governor 则是对系统低功耗的最大追求。
参考http://bbs.hiapk.com/thread-1313181-1-1.html
当我们要设置软件cpu频率时一定要注意:(scaling_max_freq scaling_min_freq scaling_setspeed)
当我们选择userspace作为我们的调频governor时,我们可以通过scaling_setspeed手工设置需要的频率。powersave则简单地使用最低的工作频率进行运行,而performance则一直选择最高的频率进行运行。
现在我们以应用层设置cpu频率为例制作一个适应我们cpu的apk并贴出源码及效果:
1.我们必须先设置节点的权限 我们现在是在我们代码平台实现,device/rockchip/sofia3gr/init.rc(不同平台有差异)
加入如下四条命令:
增加scaling_governor权限主要是让我们用户能用scaling_setspeed设置cpu频率
scaling_setspeed主要用来设置cpu频率
上述命令也可以在adb shell中去设置前提是userdebug或者eng版本并且有root权限,执行
adb root
adb remount
权限设置好后如下命令设置governor策略为userspace
如果机器有温控管理记得关闭温控管理 此平台关闭方法
先在adb shell 中输入 setprop persist.service.the
eb30
rmal 0 ,并重启设备,以关掉Intel thermal app
之后我们便能设置scaling_setspeed了
这样cpu频率就运行在了728000
2.继续我们之前的apk怎么实现呢
将apk放入系统中编译:
在相应的mk文件中加入:
**PRODUCT_PACKAGES +=\
Cpufreq_for_intel**
3.apk源码
注意点
3.1 android.mk必须修改 6 LOCAL_CERTIFICATE := platform为平台签名apk
1. android.mk
1 LOCAL_PATH := (callmy−dir)2include(CLEAR_VARS)
3
4 LOCAL_PACKAGE_NAME := Cpufreq_for_intel
5 LOCAL_SRC_FILES := $(call all-subdir-java-files)
6 LOCAL_CERTIFICATE := platform
7 include $(BUILD_PACKAGE)
3.2 AndroidManifest.xml 需要加上如下属性
android:sharedUserId=”android.uid.system”
贴出部分源码:
MainActivity.java
AndroidManifest.xml 如下
apk源码下载:链接:http://pan.baidu.com/s/1cqXsq6 密码:0hd9
cpufreq核心部分的代码都在:/drivers/cpufreq/cpufreq.c中,本文章是基于SOFIA3GR 6.0的代码进行解析,linux内核版本3.14.0。具体cpufreq核心(core)架构与API可参考:http://blog.csdn.net/droidphone/article/details/9385745
这里主要针对cpufreq的sysfs接口进行解析及apk实现定频功能
C:\Users\qinfeng>adb shell root@TM800AR:/ # cd sys/devices/system/cpu cd sys/devices/system/cpu root@TM800AR:/sys/devices/system/cpu # ls ls cpu0 cpu1 cpu2 cpu3 cpufreq cpuidle kernel_max modalias offline online possible power present uevent version
所有与cpufreq相关的sysfs接口都位于/sys/devices/system/cpu下面:
其中:
cpu0到cpu7代表我们这个cpu是四核的,有四个cpu
online:代表正在工作的cpu
offline:代表未工作被关闭的cpu
present:代表主板上已经安装的cpu
root@TM800AR:/sys/devices/system/cpu # cat online cat online 0-3 root@TM800AR:/sys/devices/system/cpu # cat offline cat offline root@TM800AR:/sys/devices/system/cpu # cat present cat present 0-3
其中:kernel_max,version,possible这三个看下面代码输出容易理解,我们现在测试的也是RK es2.0的芯片
但modalias搞不懂,uevent为空
root@TM800AR:/sys/devices/system/cpu # cat kernel_max cat kernel_max 3 root@TM800AR:/sys/devices/system/cpu # cat version cat version es2.0 root@TM800AR:/sys/devices/system/cpu # cat possible cat possible 0-3 root@TM800AR:/sys/devices/system/cpu # cat modalias cat modalias x86cpu:vendor:0000:family:0006:model: 4000 005D:feature:,0000,0001,0002,0003,0004,0005,0006,0007,0008,0009,000B,000C,000D,000E,000F,0010,0013,0017,0018,0019,001A,001B,001C,0034,003B,003D,0068,006B,006F,0070,0072,0074,0075,0076,0080,0081,0083,0089,008D,008E,008F,0093,0094,0096,0097,0099,00C0,00C8,0121,0127,0129,012D,013F root@TM800AR:/sys/devices/system/cpu # cat uevent cat uevent root@TM800AR:/sys/devices/system/cpu #
至此,还有几个目录
cpu0-cpu3,cpufreq,cpuidle,power
主要针对cpu0说明一下,cpu0里面的参数决定cpu频率调整模式,cpu频率设置的一些节点,cpu1,cpu2,cpu3设置都是基于cpu0的 所以只许更改cpu0的相关配置参数即可
root@TM800AR:/sys/devices/system/cpu/cpu0 # ls -al ls -al drwxr-xr-x root root 2016-01-08 08:01 cache drwxr-xr-x root root 2016-01-08 08:01 cpufreq drwxr-xr-x root root 2016-01-08 08:01 cpuidle -r-------- root root 4096 2016-01-08 08:01 crash_notes -r-------- root root 4096 2016-01-08 08:01 crash_notes_size drwxr-xr-x root root 2016-01-08 08:01 power lrwxrwxrwx root root 2016-01-08 08:01 subsystem -> ../../../../bus/cpu drwxr-xr-x root root 2016-01-08 08:01 topology -rw-r--r-- root root 4096 2016-01-08 08:01 uevent
root@TM800AR:/sys/devices/system/cpu/cpu1 # ls -al ls -al drwxr-xr-x root root 2016-01-08 08:38 cache lrwxrwxrwx root root 2016-01-08 08:38 cpufreq -> ../cpu0/cpufreq drwxr-xr-x root root 2016-01-08 08:01 cpuidle -r-------- root root 4096 2016-01-08 08:01 crash_notes -r-------- root root 4096 2016-01-08 08:01 crash_notes_size -rw-r--r-- root root 4096 2016-01-08 08:01 online drwxr-xr-x root root 2016-01-08 08:01 power lrwxrwxrwx root root 2016-01-08 08:01 subsystem -> ../../../../bus/cpu drwxr-xr-x root root 2016-01-08 08:38 topology -rw-r--r-- root root 4096 2016-01-08 08:01 uevent
1.android中有一个动态调整cpu频率的模块,会生成一个文件夹/sys/devices/system/cpu/cpu0/cpufreq/
现在着重分析cpu动态频率调节相关的cpu0/cpufreq相关
127|root@TM800AR:/sys/devices/system/cpu/cpu0/cpufreq # ls ls affected_cpus cpuinfo_cur_freq cpuinfo_max_freq cpuinfo_min_freq cpuinfo_transition_latency related_cpus scaling_available_frequencies scaling_available_governors scaling_cur_freq scaling_driver scaling_governor scaling_max_freq scaling_min_freq scaling_setspeed stats thermal_scaling_max_freq
1.1 其中:cpuinfo_cur_freq cpuinfo_max_freq cpuinfo_min_freq这三个分别代表cpu当前运行频率,最高运行频率和最低运行频率,前缀cpuinfo代表的是cpu硬件上支持的频率,而scaling前缀代表的是可以通过CPUFreq系统用软件进行调节时所支持的频率,
cpuinfo_cur_freq代表通过硬件实际上读到的频率值,而scaling_cur_freq则是软件当前的设置值,多数情况下这两个值是一致的,但是也有可能因为硬件的原因,有微小的差异。scaling_available_frequencies会输出当前软件支持的频率值,看看我的cpu支持那些频率
1|root@TM800AR:/sys/devices/system/cpu/cpu0/cpufreq # cat scaling_available_frequencies at scaling_available_frequencies < 416000 728000 900000 1040000 1200000
代表我这个cpu的可选频率有416000 728000 900000 1040000 1200000 5个档位
实际代码中对应(voltage-table-v2代表不同频率对应的cpu电压):
&cpufreq { intel,cpufreq-table-v2 = <416000 728000 900000 1040000 1200000>; intel,voltage-table-v2 = <925000 1125000 1150000 1225000 1275000>; intel,vddcore-table-v2 = <VDD_CORE_MED VDD_CORE_HIGH VDD_CORE_HIGH VDD_CORE_HIGH VDD_CORE_HIGH>; };
同时我们得注意:scaling-min-freq和scaling-max-freq只能写上面数字的频率其他数字都是无效的
1.2 scaling_governor代表cpu频率调整模式
1|root@TM800AR:/sys/devices/system/cpu/cpu0/cpufreq # cat scaling_available_governors at scaling_available_governors < ondemand userspace interactive performance
上述可以看出我们cpu支持的模式有四种:
performance :CPU会固定工作在其支持的最高运行频率上;
Userspace:最早的cpufreq 子系统通过userspace governor为用户提供了这种灵活性。系统将变频策略的决策权交给了用户态应用程序,并提供了相应的接口供用户态应用程序调节CPU 运行频率使用。
ondemand:userspace是内核态的检测,效率低。而ondemand正是人们长期以来希望看到的一个完全在内核态下工作并且能够以更加细粒度的时间间隔对系统负载情况进行采样分析的governor。
interactived
此模式在与用户交互的时候,反应速度更快(即是频率调节的速度更快,更能随时对及时处理器的符合作出反应),由此,便可以提供更好地用户体验(conservative模式反应速度慢于此,因此有时候会出现稍卡的体验)
当然,为了达成这一点,interactive有更高的处理器负荷采样率,并且摒弃了上述两种调节方式在高负荷时候处理器频率不满足需求以后才进行调频,interactive保证了更快的反应,保留了频率调节器的高优先级,来更快地处理器负荷高起来的时候将频提高。
还有一个模式我们cpu没有:
powersave:CPU会固定工作在其支持的最低运行频率上。因此这两种governors 都属于静态governor,即在使用它们时CPU 的运行频率不会根据系统运行时负载的变化动态作出调整。这两种governors 对应的是两种极端的应用场景,使用performance governor 是对系统高性能的最大追求,而使用powersave governor 则是对系统低功耗的最大追求。
参考http://bbs.hiapk.com/thread-1313181-1-1.html
当我们要设置软件cpu频率时一定要注意:(scaling_max_freq scaling_min_freq scaling_setspeed)
当我们选择userspace作为我们的调频governor时,我们可以通过scaling_setspeed手工设置需要的频率。powersave则简单地使用最低的工作频率进行运行,而performance则一直选择最高的频率进行运行。
现在我们以应用层设置cpu频率为例制作一个适应我们cpu的apk并贴出源码及效果:
1.我们必须先设置节点的权限 我们现在是在我们代码平台实现,device/rockchip/sofia3gr/init.rc(不同平台有差异)
加入如下四条命令:
chown system system /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed chmod 0644 /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed chown system system /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor chmod 0644 /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
增加scaling_governor权限主要是让我们用户能用scaling_setspeed设置cpu频率
scaling_setspeed主要用来设置cpu频率
上述命令也可以在adb shell中去设置前提是userdebug或者eng版本并且有root权限,执行
adb root
adb remount
权限设置好后如下命令设置governor策略为userspace
root@TM800AR:/sys/devices/system/cpu/cpu0/cpufreq # cat scaling_governor cat scaling_governor interactive root@TM800AR:/sys/devices/system/cpu/cpu0/cpufreq # echo userspace > scaling_governor cho userspace > scaling_governor < root@TM800AR:/sys/devices/system/cpu/cpu0/cpufreq # cat scaling_governor cat scaling_governor userspace root@TM800AR:/sys/devices/system/cpu/cpu0/cpufreq #
如果机器有温控管理记得关闭温控管理 此平台关闭方法
先在adb shell 中输入 setprop persist.service.the
eb30
rmal 0 ,并重启设备,以关掉Intel thermal app
之后我们便能设置scaling_setspeed了
root@TM800AR:/sys/devices/system/cpu/cpu0/cpufreq # echo 728000 > scaling_setspeed cho 728000 > scaling_setspeed < root@TM800AR:/sys/devices/system/cpu/cpu0/cpufreq # cat cpuinfo_cur_freq cat cpuinfo_cur_freq 728000
这样cpu频率就运行在了728000
2.继续我们之前的apk怎么实现呢
将apk放入系统中编译:
在相应的mk文件中加入:
**PRODUCT_PACKAGES +=\
Cpufreq_for_intel**
3.apk源码
注意点
3.1 android.mk必须修改 6 LOCAL_CERTIFICATE := platform为平台签名apk
1. android.mk
1 LOCAL_PATH := (callmy−dir)2include(CLEAR_VARS)
3
4 LOCAL_PACKAGE_NAME := Cpufreq_for_intel
5 LOCAL_SRC_FILES := $(call all-subdir-java-files)
6 LOCAL_CERTIFICATE := platform
7 include $(BUILD_PACKAGE)
3.2 AndroidManifest.xml 需要加上如下属性
android:sharedUserId=”android.uid.system”
贴出部分源码:
MainActivity.java
package com.example.cpufreq_for_intel; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.DataOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.Settings.System; import android.app.Activity; import android.util.Log; import android.view.Menu; import android.widget.RadioButton; import android.widget.RadioGroup; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { private RadioGroup cpufreq_group = null; private RadioButton freq1 = null; private RadioButton freq2 = null; private RadioButton freq3 = null; private RadioButton freq4 = null; private RadioButton freq5 = null; private TextView tvCpu1 = null; Boolean thd = true; static String c1 = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"; static String c2 = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.i("012", "beginning cpuFreq Setting now!"); cpufreq_group = (RadioGroup) findViewById(R.id.radioGroup); freq1 = (RadioButton) findViewById(R.id.freq1); freq2 = (RadioButton) findViewById(R.id.freq2); freq3 = (RadioButton) findViewById(R.id.freq3); freq4 = (RadioButton) findViewById(R.id.freq4); freq5 = (RadioButton) findViewById(R.id.freq5); tvCpu1 = (TextView) findViewById(R.id.tvCpu1); setCurCpuFreqManager("userspace"); tvCpu1.setText("" + getCurCpuFreq()); cpufreq_group .setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup arg0, int arg1) { // TODO Auto-generated method stub if (arg1 == freq1.getId()) { setCurCpuFreq("1200000"); tvCpu1.setText("" + getCurCpuFreq()); Toast.makeText(getApplicationContext(), "cpuFreq set :1200000", Toast.LENGTH_SHORT) .show(); } else if (arg1 == freq2.getId()) { setCurCpuFreq("1040000"); tvCpu1.setText("" + getCurCpuFreq()); Toast.makeText(getApplicationContext(), "cpuFreq set :1040000", Toast.LENGTH_SHORT) .show(); } else if (arg1 == freq3.getId()) { setCurCpuFreq("900000"); tvCpu1.setText("" + getCurCpuFreq()); Toast.makeText(getApplicationContext(), "cpuFreq set :900000", Toast.LENGTH_SHORT) .show(); } else if (arg1 == freq4.getId()) { setCurCpuFreq("728000"); tvCpu1.setText("" + getCurCpuFreq()); Toast.makeText(getApplicationContext(), "cpuFreq set :728000", Toast.LENGTH_SHORT) .show(); } else if (arg1 == freq5.getId()) { setCurCpuFreq("416000"); tvCpu1.setText("" + getCurCpuFreq()); Toast.makeText(getApplicationContext(), "cpuFreq set :416000", Toast.LENGTH_SHORT) .show(); } } }); Log.d("012", "getCurCpuFreq: " + getCurCpuFreq() + " getCurCpuFreqManager:" + getCurCpuFreqManager()); } // 实时设置CPU当前频率(单位KHZ) public static void setCurCpuFreq(String s) { try { FileWriter fw = new FileWriter(c2); String sfreq = String.valueOf(s); Log.e("012", "Excute exception: 0000c2"); fw.write(sfreq); fw.flush(); fw.close(); } catch (IOException e) { e.printStackTrace(); Log.e("012", "ctrlCpuFreq(): error;"); } } // 实时获取CPU当前频率(单位KHZ) public static String getCurCpuFreq() { String result = "N/A"; try { FileReader fr = new FileReader( "/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed");// scaling_cur_freq BufferedReader br = new BufferedReader(fr); String text = br.readLine(); result = text.trim(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return result; } // 实时获取CPU管理策略 public static String getCurCpuFreqManager() { String result = "N/A"; try { FileReader fr = new FileReader( "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");// scaling_cur_freq BufferedReader br = new BufferedReader(fr); String text = br.readLine(); result = text.trim(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return result; } // 设置CPU管理策略 userspace performance ondemand interactive public static void setCurCpuFreqManager(String s1) { Log.e("012", "set setCurCpuFreqManager:" + s1); try { FileWriter fw = new FileWriter(c1); String sfreq = String.valueOf(s1); fw.write(sfreq); fw.flush(); fw.close(); } catch (IOException e) { e.printStackTrace(); Log.e("012", "set setCurCpuFreqManager error;"); // return; } } // 获取CPU名字 public static String getCpuName() { try { FileReader fr = new FileReader("/proc/cpuinfo"); BufferedReader br = new BufferedReader(fr); String text = br.readLine(); String[] array = text.split(":\\s+", 100); for (int i = 0; i < array.length; i++) { } return array[1]; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_main, menu); return true; } @Override protected void onDestroy() { super.onDestroy(); thd = false; Log.e("012", "start onDestroy~~~"); } }
AndroidManifest.xml 如下
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.cpufreq_for_intel" android:versionCode="1" android:sharedUserId="android.uid.system" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="23" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.example.cpufreq_for_intel.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
apk源码下载:链接:http://pan.baidu.com/s/1cqXsq6 密码:0hd9
相关文章推荐
- Linux动态频率调节系统CPUFreq之三:governor
- Linux动态频率调节系统CPUFreq之一:概述
- Linux动态频率调节系统CPUFreq之三:governor
- Linux动态频率调节系统CPUFreq之三:governor
- Linux内核架构:动态频率调节系统CPUFreq
- Linux动态频率调节系统CPUFreq之一:概述
- Linux动态频率调节系统CPUFreq之三:governor
- Linux动态频率调节系统CPUFreq之一:概述【转】-- 非常好的博客
- Linux动态频率调节系统CPUFreq
- Linux动态频率调节系统CPUFreq之一:概述
- Linux动态频率调节系统CPUFreq之二:核心(core)架构与API
- Linux动态频率调节系统CPUFreq之一:概述
- Linux动态频率调节系统CPUFreq之三:governor
- Linux动态频率调节系统CPUFreq之一:概述
- Linux动态频率调节系统CPUFreq之二:核心(core)架构与API
- Linux动态频率调节系统CPUFreq
- Linux动态频率调节系统CPUFreq之二:核心(core)架构与API
- Linux动态频率调节系统CPUFreq之二:核心(core)架构与API
- Linux动态频率调节系统CPUFreq之二:核心(core)架构与API
- Linux动态频率调节系统CPUFreq之一:概述