android性能分析之常用命令

性能分析:

从AS3.0,android使用Profile来进行分析,关于Profile的使用,请参考文章:
Android Profiler分析(一)概述
Android Profiler分析(二) Memory Profiler
Android Profiler分析(三) CPU Profiler

android性能分析之Systrace

常用命令

  • Android studio的工具-Memory Monitor
    Memory Monitor工具主要是用来监测APP的内存分配情况,判断是否存在内存泄漏
    Dump Java Heap定位内存泄漏, 生成.hprof
    Eclipse: ddms->update heap->cause gc生成总内存信息,然后会有data object

  • 运行时错误分析
    /data/tombstones
    全志平台:/mnt/extsd/tombstones
    addr2line 工具和 objdump 工具来定位backtrace错误

工具位置:windows: ndk\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86_64\bin

  • arm-linux-androideabi-addr2line -C -f -e libss.so 00026cb3
    -e 选项来指定可执行libss.so。
    -f 选项,可以告诉工具输出函数名
  • arm-eabi-objdump -S libss.so > dvb_map.txt
  • CPU
  • 查看CPU占用空间:
    adb shell dumpsys cpuinfo <package_name>/pid

  • 查看进程占用CPU
    top -p < pid >

  • 查看CPU负载
    adb shell uptime
    20:09:54 up 71 days, 10:48, 1 user, load average: 0.99, 0.78, 0.86
    Load后面的三个数字的意思分别是1分钟、5分钟、15分钟内系统的平均负荷

  • 查看CPU状态
    online CPU数量:cat /sys/devices/system/cpu/online
    查看具体CPU的当前频率:cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

  • CPU各个频率下的运行时间,单位:10 mS
    adb shell cat /sys/devices/system/cpu/cpu1/cpufreq/stats/time_in_state
    频度 时间
    652800 1813593
    1036800 46484

  • cpu governor
    cpu gorvenor对应的是CPU的调频策略,默认的是interactive,performance是一直保持在最高频率
    查看governor类型:cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

  • 影响CPU hotplug的因素(以高通平台为例)
    perfd,可以通过stop perfd关闭
    thermel,可以通过stop thermal-engine关闭
    core_crtl,可通过rmmod core_crtl来关闭

  • 调度
    ps -p可以观察进程优先级,systrace也能看到
    /dev/cpuctl,不同的组之间具有不一样的抢占能力
    /dev/cpuset,不同的组可使用的cpu不一样,如果线程跑在小核,则线程在./system-background/tasks中,通过grep [pid] -rn ./ 查看
    cat /proc/sched_debug,查看调度队列的信息
    kill -3 (pid) 打印进程当前各个线程的调用栈
    taskset -p [pid] 查看线程在大核还是小核

  • LPM
    CPU在idle时会进入low power mode,需要运行任务时再从LPM推出,在一些需要频繁进出idle的应用场景下,有的CPU会出现明显
    的性能下降,可以disableLPM来验证这个问题
    stop perfd (因为perfd会改写lpm的值)
    echo N > /sys/module/lpm_levels/parameters/sleep_disabled
  • 将cpu固定在最高频
    高通平台
    stop perfd
    stop thermal-engine
    rmmod core_ctl
    echo 1 > /sys/devices/system/cpu/cpu0/online(遍历每个core)
    echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor(遍历每个cluster)
    MTK平台
    adb shell “echo 0 > /proc/hps/enabled”
    echo 1 > /sys/devices/system/cpu/cpu0/online(遍历每个core)
    echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor(遍历每个cluster)
  • 修改CPU频率
    高通888为4+3+1结构,所以/sys/devices/system/cpu/cpufreq/下有三个节点policy0、policy4、policy7
    cpu0~3的频率策略对应policy0、cpu7对应策略为policy7
    通过scaling_available_frequencies查看支持的频率,比如844800 960000 1075200 1190400 1305600 1420800 1555200 1670400 1785600 1900800 2035200 2150400 2265600 2380800 2496000 2592000 2688000 2764800 2841600
    然后echo 844800 > scaling_max_freq设置最大频率
  • 内存
  • 查看系统内存状态
    cat /proc/meminfo
    adb shell procrank (pid)
    adb shell dumpsys meminfo/cpuinfo <package_name>/pid内查看本地层程序
    top -t -m 5 -n 2 查询Cpu/内存的基本使用
    adb shell cat /proc/buddyinfo
    adb shell cat /proc/meminfo
    adb shell cat /proc/pid/maps
  • 查看内存碎片状态
    cat /proc/pagetypeinfo
  • 查看应用的graphic缓存(如纹理缓存)
    dumpsys gfxinfo
  • 查看进程内的位图
    dumpsys gfxinfo [pid] -b
  • 查看lowmemorykiller阈值
    cat /sys/module/lowmemorykiller/parameters/minfree
    cat /sys/module/lowmemorykiller/parameters/adj
  • 查看ion buffer使用情况,比如起camera的时候会有大量的ion使用
    cat /d/ion/heaps/system
  • IO
  • drop cache
    文件系统会有大量的page cache放在内存中,如果需要清理这个缓存,可以
    echo 3 > /proc/sys/vm/drop_caches
  • read_ahead
    文件page_fault时会预读一定数量的内容以便后续访问,不合适的预读大小可能会影响性能
    查看预读的大小
    cat /sys/class/block/mmcblk0/queue/read_ahead_kb
  • IO scheduler
    查看IO scheduler类型
    cat /sys/class/block/mmcblk0/queue/scheduler
  • IO速度
    通常的IO测试是通过文件系统来读写文件,速度在很大程度上受到file cache的影响,
    如果需要衡量纯粹的硬件读写能力,可以在read/write API使用O_DIRECT flag
    Android手机的测试推荐使用FIO工具
  • 查看磁盘占用空间
    du -sH * 查看当前目录下文件空间
    df 查看分区占用空间

  • 对进程打开的所有文件进行监控: lsof -p 7005

  • dumpsys命令
    dumpsys activity | grep mFocusedActivity 查看当前焦点activity
    adb shell dumpsys meminfo/cpuinfo <package_name>/pid内查看本地层程序

  • 老化影响

