Android 改变RenderThread调度策略提高性能

一,通过设置绘画的RenderThread线程的调度策略来提高性能

默认情况下每个进程的绘画线程RenderThread的调度策略是SCHED_OTHER, 并且优先级为-10.

设置系统属性sys.use_fifo_ui为1后,则表示每个进程的绘画线程RenderThread的调度策略变更为SCHED_FIFO,并且实时优先级为1.

调度器

名称

解释

SCHED_OTHER

默认

标准round-robin分时共享策略

SCHED_BATCH

批处理调度

针对具有batch风格(批处理)进程的调度策略

SCHED_IDLE

空闲调度

针对优先级非常低的适合在后台运行的进程

SCHED_FIFO

先进先出

实时调度策略

SCHED_RR

循环调度

实时调度策略

 

 

二,DEBUG

PS 参数

#ps -eo class,cmd

Command line field types:

 

ARGS CMDLINE minus initial path CMD Thread name (/proc/TID/stat:2)

CMDLINE Command line (argv[]) COMM EXE filename (/proc/PID/exe)

COMMAND EXE path (/proc/PID/exe) NAME Process name (PID's argv[0])

 

Process attribute field types:

 

S Process state:

R (running) S (sleeping) D (device I/O) T (stopped) t (trace stop)

X (dead) Z (zombie) P (parked) I (idle)

Also between Linux 2.6.33 and 3.13:

x (dead) K (wakekill) W (waking)

 

SCH Scheduling policy (0=other, 1=fifo, 2=rr, 3=batch, 4=iso, 5=idle)

STAT Process state (S) plus:

< high priority N low priority L locked memory

s session leader + foreground l multithreaded

%CPU Percentage of CPU time used %MEM RSS as % of physical memory

%VSZ VSZ as % of physical memory ADDR Instruction pointer

BIT 32 or 64 C Total %CPU used since start

CPU Which processor running on DIO Disk I/O

DREAD Data read from disk DWRITE Data written to disk

ELAPSED Elapsed time since PID start F Flags 1=FORKNOEXEC 4=SUPERPRIV

GID Group ID GROUP Group name

IO Data I/O LABEL Security label

MAJFL Major page faults MINFL Minor page faults

NI Niceness (static 19 to -20) PCY Android scheduling policy

PGID Process Group ID PID Process ID

PPID Parent Process ID PR Prio Reversed (dyn 39-0, RT)

PRI Priority (dynamic 0 to 139) PSR Processor last executed on

READ Data read RES Short RSS

RGID Real (before sgid) Group ID RGROUP Real (before sgid) group name

RSS Resident Set Size (DRAM pages) RTPRIO Realtime priority

RUID Real (before suid) user ID RUSER Real (before suid) user name

SHR Shared memory STIME Start time (ISO 8601)

SWAP Swap I/O SZ 4k pages to swap out

TCNT Thread count TID Thread ID

TIME CPU time consumed TIME+ CPU time (high precision)

TTY Controlling terminal UID User id

USER User name VIRT Virtual memory size

VSZ Virtual memory size (1k units) WCHAN Wait location in kernel

WRITE Data written

 

https://cloud.tencent.com/developer/article/1370262

 

 

  • static_prio静态优先级: 不会时间而改变,内核也不会修改,只能通过系统调用改变nice值的方法区修改。优先级映射公式: static_prio = MAX_RT_PRIO + nice + 20,其中MAX_RT_PRIO = 100,那么取值区间为[100, 139];对应普通进程;
  • rt_priority实时优先级:只对实时进程有意义,取值区间为[0, MAX_RT_PRIO -1],其中MAX_RT_PRIO = 100,那么取值区间为[0, 99];对应实时进程;
  • prio动态优先级: 调度程序通过增加或减少进程静态优先级的值,来达到奖励IO消耗型或惩罚cpu消耗型的进程,调整后的进程称为动态优先级。区间范围[0, MX_PRIO-1],其中MX_PRIO = 140,那么取值区间为[0,139];
  • normal_prio普通优先级 表示基于进程的静态优先级static_prio和调度策略计算出的优先级. 因此即使普通进程和实时进程具有相同的静态优先级, 其普通优先级也是不同的, 进程分叉(fork)时, 子进程会继承父进程的普通优先级

 

 

1. 设置RenderThread线程的调度策略为SCHED_FIFO

#setprop sys.use_fifo_ui 1

# ps -AT -l | grep -E "26946|PID" | grep -E "RenderThread|PID"

F S UID PID TID PPID C PRI NI BIT SZ WCHAN TTY TIME CMD

1 S 10113 26946 26974 25202 0 41 0 32 335037 SyS_epoll_wait ? 00:00:00 RenderThread

# ps -AT -o TID,SCH,NI,PRI,PR,RTPRIO,CMD | grep -E "26974 |TID" | grep -E "RenderThread|TID"

TID SCH NI PRI PR RTPRIO CMD

26974 1 0 41 -2 1 RenderThread

# cat proc/26974/sched

policy : 1

prio : 98 (MAX_RT_PRIO - 1 - RTPRIO = 99 - 1 = 98 )

 

2. 设置RenderThread线程的调度策略为SCHED_OTHER

#setprop sys.use_fifo_ui 0

# ps -AT -l | grep -E "22599|PID" | grep -E "RenderThread|PID"

F S UID PID TID PPID C PRI NI BIT SZ WCHAN TTY TIME CMD

1 S 10113 22599 22626 20804 0 29 -10 32 335037 SyS_epoll_wait ? 00:00:00 RenderThread

# ps -AT -o TID,SCH,NI,PRI,PR,RTPRIO,CMD | grep -E "22626|TID" | grep -E "RenderThread|TID"

TID SCH NI PRI PR RTPRIO CMD

22626 0 -10 29 10 - RenderThread

# cat proc/22626/sched

policy : 0

prio : 110 (MAX_RT_PRIO + (20 + NI) = 100 + 10 = 110)

 

另外线程最终实际的优先级可以如此计算: 100 + PR

 

3. 重置线程优先级, 该版本renice只能设置nice值【-20, 19】

# ps -AT -o TID,SCH,NI,PRI,PR,RTPRIO,CMD | grep -E "8768|TID"

TID SCH NI PRI PR RTPRIO CMD

8768 0 -4 23 16 - RenderThread

# renice -n 10 8768 //把线程8768的原有nice值加上10

# ps -AT -o TID,SCH,NI,PRI,PR,RTPRIO,CMD | grep -E "8768|TID"

TID SCH NI PRI PR RTPRIO CMD

8768 0 6 13 26 - RenderThread

 

三,代码

1. @ActivityManagerService.java (frameworks\base\services\core\java\com\android\server\am)

// Whether we should use SCHED_FIFO for UI and RenderThreads.

boolean mUseFifoUiScheduling = false;

public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {

if (SystemProperties.getInt("sys.use_fifo_ui", 0) != 0 ||

SystemProperties.get("ro.vendor.mtk_perf_plus").equals("1")) {

mUseFifoUiScheduling = true;

}

...

}

 

public static boolean scheduleAsFifoPriority(int tid, boolean suppressLogs) {

try {

Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK, 1);

return true;

} catch (IllegalArgumentException e) {

if (!suppressLogs) {

Slog.w(TAG, "Failed to set scheduling policy, thread does not exist:\n" + e);

}

} catch (SecurityException e) {

if (!suppressLogs) {

Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);

}

}

return false;

}

 

@Override

public void setRenderThread(int tid) {

synchronized (this) {

ProcessRecord proc;

int pid = Binder.getCallingPid();

//如果是自身system_server进程,则一般是截屏或录屏后台操作,所以不需要高优先级

if (pid == Process.myPid()) {

demoteSystemServerRenderThread(tid);

return;

}

synchronized (mPidsSelfLocked) {

proc = mPidsSelfLocked.get(pid);

if (proc != null && proc.renderThreadTid == 0 && tid > 0) {

// ensure the tid belongs to the process

if (!isThreadInProcess(pid, tid)) {

throw new IllegalArgumentException(

"Render thread does not belong to process");

}

proc.renderThreadTid = tid;

if (DEBUG_OOM_ADJ) {

Slog.d("UI_FIFO", "Set RenderThread tid " + tid + " for pid " + pid);

}

// promote to FIFO now, 必须是最前台进程的RenderThread,才提升调度策略

if (proc.getCurrentSchedulingGroup() == ProcessList.SCHED_GROUP_TOP_APP) {

if (DEBUG_OOM_ADJ) Slog.d("UI_FIFO", "Promoting " + tid + "out of band");

if (mUseFifoUiScheduling) { //改变调度策略为实时FIFO,并且优先级为1

//SCHED_RESET_ON_FORK表示策略只作用于主动设置的进程,不会传递到子进程

setThreadScheduler(proc.renderThreadTid,

SCHED_FIFO | SCHED_RESET_ON_FORK, 1);

} else {//如果不改变默认的调度策略,则设置优先级为-10

setThreadPriority(proc.renderThreadTid, TOP_APP_PRIORITY_BOOST);

}

}

} else {

if (DEBUG_OOM_ADJ) {

Slog.d("UI_FIFO", "Didn't set thread from setRenderThread? " +

"PID: " + pid + ", TID: " + tid + " FIFO: " +

mUseFifoUiScheduling);

}

}

}

}

}

 

//如果是自身system_server进程,则一般是截屏或录屏后台操作,所以不需要高优先级

private void demoteSystemServerRenderThread(int tid) {

setThreadPriority(tid, Process.THREAD_PRIORITY_BACKGROUND);

}

 

2. @OomAdjuster.java (frameworks\base\services\core\java\com\android\server\am)

private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,

final int curSchedGroup = app.getCurrentSchedulingGroup();

if (app.setSchedGroup != curSchedGroup) {

int oldSchedGroup = app.setSchedGroup;

if (app.waitingToKill != null && app.curReceivers.isEmpty()

} else {

int processGroup;

switch (curSchedGroup) {

case ProcessList.SCHED_GROUP_BACKGROUND:

processGroup = THREAD_GROUP_BG_NONINTERACTIVE;

break;

case ProcessList.SCHED_GROUP_TOP_APP:

case ProcessList.SCHED_GROUP_TOP_APP_BOUND:

processGroup = THREAD_GROUP_TOP_APP;

break;

case ProcessList.SCHED_GROUP_RESTRICTED:

processGroup = THREAD_GROUP_RESTRICTED;

break;

default:

processGroup = THREAD_GROUP_DEFAULT;

break;

}

try {

//如果进程切换到最前面:mUseFifoUiScheduling=true则把该进程的UI线程和RenderThread线程都提升为FIFO调度策略,优先级为1; mUseFifoUiScheduling=false则该进程的UI线程和RenderThread线程的优先级提升为TOP_APP_PRIORITY_BOOST=-10

if (curSchedGroup == ProcessList.SCHED_GROUP_TOP_APP) {

// do nothing if we already switched to RT

if (oldSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {

if (mService.mUseFifoUiScheduling) {

// Switch UI pipeline for app to SCHED_FIFO

app.savedPriority = Process.getThreadPriority(app.pid);

mService.scheduleAsFifoPriority(app.pid, /* suppressLogs */true);

if (app.renderThreadTid != 0) {

mService.scheduleAsFifoPriority(app.renderThreadTid,

/* suppressLogs */true);

} else {

if (DEBUG_OOM_ADJ) {

Slog.d("UI_FIFO", "Not setting RenderThread TID");

}

}

} else {

// Boost priority for top app UI and render threads

setThreadPriority(app.pid, TOP_APP_PRIORITY_BOOST);

if (app.renderThreadTid != 0) {

try {

setThreadPriority(app.renderThreadTid,

TOP_APP_PRIORITY_BOOST);

} catch (IllegalArgumentException e) {

// thread died, ignore

}

}

}

}

} else if (oldSchedGroup == ProcessList.SCHED_GROUP_TOP_APP &&

curSchedGroup != ProcessList.SCHED_GROUP_TOP_APP) {

//如果进程切换到后台

if (mService.mUseFifoUiScheduling) {

try {

// 还原UI线程调度为SCHED_OTHER, 优先级为原来默认值0; 还原RenderThread线程调度为SCHED_OTHER,优先级为-4(为啥选择-4?)

setThreadScheduler(app.pid, SCHED_OTHER, 0);

setThreadPriority(app.pid, app.savedPriority);

if (app.renderThreadTid != 0) {

setThreadScheduler(app.renderThreadTid,

SCHED_OTHER, 0);

setThreadPriority(app.renderThreadTid, -4);

}

} catch (IllegalArgumentException e) {

Slog.w(TAG,

"Failed to set scheduling policy, thread does not exist:\n"

+ e);

} catch (SecurityException e) {

Slog.w(TAG, "Failed to set scheduling policy, not allowed:\n" + e);

}

} else {

// Reset priority for top app UI and render threads

setThreadPriority(app.pid, 0);

if (app.renderThreadTid != 0) {

setThreadPriority(app.renderThreadTid, 0);

}

}

}

}

 

 

3. @ThreadedRenderer.java (frameworks\base\core\java\android\view)

public final class ThreadedRenderer extends HardwareRenderer {

}

 

4. @HardwareRenderer.java (frameworks\base\graphics\java\android\graphics)

synchronized void init(long renderProxy) {

if (mInitialized) return;

mInitialized = true;

 

initSched(renderProxy);

initGraphicsStats();

}

 

private void initSched(long renderProxy) {

try {

int tid = nGetRenderThreadTid(renderProxy); //得到RenderThread线程TID

ActivityManager.getService().setRenderThread(tid); //设置该线程调度策略和优先级

} catch (Throwable t) {

Log.w(LOG_TAG, "Failed to set scheduler for RenderThread", t);

}

}

 

四,如何设置

@device/mediatek/vendor/common/device.mk

1. 添加sys.use_fifo_ui=1定义

PRODUCT_PROPERTY_OVERRIDES += sys.use_fifo_ui=1

 

# For performance tuning ifeq ($(strip $(MTK_PERF_PLUS)),yes) PRODUCT_PROPERTY_OVERRIDES += ro.vendor.mtk_perf_plus=1 endif

 

2. 定义MTK_PERF_PLUS

@device/fih/BT1/ProjectConfig.mk

MTK_PERF_PLUS = no ---> MTK_PERF_PLUS = yes

 

五,思考

1. 设置线程的调度策略为FIFO时,是否优先级过低(设为1)?当调度策略为FIFO时,设置的实时优先级数越小则表示优先级真是小。实时优先级的范围[0,99]

setThreadScheduler(proc.renderThreadTid, SCHED_FIFO | SCHED_RESET_ON_FORK, 1);

比如把实时优先级提高到15或50?

 

2. 同理当调度策略为OTHER时,是否线程优先级过低(-10)。TOP_APP_PRIORITY_BOOST = -10, setThreadPriority(proc.renderThreadTid, TOP_APP_PRIORITY_BOOST);

比如把线程优先级提高到-20或-19?

 

3. 当APP不在最前面(Top APP)时,UI线程和RenderThread线程都要降低优先级到0或-4, 能不能降到更低呢?比如10

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值