您的位置:首页 > 其它

在MTK芯片上如何控制CPU的核数和频率-MTK PerfService

2016-04-11 17:58 337 查看

在MTK芯片上如何控制CPU的核数和频率-MTK PerfService

一句话:PerfService就是用来调整CPU/GPU资源的。对于老的API,可以更简单地讲就是调CPU核数和CPU频率的。

PerfService简介

kernel中实现了两个driver,一个负责控制开关CPU的核数,叫做hot-plug驱动,另一个负责调整CPU的频率,叫做DVFS驱动。

kernel中的driver会根据系统的负载情况下,自动调整使用几个CPU和调整CPU频率。如果负载高了,提高频率,或者多开几个核,或者开大核。如果负载降下去了,就可以关大核,关核,降频。

虽然现在的自动调频和调核的策略已经定义了很多,也在不断地完善,但是有两个问题:一是总有覆盖不到的情况,或者干脆就是互相矛盾的需求导致策略冲突。二是自动调度都是后知后觉的,只有发现负载上来了或者降下去了,才来做负载调节,需要一定的时间。这样,要么是效率不够,要么是功耗无谓地消耗掉。

PerfService就是一个在用户空间来主动调节系统能力的服务。

C/C++调用PerfService

步骤

动态加载libperfservicenative.so

注册用户场景PerfServiceNative_userReg/PerfServiceNative_userRegBigLittle/PerfServiceNative_userRegScn

激活用户场景PerfServiceNative_userEnable

执行用户场景

反激活用户场景PerfServiceNative_userDisable

退出进程之前反注册PerfServiceNative_userUnreg/PerfServiceNative_userUnregScn

老API的步骤

老API只能对CPU做调度,但是好处是可以直接指定开几个核,频率调到多少,还可以控制开大核还是小核。

PerfServiceNative_userReg可以指定几个核和多高的频率

PerfServiceNative_userRegBigLittle还可以用来指定调度大小核

PerfServiceNative_userEnable用来激活上面注册的场景,PerfServiceNative_userEnableTimeout可以指定激活的超时时间

PerfServiceNative_userDisable用来反激活

PerfServiceNative_userUnreg反注册

新API的步骤

新的API也可以调节GPU,但是采用的方式要复杂一些,就不再像老API一样直接指定核和频率了,需要定义配置

PerfServiceNative_userRegScn:没有参数,直接注册就好

PerfServiceNative_userRegScnConfig:用这个函数去真正指定配置

PerfServiceNative_userEnable/PerfServiceNative_userEnableTimeout:跟老API没有区别

PerfServiceNative_userDisable:还是老的API

PerfServiceNative_userUnregScn:反注册

老API开发指南

指定核和频率PerfServiceNative_userReg

定义一个需要scn_core个核,scn_freq频率运行的任务

原型:

int  PerfServiceNative_userReg(int scn_core, int scn_freq);


定义于:/mediatek/proprietary/hardware/perfservice/perfservicenative/PerfServiceNative.h

参数:

* scn_core:开多少个核

* scn_freq:频率调整到多少。如果只是希望多开几个核或者少开几个核,并不关注频率的话,可以置成0.

返回值:

* -1:失败

* other:handler,用于后续的操作

注册指定大核小核PerfServiceNative_userRegBigLittle

定义一个需要scn_core个核,scn_freq频率运行的任务

原型:

int  PerfServiceNative_userRegBigLittle(int scn_core_big, int scn_freq_big,int scn_core_little, int scn_freq_little);


定义于:/mediatek/proprietary/hardware/perfservice/perfservicenative/PerfServiceNative.h

参数:

* scn_core_big:开多少个核

* scn_freq_big:频率调整到多少

* scn_core_little:开多少个核

* scn_freq_little:频率调整到多少

返回值:

* -1:失败

* other:handler

反注册

在退出进程之前需要进行反注册

原型:

void PerfServiceNative_userUnreg(int handle);


激活和反激活

注册了之后也不是一直用啊,用的时候再打开吧,使用PerfServiceNative_userEnable。如果一旦忧心有可能出exception之类的流程不能保证走到PerfServiceNative_userDisable的话,也可以加个超时,调用PerfServiceNative_userEnableTimeout.

原型:

void PerfServiceNative_userEnable(int handle);
void PerfServiceNative_userDisable(int handle);
void PerfServiceNative_userEnableTimeout(int handle, int timeout);
void PerfServiceNative_userEnableTimeoutMs(int handle, int timeout);


参数:

* handle: 注册成功后返回的那个

* timeout: PerfServiceNative_userEnableTimeout是以秒为单位的超时时间,PerfServiceNative_userEnableTimeoutMs则以毫秒为单位。