老化后,可能跟可能和thermal以及cache相关,建议测试时候每次都要做:
1.等待运行完毕
adb shell sm fstrim
adb shell sm idle-maint run
2. adb shell stop thermal-engine
adb shell stop mi_thermald
3. echo 3 > /proc/sys/vm/drop_caches

按键事件:

adb shell getevent –t 查看当前按下按键的值
在这里插入图片描述
事件类型(0001),事件代码(0074)以及事件的值(00000001)
adb shell getevent /dev/input/event2 获取event2设备的事件
adb shell input keyevent 4 返回按键

卡顿内容等性能分析:

-traceview
TraceView可视化工具可以看出代码在运行时的一些具体信息,方法调用时长,次数,时间比率,了解代码运行过程的效率问题,从而针对性改善代码。它主要用于分析Android中应用程序的hotspot。Traceview本身只是一个数据分析工具,而数据的采集则需要使用Android SDK中的Debug类或者利用DDMS工具。

TraceView用法

  1. Ddms打开, Start Method Profiling->操作界面->stop, 操作最好不要超过5s
    在这里插入图片描述
  2. android.os.Debug.startMethodTracing();和android.os.Debug.stopMethodTracing();然后在sdcard目录下生产trace文件
  3. 打开tools目录下monitor.bat或者eclipse,脚本如下

@echo off
rem color 0A :设置cmd背景颜色和字体颜色 color 0A
rem title:设置cmd标题
title Start Android Studio Mointor
rem echo 请按任意键打开 Android Studio Mointor …
rem pause>nul call
D:\tools\adt-bundle-windows-x86_64-20140702\sdk\tools\monitor.bat
如果无法打开,则需要把androidstudio中的jre拷贝到monitor程序的目录下
Ubuntu:android/Sdk/tools/lib/monitor-x86_64

Profile Panel各列作用说明

描述
Name该线程运行过程中所调用的函数名
Incl Cpu Time某函数占用的CPU时间,包含内部调用其它函数的CPU时间
Excl Cpu Time某函数占用的CPU时间,但不含内部调用其它函数所占用的CPU时间
Incl Real Time某函数运行的真实时间(以毫秒为单位),内含调用其它函数所占用的真实时间
Excl Real Time某函数运行的真实时间(以毫秒为单位),不含调用其它函数所占用的真实时间
Call+Recur Calls/Total某函数被调用次数以及递归调用占总调用次数的百分比
Cpu Time/Call某函数调用CPU时间与调用次数的比。相当于该函数平均执行时间
Real Time/Call同CPU Time/Call类似,只不过统计单位换成了真实时间

