appfabric-geartrax

systemidle
2023年3月30日发(作者:单机cs1 6中文版下载)

AndroidCPU使⽤率

本⽂包含以下内容:

1.介绍常见的获取androidcpu使⽤率的⽅法

2.介绍这些常见⽅法背后的原理

3.介绍我⾃⼰写的⼀个脚本,这个脚本可以获取各个线程在cpu各个核上的占⽤率

⼀、常见的获取AndroidCPU使⽤率⽅法及其原理

⾸先说⼀下如何查看cpu的基本信息,相信很多⼈也知道,使⽤下⾯的命令即可

⽐如我从⼿边⼀台电视上获取到的信息如下,可以看到是个4核CPU,还能看到对应的CPUarchitecture

后⾯会发现,很多CPU使⽤率都是从/proc下获取到了,⽽/proc⼜是啥呢?可以直接参考

Theprocfilesystemisammonlymountedat/

ofitisread-only,butsomefilesallowkernelvariablestobechanged.

以上其实算是Linux基础知识,在这⾥做备忘⽤

1.1/proc/stat

adbshellcat/proc/cpuinfo

processor:0

BogoMIPS:24.00

Features:fpasimdevtstrmaespmullsha1sha2crc32

CPUimplementer:0x41

CPUarchitecture:AArch64

CPUvariant:0x0

CPUpart:0xd03

CPUrevision:4

Hardware:Maserati

processor:1

BogoMIPS:24.00

Features:fpasimdevtstrmaespmullsha1sha2crc32

CPUimplementer:0x41

CPUarchitecture:AArch64

CPUvariant:0x0

CPUpart:0xd08

CPUrevision:2

Hardware:Maserati

processor:2

BogoMIPS:24.00

Features:fpasimdevtstrmaespmullsha1sha2crc32

CPUimplementer:0x41

CPUarchitecture:AArch64

CPUvariant:0x0

CPUpart:0xd08

CPUrevision:2

Hardware:Maserati

processor:3

BogoMIPS:24.00

Features:fpasimdevtstrmaespmullsha1sha2crc32

CPUimplementer:0x41

CPUarchitecture:AArch64

CPUvariant:0x0

CPUpart:0xd03

CPUrevision:4

Hardware:Maserati

1.1/proc/stat

还是⼀样,在我的电视上通过上⾯的命令可以看到如下内容,需要说明的是,下⾯带#符号的是我加的注释,实际的打印没有这些内容。

因为我们关注的是CPU使⽤率,所以实际上只需要关注前五⾏的数据。其他⼏⾏数据的含义可以查看Linuxman-pages了解其含义。

前五⾏分别打印了总体CPU数据和各个核的数据。每列数据的含义同样可以参考Linuxman-pages,如下:需要注意的是,以下时间都是

从系统启动到当前时间内的累计时间

user(1)Timespentinusermode.⽤户态时间

nice(2)Timespentinusermodewithlowpriority(nice).

system(3)Timespentinsystemmode.系统态时间

idle(4)Timespentintheidletask.除IO等待之外的其他等待时间

iowait(sinceLinux2.5.41)(5)TimewaitingforI/lueisnotreliable,forthefollowingreasons:wil

lnotwaitforI/Otocomplete;iowaitisthetimethatataskiswaitingforI/PUgoesintoidlestateforoutsta

ndingtaskI/O,ti-coreCPU,thetaskwaitingforI/Otocompleteisnotrunn

ingonanyCPU,

等待时间

irq(sinceLinux2.6.0-test4)(6)Timeservicinginterrupts.硬中断时间

softirq(sinceLinux2.6.0-test4)(7)Timeservicingsoftirqs.软中断时间

steal(sinceLinux2.6.11)(8)Stolentime,whichisthetimespentinotheroperatingsystemswhenrunninginavirtualizedenviron

ment

guest(sinceLinux2.6.24)(9)TimespentrunningavirtualCPUforguestoperatingsystemsunderthecontroloftheLinuxkernel.

guest_nice(sinceLinux2.6.33)(10)Timespentrunninganicedguest(virtualCPUforguestoperatingsystemsunderthecontrol

oftheLinuxkernel).

⼀般取前七个变量(user,nice,system,idle,iowait,irq,softirq)之和即为总的cpu时间,因为这是⼀个累计时间,所以我们只需要

在两个时间点分别读⼀下cpu快照,设为total_time_old和total_time_new,则两个值相减即为这段时间内的总CPU时间total_time

_delta,然后想办法读⼀个进程或线程在相同时间段内的cpu时间proc_time_delta,则该进程或线程的cpu使⽤率即为100%*proc_ti

me_delta/total_time_delta

那么要如何读⼀个进程或线程的cpu数据呢?请看下⽂

1.2/proc/[pid]/stat和/proc/[pid]/task/[tid]/stat