新API开发指南

获取系统能力

int  PerfServiceNative_userGetCapability(int cmd);


参数:

* cmd: 请参见下面的枚举值:

enum {
CMD_GET_CPU_FREQ_LEVEL_COUNT        = 0,
CMD_GET_CPU_FREQ_LITTLE_LEVEL_COUNT = 1,
CMD_GET_CPU_FREQ_BIG_LEVEL_COUNT    = 2,
CMD_GET_GPU_FREQ_LEVEL_COUNT        = 3,
CMD_GET_MEM_FREQ_LEVEL_COUNT        = 4,
};


CMD_GET_CPU_FREQ_LEVEL_COUNT:获取CPU频率级别

CMD_GET_CPU_FREQ_LITTLE_LEVEL_COUNT:获取小核CPU频率级别

CMD_GET_CPU_FREQ_BIG_LEVEL_COUNT:获取大核CPU频率级别

CMD_GET_GPU_FREQ_LEVEL_COUNT:获取GPU频率级别

CMD_GET_MEM_FREQ_LEVEL_COUNT:获取内存频率级别

注册

因为新的API还需要指定配置,所以注册获取handle就不需要参数了。

原型:

int  PerfServiceNative_userRegScn();


反注册

反注册PerfServiceNative_userRegScn注册的handle。注意,跟PerfServiceNative_userUnreg不一样啊。

void PerfServiceNative_userUnregScn(int handle);


配置

原型:

void PerfServiceNative_userRegScnConfig(int handle, int cmd, int param_1, int param_2, int param_3, int param_4);


参数:

* handle:PerfServiceNative_userRegScn注册的handle。

* cmd:命令

* param_1, param_2, param_3, param_4:根据命令不同的参数

命令请参见下面的枚举:

enum {
CMD_SET_CPU_CORE_MIN            = 0,
CMD_SET_CPU_CORE_MAX            = 1,
CMD_SET_CPU_CORE_BIG_LITTLE_MIN = 2,
CMD_SET_CPU_CORE_BIG_LITTLE_MAX = 3,
CMD_SET_CPU_FREQ_MIN            = 4,
CMD_SET_CPU_FREQ_MAX            = 5,
CMD_SET_CPU_FREQ_BIG_LITTLE_MIN = 6,
CMD_SET_CPU_FREQ_BIG_LITTLE_MAX = 7,
CMD_SET_GPU_FREQ_MIN            = 8,
CMD_SET_GPU_FREQ_MAX            = 9,
CMD_SET_MEM_FREQ_MIN            = 10,
CMD_SET_MEM_FREQ_MAX            = 11,
CMD_SET_VCORE                   = 12,
CMD_SET_SCREEN_OFF_STATE        = 13,
CMD_SET_CPUFREQ_HISPEED_FREQ    = 14,
CMD_SET_CPUFREQ_MIN_SAMPLE_TIME = 15,
CMD_SET_CPUFREQ_ABOVE_HISPEED_DELAY = 16,
};


CMD_SET_CPU_CORE_MIN:设置最少核数.参数1个 - param_1:核数

CMD_SET_CPU_CORE_MAX:设置最大核数.参数1个 - param_1:核数

CMD_SET_CPU_CORE_BIG_LITTLE_MIN:设置最少大小核数.参数2个 - param_1:大核数,param_2:小核数

CMD_SET_CPU_CORE_BIG_LITTLE_MAX:设置最大大小核数.参数2个 - param_1:大核数,param_2:小核数

CMD_SET_CPU_FREQ_MIN:设置最低频率.参数1个 - param_1:频率

CMD_SET_CPU_FREQ_MAX:设置最高频率.参数1个 - param_1:频率

CMD_SET_CPU_FREQ_BIG_LITTLE_MIN:设置最低大小核数.参数2个 - param_1:大核频率,param_2:小核频率

CMD_SET_CPU_FREQ_BIG_LITTLE_MAX:设置最高大小核数.参数2个 - param_1:大核频率,param_2:小核频率

CMD_SET_GPU_FREQ_MIN:设置GPU最低频率级别,参数1个 - param_1:频率级别

CMD_SET_GPU_FREQ_MAX:不支持

CMD_SET_MEM_FREQ_MIN:不支持

CMD_SET_MEM_FREQ_MAX:不支持

CMD_SET_VCORE:设置图形模式,参数1个:DRAM模式:0-默认模式,1-低功耗模式,2-还是默认模式,3-高性能模式

CMD_SET_SCREEN_OFF_STATE:设置关屏模式,一个参数,模式值。0-关屏无效,1-关屏有效,2-关屏暂停,打开恢复