一般而言,hotspot包括两种类型的函数: 一类是调用次数不多,但每次调用却需要花费很长时间的函数。先按降序对时间项进行排列(可以是时间百分比、真实时间或CPU时间),然后查找耗费时间最多的函数
一类是那些自身占用时间不长,但调用却非常频繁的函数。

Systrace

Systrace的功能包括跟踪系统的I/O操作、内核工作队列、CPU负载以及Android各个子系统的运行状况(如surfaceflinger、WindowManagerService等Framework部分关键模块、服务)等,。
在Android平台中,它主要由3部分组成:

内核部分:Systrace利用了Linux Kernel中的ftrace功能。必须开启kernel中和ftrace相关的模块。
数据采集部分:Android定义了一个Trace类。应用程序可利用该类把统计信息输出给ftrace。同时,Android还有一个atrace程序,它可以从ftrace中读取统计信息然后交给数据分析工具来处理。
数据分析工具:Android提供一个systrace.py(python脚本文件,位于Android SDK目录/tools/systrace中,其内部将调用atrace程序)用来配置数据采集的方式(如采集数据的标签、输出文件名等)和收集ftrace统计数据并生成一个结果网页文件供用户查看。

从本质上说,Systrace是对Linux Kernel中ftrace的封装。应用进程需要利用Android提供的Trace类来使用Systrace。Android 4.1为系统中的几个关键进程和模块都添加了Systrace功能
添加代码的跟踪方式native和java
native层用法

头文件:<utils/Trace.h>
定义ATRACE_TAG:如使用了ATRACE_TAG_GRAPHICS,表示它和Graphics相关。
ATRACE_INIT:用于统计某个变量使用的情况。ATRACE_INIT(“变量TAG”, 变量名)
ATRACE_CALL:用于统计函数的调用情况ATRACE_CALL()

app层

Trace.beginSection(“Fragement_onCreateView”);
// … 其他代码
// …
// … 结束处
Trace.endSection()
然后通过指令:python systrace.py --app=sectionName 指定APK,或者通过DDMS选择指定APK,抓取systrace分析

Java framework层

Trace.traceBegin(long traceTag, String methodName)
Trace.traceEnd(long traceTag)

打开方式:
进入Android/Sdk/platform-tools/systrace目录下
python systrace.py [options] [category1] [category2] … [categoryN]

[options]”是一些命令参数;“[category]”等是你感兴趣的系统模块,比如view代表View系统(包含绘制流程),am代表ActivityManager(包含Activity的创建过程等
如:python systrace.py --time=10 -o mynewtrace.html sched gfx view wm

要在 Pixel/Pixel XL 上调试抖动问题,请从以下命令开始:

./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000
如果报错apt-get install python-six,请执行sudo apt-get install python-six

options:

options描述
-o < FILE >输出的目标文件
-t N, –time=N执行时间,默认5s
-b N, –buf-size=Nbuffer大小(单位kB),用于限制trace总大小,默认无上限
-k < KFUNCS >,–ktrace=< KFUNCS >追踪kernel函数,用逗号分隔
-a < APP_NAME >,–app=< APP_NAME >追踪应用包名,用逗号分隔
–from-file=< FROM_FILE >从文件中创建互动的systrace
-e < DEVICE_SERIAL >,–serial=< DEVICE_SERIAL >指定设备
-l, –list-categories列举可用的tags

category常用取值

sched:CPU调度的信息,非常重要;你能看到CPU在每个时间段在运行什么线程;线程调度情况,比如锁信息。
gfx:Graphic系统的相关信息,包括SurfaceFlinger,VSYNC消息,Texture,RenderThread等;分析卡顿非常依赖这个。
view:View绘制系统的相关信息,比如onMeasure,onLayout等;对分析卡顿比较有帮助。
am:ActivityManager调用的相关信息;用来分析Activity的启动过程比较有效。
dalvik: 虚拟机相关信息,比如GC停顿等。
binder_driver:Binder驱动的相关信息,如果你怀疑是Binder IPC的问题,不妨打开这个。
core_services:SystemServer中系统核心Service的相关信息,分析特定问题用。

利用anr日志:

- java层:
默认trace位置: /data/anr/trace.txt
可以通过修改系统属性dalvik.vm.stack-trace-file改变trace文件路径

ANR分类
从发生的场景分类:

  • Input事件超过5s没有被处理完
  • Service处理超时,前台20s,后台200s
  • BroadcastReceiver处理超时,前台10S,后台60s
  • ContentProvider执行超时,比较少见

从发生的原因分:

  • 主线程有耗时操作,如有复杂的layout布局,IO操作等。
  • 被Binder对端block
  • 被子线程同步锁block
  • Binder被占满导致主线程无法和SystemServer通信
  • 得不到系统资源(CPU/RAM/IO)

从进程的角度分:

  • 问题出在当前进程:
  • 主线程本身耗时, 或则主线程的消息队列存在耗时操作;
  • 主线程被本进程的其他子线程所blocked;
  • 问题出在远端进程(一般是binder call或socket等通信方式)
----- pid 27661 at 2017-06-16 16:16:20 -----
Cmd line: com.android.camera
"main" prio=5 tid=1 Waiting
 | group="main" sCount=1 dsCount=0 obj=0x75a4b5c8 self=0xb4cf6500
 | sysTid=27661 nice=-10 cgrp=default sched=0/0 handle=0xb6f6cb34
 | state=S schedstat=( 11242036155 8689191757 38520 ) utm=895 stm=229 core=0 HZ=100
 | stack=0xbe4ea000-0xbe4ec000 stackSize=8MB
 | held mutexes=
 at java.lang.Object.wait!(Native method)
 - waiting on <0x09e6a059> (a java.lang.Object)
 at java.lang.Thread.parkFor$(Thread.java:1220)
 - locked <0x09e6a059> (a java.lang.Object)
 at sun.misc.Unsafe.park(Unsafe.java:299)
 at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:810)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:970)
 at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1278)
 at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:203)
 at android.app.SharedPreferencesImpl$EditorImpl$1.run(SharedPreferencesImpl.java:366)
 at android.app.QueuedWork.waitToFinish(QueuedWork.java:88)
 at android.app.ActivityThread.handleStopActivity(ActivityThread.java:3605)
 at android.app.ActivityThread.access$1300(ActivityThread.java:153)
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1399)
 at android.os.Handler.dispatchMessage(Handler.java:102)
 at android.os.Looper.loop(Looper.java:154)
 at android.app.ActivityThread.main(ActivityThread.java:5528)
 at java.lang.reflect.Method.invoke!(Native method)
 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:740)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:630)