⾄于如何获取pid和tid,则可以⽤ps命令,⽐如在我⼿边的电视上⽤ps命令先查看⼀个进程的pid,这⾥以ijkplayerdemo为例,如下

adbshellcat/proc/stat

#usernicesystemidleiowaitirqsoftirqstealguestguest_nice

cpu922533559321156447788

cpu2226000

cpu0000

cpu2228956226638249963703323000

cpu3239224

intr22680000

000

59779252700000000

514900000

0000

0

ctxt3894466714

btime1504771975

processes324478

procs_running1

procs_blocked0

softirq5932233356326524

adbshellcat/proc/[pid]/stat

adbshellcat/proc/[pid]/task/[tid]/stat

u0_a69546429648SyS_epoll_e

然后⽤下⾯的命令看看这个进程都有那些线程

结果如下

分别看看进程和随便⼀个线程的cpu数据如下

⼀⼝⽓打印了50多个数据,不⽤怕,接着查看Linuxman-page,可以知道各个数据项的含义如下,先说明⼀下/proc/[pid]/stat的含义,如

下,可以看到就是进程的信息

usedbyps(1).Itisdefinedinthekernelsourcefilefs/proc/array.c.

⽽/proc/[pid]/task的含义,如下

ThisieofeachsubdirectoryisthenumericalthreadI

D([tid])ofthethread(seegettid(2)).Withineachofthesesubdirectories,thereisasetoffileswiththesamenamesandcontentsasund

erthe/proc/[pid]directories.

是线程的信息,⽽且该⽬录下的⼦⽬录结构和/proc/[pid]/stat下的⼀致

下⾯来看看这50多项是什么含义,为了阅读⽅便,我把上⾯的获取到的数据也写到各项含义后⾯

(1)pid%dTheprocessID.18446

(2)comm%s线程名或进程名(e)

(3)state%cOneofthefollowingcharacters,indicatingprocessstate运⾏状态,常见值有如下:(这个例⼦中是S)

RRunning

SSleepinginaninterruptiblewait

DWaitinginuninterruptibledisksleep

ZZombie

(4)ppid%d⽗进程IDThePIDoftheparentofthisprocess.1758

(5)pgrp%dTheprocessgroupIDoftheprocess.1757

(6)session%dThesessionIDoftheprocess.0

(7)tty_nr%dThecontrollingterminaloftheprocess.0

(8)tpgid%dTheIDoftheforegroundprocessgroupofthecontrollingterminaloftheprocess.-1

(9)flags%meanings,seethePF_*definesintheLinuxkernelsourcefileinclude/linux/sche

sdependonthekernelversion.1077936448

(10)minflt%luThenumberofminorfaultstheprocesshasmadewhichhavenotrequiredloadingamemorypagefromdisk.20639

adbshellps-t18446

USERPIDPPIDVSIZERSSWCHANPCNAME

u0_a69546429648SyS_epoll_e

u0_a691546429648do_sigtimeSSignalCatcher

u0_a691546429648poll_schedSJDWP

u0_a691546429648futex_waitSReferenceQueueD

u0_a691546429648futex_waitSFinalizerDaemon

u0_a691546429648futex_waitSFinalizerWatchd

u0_a691546429648futex_waitSHeapTaskDaemon

u0_a691546429648binder_thrSBinder_1

u0_a691546429648binder_thrSBinder_2

u0_a691546429648futex_waitSModernAsyncTask

u0_a691546429648SyS_epoll_SRenderThread

u0_a69185429648futex_waitSmali-mem-purge

u0_a69185429648futex_waitSmali-utility-wo

u0_a69185429648futex_waitSmali-utility-wo

u0_a69185429648futex_waitSmali-utility-wo

u0_a69185429648futex_waitSmali-utility-wo

u0_a69185429648poll_schedSmali-cmar-backe

u0_a69185429648futex_waitSmali-hist-dump

u0_a691546429648futex_waitSModernAsyncTask

u0_a69256429648binder_thrSBinder_3

u0_a69256429648futex_waitSModernAsyncTask

18446(e)S1758175700-741

000000

18495(RenderThread)S1758175700-114-428446744113618

44674400-130

(10)minflt%luThenumberofminorfaultstheprocesshasmadewhichhavenotrequiredloadingamemorypagefromdisk.20639

(11)cminflt%luThenumberofminorfaultsthattheprocess’swaited-forchildrenhavemade.0

(12)majflt%luThenumberofmajorfaultstheprocesshasmadewhichhaverequiredloadingamemorypagefromdisk.1

(13)cmajflt%luThenumberofmajorfaultsthattheprocess’swaited-forchildrenhavemade.0

(14)utime%lu⽤户态时间Amountoftimethatthisprocesshasbeenscheduledinusermode,measuredinclockticks(dividebysysconf(

_SC_CLK_TCK)).Thisincludesguesttime,guest_time(timespentrunningavirtualCPU,seebelow),sothatapplicationsthatarenotaw

areoftheguesttimefielddonotlosethattimefromtheircalculations.70

(15)stime%lu系统态时间Amountoftimethatthisprocesshasbeenscheduledinkernelmode,measuredinclockticks(dividebysysco

nf(_SC_CLK_TCK)).18

(16)cutime%ldAmountoftimethatthisprocess’swaited-forchildrenhavebeenscheduledinusermode,measuredinclockticks(divide

bysysconf(_SC_CLK_TCK)).(Seealsotimes(2).)Thisincludesguesttime,cguest_time(timespentrunningavirtualCPU,seebelow).0

(17)cstime%ldAmountoftimethatthisprocess’swaited-forchildrenhavebeenscheduledinkernelmode,measuredinclockticks(divid

ebysysconf(_SC_CLK_TCK)).0

(18)priority%ld优先级,取值在0(high)-39(low)之间,本例中是20

(19)nice%ldThenicevalue(seesetpriority(2)),avalueintherange19(lowpriority)to-20(highpriority).0

(20)num_threads%ld线程数,在本例中是21

(21)itrealvalue%ldhardcodedas0.

(22)starttime%llu进程启动的时间Thetimetheprocessstartedaftersystemboot.8405754

(23)vsize%luVirtualmemorysizeinbytes.937435136

(24)rss%ldResidentSetSize:justthepageswhichcounttowardtext,data,ors

esnotincludepageswhichhavenotbeendemand-loadedin,orwhichareswappedout.7412

(25)rsslim%luCurrentsoftlimitinbytesontherssoftheprocess;seethedescriptionofRLIMIT_RSSingetrlimit(2).70955

1615

(26)startcode%lu[PT]Theaddressabovewhichprogramtextcanrun.1

(27)endcode%lu[PT]Theaddressbelowwhichprogramtextcanrun.1

(28)startstack%lu[PT]Theaddressofthestart(i.e.,bottom)ofthestack.0

(29)kstkesp%lu[PT]ThecurrentvalueofESP(stackpointer),asfoundinthekernelstackpagefortheprocess.0

(30)kstkeip%lu[PT]ThecurrentEIP(instructionpointer).0

(31)signal%luThebitmapofpendingsignals,te,becauseitdoesnotprovideinformationonreal-

timesignals;use/proc/[pid]/statusinstead.0

(32)blocked%luThebitmapofblockedsignals,te,becauseitdoesnotprovideinformationonrea

l-timesignals;use/proc/[pid]/statusinstead.4612

(33)sigignore%luThebitmapofignoredsignals,te,becauseitdoesnotprovideinformationonre

al-timesignals;use/proc/[pid]/statusinstead.0

(34)sigcatch%luThebitmapofcaughtsignals,te,becauseitdoesnotprovideinformationonreal

-timesignals;use/proc/[pid]/statusinstead.38136

(35)wchan%lu[PT]Thisisthe“channel”eaddressofalocationinthekernelwheretheprocessis

respondingsymbolicnamecanbefoundin/proc/[pid]/wchan.18446744

(36)nswap%lualways0

(37)cnswap%lualways0

(38)exit_signal%d(sinceLinux2.1.22)Signaltobesenttoparentwhenwedie.17

(39)processor%d上次运⾏在哪个cpu核上(sinceLinux2.2.8)CPUnumberlastexecutedon.3

(40)rt_priority%u(sinceLinux2.5.19)Real-timeschedulingpriority,anumberintherange1to99forprocessesscheduledunderareal-ti

mepolicy,or0,fornon-real-timeprocesses(seesched_setscheduler(2)).0

(41)policy%u(sinceLinux2.5.19)Schedulingpolicy(seesched_setscheduler(2)).DecodeusingtheSCHED_*constantsinlinux/sched.

h.0

(42)delayacct_blkio_ticks%llu(sinceLinux2.6.18)AggregatedblockI/Odelays,measuredinclockticks(centiseconds).0

(43)guest_time%lu(sinceLinux2.6.24)Guesttimeoftheprocess(timespentrunningavirtualCPUforaguestoperatingsystem),measu

redinclockticks(dividebysysconf(_SC_CLK_TCK)).0

(44)cguest_time%ld(sinceLinux2.6.24)Guesttimeoftheprocess’schildren,measuredinclockticks(dividebysysconf(_SC_CLK_TC

K)).0

(45)start_data%lu(sinceLinux3.3)[PT]Addressabovewhichprograminitializedanduninitialized(BSS)dataareplaced.0

(46)end_data%lu(sinceLinux3.3)[PT]Addressbelowwhichprograminitializedanduninitialized(BSS)dataareplaced.0

(47)start_brk%lu(sinceLinux3.3)[PT]Addressabovewhichprogramheapcanbeexpandedwithbrk(2).0

(48)arg_start%lu(sinceLinux3.5)[PT]Addressabovewhichprogramcommand-linearguments(argv)areplaced.0

(49)arg_end%lu(sinceLinux3.5)[PT]Addressbelowprogramcommand-linearguments(argv)areplaced.0

(49)arg_end%lu(sinceLinux3.5)[PT]Addressbelowprogramcommand-linearguments(argv)areplaced.0

(50)env_start%lu(sinceLinux3.5)[PT]Addressabovewhichprogramenvironmentisplaced.0

(51)env_end%lu(sinceLinux3.5)[PT]Addressbelowwhichprogramenvironmentisplaced.0

(52)exit_code%d(sinceLinux3.5)[PT]Thethread’sexitstatusintheformreportedbywaitpid(2).0

上⾯这些项在kernel中都能找到对应的代码,在fs/proc/array.c的do_task_stat⽅法中,如下

虽然数据项很多,但是我们并不是全都关⼼,其中只有线程名,pid,优先级,运⾏在哪个核上,以及当前进程或线程占⽤的cpu时间这

⼏项是我们所关⼼的。具体来说,process_total_time=utime+stime+cutime+cstime,即上⾯数据项中的(14)~(17)项。由此,我

们就很清楚要怎么计算某⼀进程或线程的CPU使⽤率了:

在两个时间点分别通过/proc/stat和/proc/[pid]/stat抓取总体CPU数据快照和进程(线程)CPU数据快照,从⽽计算出total_time_delta和proc

ess_time_delta,如果要具体到某⼀个核上的CPU使⽤率,则利⽤/proc/stat也可以计算出core_time_delta,随后利⽤process_time_delta*

100%/total_time_delta或process_time_delta*100%/core_time_delta即可计算进程(线程)的总体CPU使⽤率或某⼀个核上的CPU使⽤率

1.3top

top提供了CPU数据的实时监视

Usage:top[-mmax_procs][-niterations][-ddelay][-ssort_column][-t][-h]

-mnumMaximumnumberofprocessestodisplay.最多显⽰⼏个进程,top会⾃动进⾏排序,⽐如让CPU占⽤率⾼的进程在前

-nnumUpdatestoshowbeforeexiting.刷新次数

-dnumSecondstowaitbetweenupdates.刷新间隔,可以输⼊⼩数即代表毫秒级间隔

-scolColumntosortby(cpu,vss,rss,thr).选择以哪⼀项进⾏排序

-tShowthreadsinsteadofprocesses.显⽰线程

-hDisplaythishelpscreen.

在⼿边的电视上运⾏top-m5命令,结果如下

相信此时你⼀定已经明⽩最开始两⾏数据的含义了。接下来的表头项含义如下

PID:略

PR:在androidN之前代表运⾏在哪个核上,在androidN上代表优先级,当然可能设备⼚商会进⾏⾃定义

CPU%:略

S:运⾏状态

#THR:线程数

VSS:VirtualSetSize虚拟耗⽤内存(包含共享库占⽤的内存)

seq_printf(m,"%d(%s)%c",pid_nr_ns(pid,ns),tcomm,state);

seq_put_decimal_ll(m,'',ppid);

seq_put_decimal_ll(m,'',pgid);

seq_put_decimal_ll(m,'',sid);

seq_put_decimal_ll(m,'',tty_nr);

seq_put_decimal_ll(m,'',tty_pgrp);

seq_put_decimal_ull(m,'',task->flags);

seq_put_decimal_ull(m,'',min_flt);

seq_put_decimal_ull(m,'',cmin_flt);

seq_put_decimal_ull(m,'',maj_flt);

seq_put_decimal_ull(m,'',cmaj_flt);

seq_put_decimal_ull(m,'',cputime_to_clock_t(utime));

seq_put_decimal_ull(m,'',cputime_to_clock_t(stime));

seq_put_decimal_ll(m,'',cputime_to_clock_t(cutime));

seq_put_decimal_ll(m,'',cputime_to_clock_t(cstime));

seq_put_decimal_ll(m,'',priority);

....

adbshelltop

User5%,System5%,IOW0%,IRQ0%

User70+Nice0+Sys70+Idle1069+IOW1+IRQ0+SIRQ3=1213

PIDPRCPU%S#THRVSSRSSPCYUIDName

172802%S28648828K18764Kfgsystem/system/bin/surfaceflinger

2636622%xxxxx

179201%S611640236K16508Kfgroot/applications/bin/xxxx

390630%xxxxxx

2519210%xxxx

VSS:VirtualSetSize虚拟耗⽤内存(包含共享库占⽤的内存)

RSS:ResidentSetSize实际使⽤物理内存(包含共享库占⽤的内存)

PCY:调度策略优先级,SP_BACKGROUND/SP_FOREGROUND

UID:进程所有者的⽤户id

Name:进程名

加上-t参数,结果如下

多了TID和Thread表头项,顾名思义。

那么top命令⼜是如何计算出cpu占⽤率的呢?想必你已经猜到了,也是通过读取上⾯的/proc/stat,/proc/[pid]/stat,/proc/[pid]/task/[tid]/stat

。查看top的源码,在system/core/toolbox/top.c中可以看到

读取CPU数据部分的代码如下,可以说是⾮常浅显易懂了

staticvoidread_procs(void){

DIR*proc_dir,*task_dir;

structdirent*pid_dir,*tid_dir;

charfilename[64];

FILE*file;

intproc_num;

structproc_info*proc;

pid_tpid,tid;

inti;

proc_dir=opendir("/proc");

if(!proc_dir)die("Couldnotopen/proc.n");

new_procs=calloc(INIT_PROCS*(threads?THREAD_MULT:1),sizeof(structproc_info*));

num_new_procs=INIT_PROCS*(threads?THREAD_MULT:1);

file=fopen("/proc/stat","r");

if(!file)die("Couldnotopen/proc/stat.n");

fscanf(file,"cpu%lu%lu%lu%lu%lu%lu%lu",&new_,&new_,&new_,

&new_,&new_e,&new_e,&new_me);

fclose(file);

proc_num=0;

while((pid_dir=readdir(proc_dir))){

if(!isdigit(pid_dir->d_name[0]))

continue;

pid=atoi(pid_dir->d_name);

structproc_infocur_proc;

if(!threads){

proc=alloc_proc();

proc->pid=proc->tid=pid;

sprintf(filename,"/proc/%d/stat",pid);

read_stat(filename,proc);

sprintf(filename,"/proc/%d/cmdline",pid);

read_cmdline(filename,proc);

User2%,System2%,IOW0%,IRQ0%

User30+Nice0+Sys33+Idle1195+IOW0+IRQ0+SIRQ2=1260

PIDTIDPRCPU%SVSSRSSPCYUIDThreadProc

294022940220%R4204K1612Kfgshelltoptop

1792209910%S1640236K16508KfgrootInitHDMIthread/applications/xxxx

1039103930%S0K0Kfgrootirq/202-scaler

293952939500%S0K0Kfgrootkworker/0:2

1737239230%S826844K10920Kfgmediamediaserver/system/bin/mediaserver

sprintf(filename,"/proc/%d/status",pid);

read_status(filename,proc);

read_policy(pid,proc);

proc->num_threads=0;

}else{

sprintf(filename,"/proc/%d/cmdline",pid);

read_cmdline(filename,&cur_proc);

sprintf(filename,"/proc/%d/status",pid);

read_status(filename,&cur_proc);

proc=NULL;

}

sprintf(filename,"/proc/%d/task",pid);

task_dir=opendir(filename);

if(!task_dir)continue;

while((tid_dir=readdir(task_dir))){

if(!isdigit(tid_dir->d_name[0]))

continue;

if(threads){

tid=atoi(tid_dir->d_name);

proc=alloc_proc();

proc->pid=pid;proc->tid=tid;

sprintf(filename,"/proc/%d/task/%d/stat",pid,tid);

read_stat(filename,proc);

read_policy(tid,proc);

strcpy(proc->name,cur_);

proc->uid=cur_;

proc->gid=cur_;

add_proc(proc_num++,proc);

}else{

proc->num_threads++;

}

}

closedir(task_dir);

if(!threads)

add_proc(proc_num++,proc);

}

for(i=proc_num;i

new_procs[i]=NULL;

closedir(proc_dir);

}

staticintread_stat(char*filename,structproc_info*proc){

FILE*file;

charbuf[MAX_LINE],*open_paren,*close_paren;

file=fopen(filename,"r");

if(!file)return1;

fgets(buf,MAX_LINE,file);

fclose(file);

fclose(file);

/*Splitatfirst'('andlast')'togetprocessname.*/

open_paren=strchr(buf,'(');

close_paren=strrchr(buf,')');

if(!open_paren||!close_paren)return1;

*open_paren=*close_paren='0';

strncpy(proc->tname,open_paren+1,THREAD_NAME_LEN);

proc->tname[THREAD_NAME_LEN-1]=0;

/*Scanrestofstring.*/

sscanf(close_paren+1,

"%c""%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d"

"%"SCNu64"%"SCNu64"%*d%*d%*d%*d%*d%*d%*d"

"%"SCNu64"%"SCNu64"%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d%*d"

"%d",

&proc->state,

&proc->utime,

&proc->stime,

&proc->vss,

&proc->rss,

&proc->prs);

return0;

}

⽽计算CPU占⽤率的⽅法也和我们前⾯说的⼀致,同样在top.c中可以看到,也很浅显易懂

staticvoidprint_procs(void){

inti;

structproc_info*old_proc,*proc;

longunsignedtotal_delta_time;

structpasswd*user;

char*user_str,user_buf[20];

for(i=0;i

if(new_procs[i]){

old_proc=find_old_proc(new_procs[i]->pid,new_procs[i]->tid);

if(old_proc){

new_procs[i]->delta_utime=new_procs[i]->utime-old_proc->utime;

new_procs[i]->delta_stime=new_procs[i]->stime-old_proc->stime;

}else{

new_procs[i]->delta_utime=0;

new_procs[i]->delta_stime=0;

}

new_procs[i]->delta_time=new_procs[i]->delta_utime+new_procs[i]->delta_stime;

}

}

total_delta_time=(new_+new_+new_+new_

+new_e+new_e+new_me)

-(old_+old_+old_+old_

+old_e+old_e+old_me);

qsort(new_procs,num_new_procs,sizeof(structproc_info*),proc_cmp);

printf("nnn");

printf("User%ld%%,System%ld%%,IOW%ld%%,IRQ%ld%%n",

((new_+new_)-(old_+old_))*100/total_delta_time,

((new_)-(old_))*100/total_delta_time,

((new_e)-(old_e))*100/total_delta_time,

((new_e+new_me)

-(old_e+old_me))*100/total_delta_time);

printf("User%ld+Nice%ld+Sys%ld+Idle%ld+IOW%ld+IRQ%ld+SIRQ%ld=%ldn",

new_-old_,

new_-old_,

new_-old_,

new_-old_,

new_e-old_e,

1.4dumpsyscpuinfo

在⼿边的电视上运⾏的结果如下

Load:3.18/3.42/3.49

CPUusagefrom1053590msto153542msago:

7%1792/xxx:2.7%user+4.3%kernel

3.3%1728/surfaceflinger:2.3%user+0.9%kernel

3.1%26366/:2.4%user+0.7%kernel/faults:197480minor

2.1%25192/:1.7%user+0.4%kernel/faults:28686minor

1.7%2204/system_server:1.2%user+0.4%kernel/faults:4071minor

....

dumpsys的原理是利⽤Binder的dump,如源码所⽰,在/frameworks/native/cmds/dumpsys/中

spservice=sm->checkService(services[i]);

if(service!=NULL){

if(N>1){

aout<<"------------------------------------------------------------"

"-------------------"<

aout<<"DUMPOFSERVICE"<

}

interr=service->dump(STDOUT_FILENO,args);

if(err!=0){

aerr<<"Errordumpingserviceinfo:("<

<<")"<

}

}else{

aerr<<"Can'tfindservice:"<

}

对应到/frameworks/base/services/core/java/com/android/server/am/

new_e-old_e,

new_e-old_e,

new_me-old_me,

total_delta_time);

printf("n");

if(!threads)

printf("%5s%2s%4s%1s%5s%7s%7s%3s%-8s%sn","PID","PR","CPU%","S","#THR","VSS","RSS","PCY","UID","Name");

else

printf("%5s%5s%2s%4s%1s%7s%7s%3s%-8s%-15s%sn","PID","TID","PR","CPU%","S","VSS","RSS","PCY","UID","Thread","Proc");

for(i=0;i

proc=new_procs[i];

if(!proc||(max_procs&&(i>=max_procs)))

break;

user=getpwuid(proc->uid);

if(user&&user->pw_name){

user_str=user->pw_name;

}else{

snprintf(user_buf,20,"%d",proc->uid);

user_str=user_buf;

}

if(!threads){

printf("%5d%2d%3"PRIu64"%%%c%5d%6"PRIu64"K%6"PRIu64"K%3s%-8.8s%sn",

proc->pid,proc->prs,proc->delta_time*100/total_delta_time,proc->state,proc->num_threads,

proc->vss/1024,proc->rss*getpagesize()/1024,proc->policy,user_str,proc->name[0]!=0?proc->name:proc->tname);

}else{

printf("%5d%5d%2d%3"PRIu64"%%%c%6"PRIu64"K%6"PRIu64"K%3s%-8.8s%-15s%sn",

proc->pid,proc->tid,proc->prs,proc->delta_time*100/total_delta_time,proc->state,

proc->vss/1024,proc->rss*getpagesize()/1024,proc->policy,user_str,proc->tname,proc->name);

}

}

}

adbshelldumpsyscpuinfo

对应到/frameworks/base/services/core/java/com/android/server/am/

if(MONITOR_CPU_USAGE){

vice("cpuinfo",newCpuBinder(this));

}

对应的CPUBinder内容如下

staticclassCpuBinderextendsBinder{

ActivityManagerServicemActivityManagerService;

CpuBinder(ActivityManagerServiceactivityManagerService){

mActivityManagerService=activityManagerService;

}

@Override

protectedvoiddump(FileDescriptorfd,PrintWriterpw,String[]args){

if(allingPermission()

!=SION_GRANTED){

n("PermissionDenial:can'tdumpcpuinfofromfrompid="

+lingPid()+",uid="+lingUid()

+"withoutpermission"+);

return;

}

synchronized(ssCpuTracker){

(urrentLoad());

(urrentState(

Millis()));

}

}

}

printCurrenLoad和printCurrentState⽅法在/frameworks/base/core/java/com/android/internal/os/中可以看到,

⼀样是读取/proc下的内容,⽐如第⼀⾏三个Load值就是读取的/proc/loadavg的前三项,查看man-page即可知其含义,如下

Thefirstthreefieldsinthisfileareloadaveragefiguresgivingthenumberofjobsintherunqueue(stateR)orwaitingfordiskI/O(state

D)averagedover1,5,and15minutes.

⼆、写个脚本获取各个线程在各个CPU核上的占⽤率

通过前⾯的介绍,我们发现这些⽅法都只是抓取瞬时CPU占⽤率数据,⽽难以⽅便的持续输出某⼀个进程或线程在各个CPU核上的占⽤

率数据。此前我们介绍过DS5StreamLine⼯具可以完成这⼀⼯具,但是有两个问题:⼀是必须要拿到设备的源码编译出指定的库才能使⽤

StreamLine⼯具,⼆是要付费……

基于这样的背景,我们可以⾃⼰写个python脚本,读取/proc下的内容,输出⼀段时间内某⼀个进程或线程在各个CPU核上的占⽤率数据。

话不多说,直接上代码,还是⽐较简单的。在脚本开头简单描述了设计思路

#!/usr/bin/python

#coding:utf-8

Thisscriptcancalculatecpuusagepercentageoneachcoreofaprocess'sthreads

#Author:

#zhanghui

#LeEcoBSPMultimedia/CommunicationUniversityofChina

###BasicDesignIdeaisasfollows:

'''inputpidlistthreadsbyls/proc/pid/taskstructthread_info{a}a{core0_percentage[]core1_perc

importos

importsys

importsubprocess

importtime

importtime

importcommands

fromoptparseimportOptionParser

fromtimeimportsleep

fromsubprocessimportcheck_output,CalledProcessError

globalOptions

globalPid

globalInterval

Threads=[]

classCpudata:

def__init__(self):

ts=[]

0_percent=[]

1_percent=[]

2_percent=[]

3_percent=[]

(0_percent)

(1_percent)

(2_percent)

(3_percent)

_utime_old=0

_stime_old=0

_utime_new=0

_stime_new=0

_time_delta=0

_times_old=[]

_times_new=[]

defaddData(self,coreID,percent):

ts[coreID].append(percent)

defgetData(self,coreID):

ts[coreID]

defgetProcUtimeOld(self):

_utime_old

defgetProcStimeOld(self):

_stime_old

defgetProcUtimeNew(self):

_utime_new

defgetProcStimeNew(self):

_stime_new

defgetCpuTimesOld(self):

_times_old

defgetCpuTimesNew(self):

_times_new

defgetProcTimeDelta(self):

_time_delta

defgetPercents(self):

ts

defsetProcUtimeOld(self,utime):

_utime_old=utime

defsetProcStimeOld(self,stime):

_stime_old=stime

_stime_old=stime

defsetProcUtimeNew(self,utime):

_utime_new=utime

defsetProcStimeNew(self,stime):

_stime_new=stime

defsetCpuTimesOld(self,cputimes):

_times_old=cputimes

defsetCpuTimesNew(self,cputimes):

_times_new=cputimes

defcalProcTimeDelta(self):

new=(int)(_utime_new)+(int)(_stime_new)

old=(int)(_utime_old)+(int)(_stime_old)

_time_delta=new-old

defcalPercentage(self,which_cpu):

cpu_time_delta=_times_new[which_cpu]-_times_old[which_cpu]

ifcpu_time_delta==0:

percentage=0

else:

percentage=_time_delta*100/cpu_time_delta

foriinrange(0,4):

ifi==which_cpu:

ts[i].append(percentage)

else:

ts[i].append(0)

classThread:

def__init__(self,tid):

=tid

=''

ty=0

a=Cpudata()

defgetName(self):

defgetTid(self):

return(int)()

defgetPrio(self):

ty

defgetCpudata(self):

a

defsetName(self,name):

=name

defrun_command(options,cmd):

:

print'COMMAND:',cmd

try:

out_bytes=_output(cmd,shell=True)

out_text=out_('utf-8')

returnout_text

exceptCalledProcessError,e:

message="binarytoolfailedwitherror%d"%code

e:

message+="-"+str(cmd)

raiseException(message)

deflist_threads(options,pid):

cmd='adbshellls/proc/'+pid+'/task'

result=run_command(options,cmd)

result=()

tids=('n')

foriinrange(len(tids)):

thread=Thread((int)(tids[i]))

(thread)

defcal_percent(options,pid,thread,cputimes):

cmd='adbshellcat/proc/%d/task/%d/stat'%((int)(pid),())

#somethinglike:

#18368(Loader:HlsSampl)S375446328

result=run_command(options,cmd)

datas=('')

e(datas[1])

which_cpu=(int)(datas[38])

data().getProcUtimeOld()==data().getProcStimeOld()==0:

data().setProcUtimeOld((int)(datas[13]))

data().setProcStimeOld((int)(datas[14]))

data().setCpuTimesOld(cputimes)

else:

data().setProcUtimeNew((int)(datas[13]))

data().setProcStimeNew((int)(datas[14]))

data().calProcTimeDelta()

data().setCpuTimesNew(cputimes)

data().calPercentage(which_cpu)

data().setProcUtimeOld(data().getProcUtimeNew())

data().setProcStimeOld(data().getProcStimeNew())

data().setCpuTimesOld(data().getCpuTimesNew())

defget_cputime(options):

cmd='adbshellcat/proc/stat'

#somethinglike:

#cpu000

result=run_command(options,cmd)#(cmd,shell=True,stdout=).stdout

cpu_raw_datas=('n')

cpu_times=[]

foriinrange(1,5):

cpu_info=cpu_raw_datas[i].split('')

cpu_one_core_total_time=0

forjinrange(1,8):

cpu_one_core_total_time+=(int)(cpu_info[j])

cpu_(cpu_one_core_total_time)

returncpu_times

defdraw_plot(options):

foriinrange(len(Threads)):

print'ThreadName:',Threads[i].getName()

print'Cpu#0:',

printThreads[i].getCpudata().getPercents()[0]

print'Cpu#1:',

printThreads[i].getCpudata().getPercents()[1]

print'Cpu#2:',

printThreads[i].getCpudata().getPercents()[2]

print'Cpu#3:',

printThreads[i].getCpudata().getPercents()[3]

if__name__=='__main__':

parser=OptionParser(usage="%prog-d-ppid-tinterval")

_option('-d','--debug',dest="debug",action='store_true',default=False,

help="Printoutdebugginginformation")

_option('-p','--pid',dest="process_id",

help="Processid")

_option('-t','--interval',dest="time_interval",

_option('-t','--interval',dest="time_interval",

help="Timeintervalfordatacollecting,insecondsex.(0.1means100ms)")

(options,args)=_args()

s_id:

Pid=s_id

_interval:

Interval=(float)(_interval)

list_threads(options,Pid)

print'startcollectingdata...'

whileTrue:

try:

CpuTimes=get_cputime(options)

foriinrange(len(Threads)):

cal_percent(options,Pid,Threads[i],CpuTimes)

sleep(Interval)

exceptKeyboardInterrupt:

print'stopcollectingdata...'

print'startgeneratingreport...'

draw_plot(options)

print'reportexported'

("Finished")

以我⼿边的电视为例,adbconnect之后,看到电视上⾯有⼀个pid=22868的进程,则输⼊下⾯的命令

即可以10ms为间隔记录该进程下所有线程在各个cpu核上的占⽤率结果,记录⼀段时间后按Ctrl+c退出记录,则⾃动打印出记录结果,

如下

startcollectingdata...

^Cstopcollectingdata...

startgeneratingreport...

ThreadName:(ExoPlayerImplIn)

Cpu#0:[0,0,0,0,0,0,26,0,27,23,0,0,0,0,0,0,0,23,26,0,0,0,0,20,0,17,0,0,0,0,20,0,0,0,0]

Cpu#1:[22,23,29,25,0,0,0,0,0,0,26,0,23,0,23,24,0,0,0,0,22,22,0,0,0,0,0,0,0,0,0,28,0,25,27]

Cpu#2:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,22,0,0,0,0,0,0,0,24,0,0]

Cpu#3:[0,0,0,0,24,24,0,28,0,0,0,25,0,25,0,0,26,0,0,21,0,0,0,0,0,0,21,21,22,20,0,0,0,0,0]

ThreadName:(Loader:HlsSampl)

Cpu#0:[0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,11,0,13,0,0,0,0,0]

Cpu#1:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,17,0,0,0,0,0,19,0,0,0,0,0,0,0,0]

Cpu#2:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,14,0,0,0,0,0,0,0,0,0]

Cpu#3:[13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,13,14,0,0,0,16,0,14,0,0,0,0]

ThreadName:(MediaCodec_loop)

Cpu#0:[4,4,0,5,2,0,0,3,0,0,0,0,4,0,0,0,0,4,0,0,0,0,3,0,4,3,0,4,3,0,4,0,0,0,3]

Cpu#1:[0,0,0,0,0,4,5,0,3,0,3,4,0,4,4,4,0,0,0,3,3,4,0,0,0,0,0,0,0,3,0,4,0,4,0]

Cpu#2:[0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0]

Cpu#3:[0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,4,0,0]

....

reportexported

Finished

以上便是本⽂的所有内容了,因为我在android性能优化⽅⾯还是新⼿,有任何错误之处欢迎交流指出

./-p22868-t0.01

更多推荐

systemidle