- 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实现定频功能
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: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或者user版本并且有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.thermal 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 :=
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