tid=1线程号
sysTid=27661主线程的线程号和进程号相同
Waiting线程状态,其中state也是线程状态,如果state=D代表底层被blocked了
nicenice值越小,则优先级越高。因为是主线程此处nice=-10, 可以看到优先级很高了
schedstat括号中的3个数字,依次是Running, Runable, Switch,Running时间。Running时间:CPU运行的时间,单位ns。  Runable时间:RQ队列的等待时间,单位ns
utm该线程在用户态所执行的时间,单位是jiffies
stm该线程在内核态所执行的时间,单位是jiffies
sCount此线程被挂起的次数
dsCount线程被调试器挂起的次数,当一个进程被调试后,sCount会重置为0,调试完毕后sCount会根据是否被正常挂起增长,但是dsCount不会被重置为0,所以dsCount也可以用来判断这个线程是否被调试过
self线程本身的地址

一般的看trace有如下规律

  • 发生ANR时,trace中找不到相应进程,检查一下Android Runtime是否因为应用的崩溃给ShutDown了,如果ShutDown了,此时要去查ShutDown的原因。
  • 应用发生ANR,如果主线程正在执行getContentProvider,那么它正在请求另一个应用的ContentProvider,此时要查一下目标ContentProvider的宿主进程,看看正在做什么
  • 主线程执行数据库操作或网络请求,应该是应用自身问题
  • 主线程等待其他线程持有的锁,而目标线程执行数据库操作或网络请求,那么是应用自身问题。

ANR分析基本流程

  • 抓取bugreport,搜索am_anr, ANR in,查看发生的时间和进程
  • 根据进程寻找主线程的trace,发现被blocked的地方,如果是Binder call则,进一步确认下对端的情况;如果是耗时操作,直接修改成异步,怀疑系统执行慢可以看看binder_sample,dvm_lock等信息,其次gc多不多,lmk杀进程是不是很频繁,都可以看出系统的健康状态
  • 结合源码进行分析解决
  • 系统耗时关键字:binder_sample,dvm_lock_sample,am_lifecycle_sample,binder thread

ANR:

VM TRACES AT LAST ANR”,数据来源”/data/anr/traces.txt”
若存在该ANR则输出相应traces,否则输出
*** NO ANR VM TRACES FILE (/data/anr/traces.txt): No such file or directory

am_anr

