appfabric-geartrax
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/中
sp
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
发布评论