CMD_SET_CPUFREQ_HISPEED_FREQ:设置高速频率,一个参数。

CMD_SET_CPUFREQ_MIN_SAMPLE_TIME:设置最小采样值,一个参数。

CMD_SET_CPUFREQ_ABOVE_HISPEED_DELAY:设置above speed hispeed,一个参数。

开关屏的参数,请使用下面的枚举值:

enum {
SCREEN_OFF_DISABLE      = 0,
SCREEN_OFF_ENABLE       = 1,
SCREEN_OFF_WAIT_RESTORE = 2,
};


Java调用PerfService

步骤

import IPerfServiceWrapper和PerfServiceWrapper

注册用户场景IPerfServiceWrapper.userReg

激活用户场景IPerfServiceWrapper.userEnable

执行用户场景

反激活用户场景IPerfServiceWrapper.userDisable

反注册用户场景IPerfServiceWrapper.userUnreg

IPerfServiceWrapper定义于

/frameworks/base/core/java/com/mediatek/perfservice/IPerfServiceWrapper.java

老API的步骤

老API只能对CPU做调度,但是好处是可以直接指定开几个核,频率调到多少,还可以控制开大核还是小核。

IPerfServiceWrapper.userReg可以指定几个核和多高的频率

IPerfServiceWrapper.userRegBigLittle还可以用来指定调度大小核

IPerfServiceWrapper.userEnable用来激活上面注册的场景,IPerfServiceWrapper.userEnableTimeout可以指定激活的超时时间

IPerfServiceWrapper.userDisable用来反激活

IPerfServiceWrapper.userUnreg反注册

新API的步骤

新的API也可以调节GPU,但是采用的方式要复杂一些,就不再像老API一样直接指定核和频率了,需要定义配置

IPerfServiceWrapper.userRegScn:没有参数,直接注册就好

IPerfServiceWrapper.userRegScnConfig:用这个函数去真正指定配置

IPerfServiceWrapper.userEnable/IPerfServiceWrapper.userEnableTimeout:跟老API没有区别

IPerfServiceWrapper.userDisable:还是老的API

IPerfServiceWrapper.userUnregScn:反注册

老API开发指南

指定核和频率PerfServiceNative_userReg

定义一个需要scn_core个核,scn_freq频率运行的任务

原型:

public int  userReg(int scn_core, int scn_freq);


参数:

* scn_core:开多少个核

* scn_freq:频率调整到多少。如果只是希望多开几个核或者少开几个核,并不关注频率的话,可以置成0.

返回值:

* -1:失败

* other:handler,用于后续的操作

注册指定大核小核PerfServiceNative_userRegBigLittle

定义一个需要scn_core个核,scn_freq频率运行的任务

原型:

public int  userRegBigLittle(int scn_core_big, int scn_freq_big, int scn_core_little, int scn_freq_little);


参数:

* scn_core_big:开多少个核

* scn_freq_big:频率调整到多少

* scn_core_little:开多少个核

* scn_freq_little:频率调整到多少

返回值:

* -1:失败

* other:handler

反注册

在退出进程之前需要进行反注册

原型:

public void userUnreg(int handle);


激活和反激活

注册了之后也不是一直用啊,用的时候再打开吧,使用PerfServiceNative_userEnable。如果一旦忧心有可能出exception之类的流程不能保证走到PerfServiceNative_userDisable的话,也可以加个超时,调用PerfServiceNative_userEnableTimeout.

原型:

public void userEnable(int handle);
public void userEnableTimeout(int handle, int timeout);
public void userEnableTimeoutMs(int handle, int timeout_ms);
public void userDisable(int handle);


参数:

* handle: 注册成功后返回的那个

* timeout: PerfServiceNative_userEnableTimeout是以秒为单位的超时时间,PerfServiceNative_userEnableTimeoutMs则以毫秒为单位。

新API开发指南

获取系统能力

public int  userGetCapability(int cmd);


参数:

* cmd: 请参见下面的常量值:

public static final int CMD_GET_CPU_FREQ_LEVEL_COUNT        = 0;
public static final int CMD_GET_CPU_FREQ_LITTLE_LEVEL_COUNT = 1;
public static final int CMD_GET_CPU_FREQ_BIG_LEVEL_COUNT    = 2;
public static final int CMD_GET_GPU_FREQ_LEVEL_COUNT        = 3;
public static final int CMD_GET_MEM_FREQ_LEVEL_COUNT        = 4;


CMD_GET_CPU_FREQ_LEVEL_COUNT:获取CPU频率级别