12-17 06:02:14.463 1566 1583 I am_anr : [0,8769,com.android.updater,952680005,Broadcast of Intent { act=android.intent.action.BOOT_COMPLETED flg=0x9000010 cmp=com.android.updater/.BootCompletedReceiver (has extras) }]

  • 发生anr的时间点 am_anr: 进程pid:8769、进程名:com.android.updater、发生ANR的类型是:BroadcastTimeout、的具体类或者原因:{ act=android.intent.action.BOOT_COMPLETED flg=0x9000010 cmp=com.android.updater/.BootCompletedReceiver (has extras) }
  • 超时anr关键字
  • KeyDispatchTimeout-主要类型按键或触摸事件,input事件在5S内没有处理完成发生ANR
    日志关键字:Reason: Input dispatching timed out xxxx
  • ServiceTimeout-bind,create,start,unbind等在主线程处理耗时,前台Service在20s内,后台Service在200s内没有处理完成发生ANR
    日志关键字:Timeout executing service:/executing service XXX
  • BroadcastTimeout- BroadcastReceiver onReceiver处理事务时前台广播在10S内,后台广播在60s内没有处理完成发生ANR
    日志关键字:Timeout of broadcast XXX/Receiver during timeout:XXX/Broadcast of XXX
  • ProcessContentProviderPublishTimedOutLocked-ContentProvider publish在10s内没有处理完成发生ANR
    日志关键字:timeout publishing content providers
  • 造成ANR的常见原因

主线程耗时操作,如复杂的layout,庞大的for循环,IO等。
主线程被子线程同步锁block
主线程被Binder 对端block
Binder被占满导致主线程无法和SystemServer通信
得不到系统资源(CPU/Memory/IO)

bugreport

抓取方法:
adb shell bugreportz -p
/data/user_de/0/com.android.shell/files/bugreports/
hippo -l
hippo xx.zip meminfo
hippo xx.zip logs
hippo xx.zip events -m 3 //只显示最近 3 分钟的 events log

详细bugreport关键字,请参考bugreport关键字

Hprof

Zygote fork出来的process,如APP以及system_server,都会进行Java运行环境分析。其关键是分析Java Heap,以便快速知道某个Java变量的值,以及Java对象的分布和引用情况。
通常Java Heap的分析方式则是抓取Java Hprof,然后使用MAT等工具进行分析
抓取Hprof日志方法:

  • 方式一:使用am 命令

db shell am dumpheap {Process} file
adb shell am dumpheap com.android.phone /data/anr/phone.hprof
adb pull /data/anr/phone.hprof

  • 方式二:使用DDMS 命令

在DDMS中选择对应的process,然后在Devices按钮栏中选择Dump Hprof file,保存即可

  • 方式三:通过代码的方式

在android.os.Debug这个class 中有定义相关的抓取hprof 的method。
如: public static void dumpHprofData(String fileName) throwsIOException;
这样即可在代码中直接将这个process的hprof 保存到相对应的文件中,注意这个只能抓取当时的process。

快速分析

  1. DVM的Hprof 和标准的Java Hprof 有一些差别,需要使用hprof-conv进行一次转换,将DVM格式的hprof转换成标准的java 命令 hprof-conv in.hprof out.hprof
  2. 使用如MAT Tool,打开转换后的hprof文件

- Native层:
添加代码直接抓取
Google 默认提供了CallStack API,请参考
system/core/include/libutils/CallStack.h
system/core/libutils/CallStack.cpp
可快速打印单个线程的backtrace

自动抓取
Natice层的进程发生异常后一般都在/data/tombstones目录下生成文件
arm-linux-androideabi -addr2line-f -C -e symbols address

MTK工具
利用debuggerd抓取Native backtrace的tool RTT(Runtime Trace),对应的执行命令是:

USAGE : rtt[-h] -f function -p pid [-t tid]
-ffuncion : current support functions: bt (Backtrace function)
-ppid : pid to trace
-ttid : tid to trace
nname : process name to trace
-h : help menu

-Kernel层

  • AEE/RTT 工具
  • cat proc/pid/task/tid/stack
  • proc/kmsg
    adb shell cat proc/kmsg > kmsg.txt
    adb shell "echo 8 > proc/sys/kernel/printk“ //修改printk loglevel
    adb shell "echo t > /proc/sysrq-trigger“ //打印所有的backtrace
    adb shell "echo w > /proc/sysrq-trigger“//打印’-D’ status’D’的 process
  • 2
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值