CMD_GET_CPU_FREQ_LITTLE_LEVEL_COUNT:获取小核CPU频率级别

CMD_GET_CPU_FREQ_BIG_LEVEL_COUNT:获取大核CPU频率级别

CMD_GET_GPU_FREQ_LEVEL_COUNT:获取GPU频率级别

CMD_GET_MEM_FREQ_LEVEL_COUNT:获取内存频率级别

注册

因为新的API还需要指定配置,所以注册获取handle就不需要参数了。

原型:

public int  userRegScn();


反注册

反注册PerfServiceNative_userRegScn注册的handle。注意,跟PerfServiceNative_userUnreg不一样啊。

原型:

public void userUnregScn(int handle);


配置

原型:

public void userRegScnConfig(int handle, int cmd, int param_1, int param_2, int param_3, int param_4);


参数:

* handle:PerfServiceNative_userRegScn注册的handle。

* cmd:命令

* param_1, param_2, param_3, param_4:根据命令不同的参数

命令请参见下面的常量:

public static final int CMD_SET_CPU_CORE_MIN            = 0;
public static final int CMD_SET_CPU_CORE_MAX            = 1;
public static final int CMD_SET_CPU_CORE_BIG_LITTLE_MIN = 2;
public static final int CMD_SET_CPU_CORE_BIG_LITTLE_MAX = 3;
public static final int CMD_SET_CPU_FREQ_MIN            = 4;
public static final int CMD_SET_CPU_FREQ_MAX            = 5;
public static final int CMD_SET_CPU_FREQ_BIG_LITTLE_MIN = 6;
public static final int CMD_SET_CPU_FREQ_BIG_LITTLE_MAX = 7;
public static final int CMD_SET_GPU_FREQ_MIN            = 8;
public static final int CMD_SET_GPU_FREQ_MAX            = 9;
public static final int CMD_SET_MEM_FREQ_MIN            = 10;
public static final int CMD_SET_MEM_FREQ_MAX            = 11;
public static final int CMD_SET_SCREEN_OFF_STATE        = 12;
public static final int CMD_SET_CPUFREQ_HISPEED_FREQ    = 13;
public static final int CMD_SET_CPUFREQ_MIN_SAMPLE_TIME = 14;
public static final int CMD_SET_CPUFREQ_ABOVE_HISPEED_DELAY = 15;
public static final int CMD_SET_VCORE                       = 16;


CMD_SET_CPU_CORE_MIN:设置最少核数.参数1个 - param_1:核数

CMD_SET_CPU_CORE_MAX:设置最大核数.参数1个 - param_1:核数

CMD_SET_CPU_CORE_BIG_LITTLE_MIN:设置最少大小核数.参数2个 - param_1:大核数,param_2:小核数

CMD_SET_CPU_CORE_BIG_LITTLE_MAX:设置最大大小核数.参数2个 - param_1:大核数,param_2:小核数

CMD_SET_CPU_FREQ_MIN:设置最低频率.参数1个 - param_1:频率

CMD_SET_CPU_FREQ_MAX:设置最高频率.参数1个 - param_1:频率

CMD_SET_CPU_FREQ_BIG_LITTLE_MIN:设置最低大小核数.参数2个 - param_1:大核频率,param_2:小核频率

CMD_SET_CPU_FREQ_BIG_LITTLE_MAX:设置最高大小核数.参数2个 - param_1:大核频率,param_2:小核频率

CMD_SET_GPU_FREQ_MIN:设置GPU最低频率级别,参数1个 - param_1:频率级别

CMD_SET_GPU_FREQ_MAX:不支持

CMD_SET_MEM_FREQ_MIN:不支持

CMD_SET_MEM_FREQ_MAX:不支持

CMD_SET_VCORE:设置图形模式,参数1个:DRAM模式:0-默认模式,1-低功耗模式,2-还是默认模式,3-高性能模式

CMD_SET_SCREEN_OFF_STATE:设置关屏模式,一个参数,模式值。0-关屏无效,1-关屏有效,2-关屏暂停,打开恢复

CMD_SET_CPUFREQ_HISPEED_FREQ:设置高速频率,一个参数。

CMD_SET_CPUFREQ_MIN_SAMPLE_TIME:设置最小采样值,一个参数。

CMD_SET_CPUFREQ_ABOVE_HISPEED_DELAY:设置above speed hispeed,一个参数。

Java调用例

WebView中的应用例

例:

public void loadData(String data, String mimeType, String encoding) {
checkThread();
if (TRACE) Log.d(LOGTAG, "loadData");
/// M:PerfBoost include @{
if (sFirstLoadData) {
int maxFreq = 0;
try {
String freqFile = "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq";
RandomAccessFile reader = new RandomAccessFile(freqFile, "r");
String stringMaxFreq = reader.readLine();
reader.close();
maxFreq = Integer.parseInt(stringMaxFreq);
} catch (IOException | NumberFormatException e) {
e.printStackTrace();
}
if (maxFreq != 0) {
sPerfService = new PerfServiceWrapper(null);
if (sPerfService != null) {
int minCPU = 2;
if (maxFreq < 1100000)
minCPU = 4;
sPerfHandle = sPerfService.userReg(minCPU, maxFreq);
if (sPerfHandle != -1) {
sPerfService.userEnableTimeoutMs(sPerfHandle, 500);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
sPerfService.userUnreg(sPerfHandle);
}
}, 600);
}
}
}
sFirstLoadData = false;
}
/// @}

mProvider.loadData(data, mimeType, encoding);
}


AmS和WmS中的应用例

下面是/frameworks/base/services/core/java/com/android/server/am/ActivityStack.java中定义的perfBoost的两个方法,一个是perfBoostResume,另一个是perfBoostPause.

这个就是下节我们要介绍的SCN_APP_SWITCH场景。

private void perfBoostResume() {
if (mPerfService == null) {
mPerfService = new PerfServiceWrapper(null);
}

if (mPerfService != null) {
Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "amPerfBoost", 0);
if (DEBUG_PERFSRV) {
Slog.d(TAG, "boostEnableTimeoutMs(" +
IPerfServiceWrapper.SCN_APP_SWITCH + ") cross app");
}
mPerfService.boostEnableTimeoutMs(IPerfServiceWrapper.SCN_APP_SWITCH,
BOOST_ENABLE_TIMEOUT);
} else {
Slog.e(TAG, "PerfService is not ready!");
}
}

public void perfBoostPause() {
if (mPerfService == null) {
mPerfService = new PerfServiceWrapper(null);
}

if (mPerfService != null) {
if (DEBUG_PERFSRV) {
Slog.d(TAG, "boostDisable(" +
IPerfServiceWrapper.SCN_APP_SWITCH + ") cross app");
}
mPerfService.boostDisable(IPerfServiceWrapper.SCN_APP_SWITCH);
Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "amPerfBoost", 0);
} else {
Slog.e(TAG, "perfBoostPause, PerfService is not ready!");
}
}


我们再看一个

if (!mIsPerfBoostEnable) {
if (mPerfService == null) {
mPerfService = new PerfServiceWrapper(null);
}
mPerfService.boostEnable(IPerfServiceWrapper.SCN_APP_ROTATE);
mIsPerfBoostEnable = true;
}


MTK预定义的一些场景

MediaTek预定义了这么多API,当然它自己也会有自己的预定义场景,这些场景就不需要再定义了。

libperfservice.so中预定义的场景

场景cpu核数cpu频率UI操作
SCN_APP_SWITCH2-app启动、退出
SCN_APP_ROTATE2-app rotate
SCN_APP_TOUCH2169000touch
但是,这个值肯定不是在所有平台上都是最优的值啊,所以MTK也提供了客户定制化的机制。

定制预定义场景

定义于/vendor/mediatek/proprietary/hardware/perfservice/mt[xxxx]/scn_tbl/perfservscntbl.txt中。

我们以MT6735为例,来看一看具体的内容,定义于/vendor/mediatek/proprietary/hardware/perfservice/mt6735/scn_tbl/perfservscntbl.txt中。

CMD_SET_CPU_CORE, SCN_APP_TOUCH, 3
CMD_SET_CPU_FREQ, SCN_APP_TOUCH, 819000
CMD_SET_CPU_CORE, SCN_SW_FRAME_UPDATE, 3
CMD_SET_CPU_FREQ, SCN_SW_FRAME_UPDATE, 819000
CMD_SET_CPU_CORE, SCN_APP_SWITCH, 4
CMD_SET_CPU_FREQ, SCN_APP_SWITCH, 1300000
CMD_SET_CPU_UP_THRESHOLD, SCN_SW_FRAME_UPDATE, 80
CMD_SET_CPU_DOWN_THRESHOLD, SCN_SW_FRAME_UPDATE, 65
CMD_SET_CPU_CORE, SCN_APP_LAUNCH, 4
CMD_SET_CPU_FREQ, SCN_APP_LAUNCH, 1300000


白名单

定义于:/vendor/mediatek/proprietary/hardware/perfservice/mt[xxxx]/app_list/perfservapplist.txt

格式:包名 核数

例:

com.imangi.templerun2 3
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: