android帧率测试
① Android流畅度评估及卡顿优化
Google定义:界面呈现是指从应用生成帧并将其显示在屏幕上的动作。要确保用户能够流畅地与应用互动,应用呈现每帧的时间不应超过16ms,以达到每秒60帧的呈现速度(为什么是60fps?)。
如果应用存在界面呈现缓慢的问题,系统会不得不跳过一些帧,这会导致用户感觉应用不流畅,我们将这种情况称为卡顿。
来源于: Google Android的为什么是60fps?
16ms意味着1000/60hz,相当于60fps。这是因为人眼与大脑之间的协作无法感知超过60fps的画面更新。12fps大概类似手动快速翻动书籍的帧率, 这明显是可以感知到不够顺滑的。24fps使得人眼感知的是连续线性的运动,这其实是归功于运动模糊的效果。 24fps是电影胶圈通常使用的帧率,因为这个帧率已经足够支撑大部分电影画面需要表达的内容,同时能够最大的减少费用支出。 但是低于30fps是 无法顺畅表现绚丽的画面内容的,此时就需要用到60fps来达到想要的效果,超过60fps就没有必要了。如果我们的应用没有在16ms内完成屏幕刷新的全部逻辑操作,就会发生卡顿。
首先要了解Android显示1帧图像,所经历的完整过程。
如图所示,屏幕显示1帧图像需要经历5个步骤:
常见的丢帧情况: 渲染期间可能出现的情况,渲染大于16ms和小于16ms的情况:
上图中应该绘制 4 帧数据 , 但是实际上只绘制了 3 帧 , 实际帧率少了一帧
判断APP是否出现卡顿,我们从通用应用和游戏两个纬度的代表公司标准来看,即Google的Android vitals性能指标和地球第一游戏大厂腾讯的PrefDog性能指标。
以Google Vitals的卡顿描述为准,即呈现速度缓慢和帧冻结两个维度判断:
PerfDog Jank计算方法:
帧率FPS高并不能反映流畅或不卡顿。比如:FPS为50帧,前200ms渲染一帧,后800ms渲染49帧,虽然帧率50,但依然觉得非常卡顿。同时帧率FPS低,并不代表卡顿,比如无卡顿时均匀FPS为15帧。所以平均帧率FPS与卡顿无任何直接关系)
当了解卡顿的标准以及渲染原理之后,可以得出结论,只有丢帧情况才能准确判断是否卡顿。
mpsys 是一种在设备上运行并转储需要关注的系统服务状态信息的 Android 工具。通过向 mpsys 传递 gfxinfo 命令,可以提供 logcat 格式的输出,其中包含与录制阶段发生的动画帧相关的性能信息。
借助 Android 6.0(API 级别 23),该命令可将在整个进程生命周期中收集的帧数据的聚合分析输出到 logcat。例如:
这些总体统计信息可以得到期间的FPS、Jank比例、各类渲染异常数量统计。
命令 adb shell mpsys gfxinfo <PACKAGE_NAME> framestats 可提供最近120个帧中,渲染各阶段带有纳秒时间戳的帧时间信息。
关键参数说明:
通过gfxinfo输出的帧信息,通过定时reset和打印帧信息,可以得到FPS(帧数/打印间隔时间)、丢帧比例((janky_frames / total_frames_rendered)*100 %)、是否有帧冻结(帧耗时>700ms)。
根据第2部分的通用应用卡顿标准,可以通过丢帧比例和帧冻结数量,准确判断当前场景是否卡顿。并且通过定时截图,还可以根据截图定位卡顿的具体场景。
如上图所示,利用gfxinfo开发的检查卡顿的小工具,图中参数和卡顿说明如下:
根据上面对gfxinfo的帧信息解析,可以准确计算出每一帧的耗时。从而可以开发出满足腾讯PerfDog中关于普通卡顿和严重卡顿的判断。
依赖定时截图,即可准确定位卡顿场景。如下图所示(此处以PerfDog截图示例):
通过第3部分的卡顿评估方法,我们可以定位到卡顿场景,但是如何定位到具体卡顿原因呢。
首先了解卡顿问题定位工具,然后再了解常见的卡顿原因,即可通过复现卡顿场景的同时,用工具去定位具体卡顿问题。
重点就是,充分利用gfxinfo输出的帧信息,对卡顿问题进行分类。
了解了高效定位卡顿的方法和卡顿问题定位工具,再熟悉一下常见的卡顿原因,可以更熟练的定位和优化卡顿。
SurfaceFlinger 负责 Surface 的合成,一旦 SurfaceFlinger 主线程调用超时,就会产生掉帧。
SurfaceFlinger 主线程耗时会也会导致 hwc service 和 crtc 不能及时完成,也会阻塞应用的 binder 调用,如 dequeueBuffer、queueBuffer 等。
后台进程活动太多,会导致系统非常繁忙,cpu io memory 等资源都会被占用,这时候很容易出现卡顿问题,这也是系统这边经常会碰到的问题。
mpsys cpuinfo 可以查看一段时间内 cpu 的使用情况:
当线程为 Runnable 状态的时候,调度器如果迟迟不能对齐进行调度,那么就会产生长时间的 Runnable 线程状态,导致错过 Vsync 而产生流畅性问题。
system_server 的 AMS 锁和 WMS 锁 , 在系统异常的情况下 , 会变得非常严重 , 如下图所示 , 许多系统的关键任务都被阻塞 , 等待锁的释放 , 这时候如果有 App 发来的 Binder 请求带锁 , 那么也会进入等待状态 , 这时候 App 就会产生性能问题 ; 如果此时做 Window 动画 , 那么 system_server 的这些锁也会导致窗口动画卡顿。
Android P 修改了 Layer 的计算方法 , 把这部分放到了 SurfaceFlinger 主线程去执行, 如果后台 Layer 过多,就会导致 SurfaceFlinger 在执行 rebuildLayerStacks 的时候耗时 , 导致 SurfaceFlinger 主线程执行时间过长。
主线程执行 Input Animation Measure Layout Draw decodeBitmap 等操作超时都会导致卡顿 。
Activity resume 的时候, 与 AMS 通信要持有 AMS 锁, 这时候如果碰到后台比较繁忙的时候, 等锁操作就会比较耗时, 导致部分场景因为这个卡顿, 比如多任务手势操作。
应用里面涉及到 WebView 的时候, 如果页面比较复杂, WebView 的性能就会比较差, 从而造成卡顿。
如果屏幕帧率和系统的 fps 不相符 , 那么有可能会导致画面不是那么顺畅. 比如使用 90 Hz 的屏幕搭配 60 fps 的动画。
由上面的分析可知对象分配、垃圾回收(GC)、线程调度以及Binder调用 是Android系统中常见的卡顿原因,因此卡顿优化主要以下几种方法,更多的要结合具体的应用来进行:
在计算机和通信领域,帧是一个包括“帧同步串行”的数字数据传输单元或数字数据包。
在视频领域,电影、电视、数字视频等可视为随时间连续变换的许多张画面,其中帧是指每一张画面。
② 如何测量Android应用的帧率FPS
方法如下:
1.打开网络浏览器,在输入栏里输入gltools,并点击下载安装。
③ Android性能测试(内存、cpu、fps、流量、GPU、电量)——adb篇
3)查看进程列表:adb shell "ps",同时也能获取到应用的UID,方式如下(不需root权限):
u0_a开头的都是Android的应用进程,Android的应用的UID是从10000开始,到19999结束,可以在Process.java中查看到(FIRST_APPLICATION_UID和LAST_APPLICATION_UID),u0_a后面的数字就是该应用的UID值减去FIRST_APPLICATION_UID所得的值,所以,对于截图这个应用进程,它是u0_a155,按前面的规制,它的UID就是155 + FIRST_APPLICATION_UID = 10155。
VSS - Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS - Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS - Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS - Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
使用 adb shell "mpsys meminfo -s <pakagename | pid>"命令,输出结果分以下4部分:
PS:在apk内调用运行获取其他app的内存数据则需要root权限
adb命令:adb shell mpsys gfxinfo <package | pid>
正常情况下帧率应该在16.67ms左右,1秒60帧,执行结果如下:
详细计算方法如下:
还有一个命令是: adb shell mpsys SurfaceFlinger --latency LayerName
其中LayerName在各个不同系统中获取的命令是不一样的
在Android 6系统直接就是SurfaceView
在Android 7系统中可以通过 mpsys window windows | grep mSurface | grep SurfaceView 然后通过数据截取到
在Android 8系统中可以通过 mpsys SurfaceFlinger | grep android包名获取到
执行命令结果如下:
计算方法比较简单,一般打印出来的数据是129行(部分机型打印两次257行,但是第一部分是无效数据,取后半部分),取len-2的第一列数据为end_time,取len-128的第一列数据为start_time
fps = 127/((end_time - start_time) / 1000000.0)
至于为啥要取第一列数据,这里不做过多介绍,欢迎参看这两篇文章
老罗的文章SurfaceView原理
Android性能测试之fps获取
至于为啥要处于1000000,因为命令打印出来的是纳秒单位,要转为毫秒进行计算,127就是因为命令一次打印出来127帧的数据而已
有两种方法可以获取
1) adb shell "top -n 5 | grep <package | pid>" ,第三列就是实时监控的CPU占用率(-n 指定执行次数,不需root权限),这边top命令执行需要2到3s左右,一般可以采用busybox 的top命令执行,效率会快很多
2) adb shell "mpsys cpuinfo | grep <package | pid>"
两种方法直接区别在于,top是持续监控状态,而mpsys cpuinfo获取的实时CPU占用率数据
adb命令:adb shell "mpsys batterystats < package | pid>" (Android 5.0后引入)
获取单个应用的耗电量信息,具体返回结果待研究
adb命令:adb shell "mpsys battery"
出现信息解读:
AC powered:false 是否连接AC(电源)充电线
USB powered:true 是否连接USB(PC或笔记本USB插口)充电
Wireless powered:false 是否使用了无线电源
status: 1 电池状态,2为充电状态,其他为非充电状态
level:58 电量(%)
scale: 100. 电量最大数值
voltage: 3977 当前电压(mV)
current now: -335232. 当前电流(mA)
temperature:355 电池温度,单位为0.1摄氏度
adb 命令:adb shell "mpsys< package | pid> | grep UID" [通过ps命令,获取app的UID(安装后唯一且固定)]
adb shell cat /proc/uid_stat/UID/tcp_rcv [cat为查看命令,读取tcp_rcv获取应用接收流量信息(设备重启后清零)]
adb shell cat /proc/uid_stat/UID/tcp_snd [cat为查看命令,读取tcp_snd获取应用发送流量信息(设备重启后清零)]
计算流量消耗步骤:
或者还有一种方式获取应用流量消耗:
首先判断类型:
cat /sys/class/thermal/thermal_zone*/type
只有红框框出来的是有效的
cat /sys/class/thermal/thermal_zone*/temp
获取CPU温度
mpsys battery | grep temperature 单位0.1摄氏度
获取/proc/stat文件内容(无权限限制)
总的cpu时间片是 total = user+nice+system+idle+iowait+irq+softirq
忙碌时间为 notidle = user+nice+system +iowait+irq+softirq
cpu使用率计算方法为,先取开始的total值和忙碌时间notidle,隔一段时间片,再取一次计算total2,notidle2, cpuuse = (notidle2 – notidle) * 100 / (total2 - total)%
PS:由于Android 8权限收紧,在Android 8系统手机内apk内读取文件内容为空,需要shell权限才可获取文件内容,下同
读/sys/devices/system/cpu/cpuX/cpufreq/scaling_cur_freq文件的值,X不定,看是几核手机,scaling_cur_freq是否存在也不一定,需要判断
至于为啥不取cpuinfo_cur_freq文件的值,原因是android 6,7系统获取的时候,这个文件shell没有读取权限,需要root权限
参考文章: https://blog.csdn.net/long_meng/article/details/45934899
Android 6,7系统可执行
mpsys window windows | grep "mCurrentFocus"
执行结果一般为类似:
mCurrentFocus=Window{81caaa5 u0 com.tencent.mobileqq/com.tencent.mobileqq.activity.SplashActivity}
按照一定规则把com.tencent.mobileqq提取出来即可
直接apk内读取文件即可,不需要shell权限(支持到Android8)
Gpu使用率获取:会得到两个值,(前一个/后一个)*100%=使用率
adb shell cat /sys/class/kgsl/kgsl-3d0/gpubusy
Gpu工作频率:
adb shell cat /sys/class/kgsl/kgsl-3d0/gpuclk
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/cur_freq
Gpu最大、最小工作频率:
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/min_freq
Gpu可用频率
adb shell cat /sys/class/kgsl/kgsl-3d0/gpu_available_frequencies
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/available_frequencies
Gpu可用工作模式:
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/available_governors
Gpu当前工作模式:
adb shell cat /sys/class/kgsl/kgsl-3d0/devfreq/governor
④ APP性能测试(1):FPS测试
adb 计算帧率: https://zhuanlan.hu.com/p/67056913
adb 计算帧率: https://www.huaweicloud.com/articles/12566219.html
帧率:FPS是图像领域中的定义,是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数。30FPS是一般录像的常用帧数,30FPS在快速动作的时候会感觉不流畅。60FPS是一般游戏的常用帧数。
绝大部分时间两者(Android和IOS)都能保持60FPS左右的满帧率。但都会有偶尔的掉帧。并且Android上要比IOS上严重很多。掉帧导致卡顿,用户必然会感觉到掉帧那一刻的不流畅。
FPS是图像领域中的定义,是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数。FPS是测量用于保存、显示动态视频的信息数量。每秒钟帧数愈多,所显示的动作就会愈流畅一般来说,Android设备的屏幕刷新率为 60帧/s ,要保持画面流畅不卡顿,要求每一帧的时间不超过 1000/60=16.6ms ,这就是16ms的黄金准则,如果中间的某些帧的渲染时间超过16ms,就会导致这段时间的画面发生了跳帧,因此原本流畅的画面变发生了卡顿。
FPS 通常作为衡量应用是否流畅的标准。
FPS 即 Frames per Second(每秒显示的帧数),用于测量显示帧数的度量。帧数为 0 说明页面处于静止,只要页面动起来,这个帧数就会有变化,然后再趋于静止,页面滚动起来帧数整体呈现 “非对称” 抛物线走势。接下来看一张图直观感受一下:
通过上图我们能看出 FPS 值的大小对画面流畅度的影响,每一帧都是静止的图像,快速连续地显示帧便形成了运动的假象,因此高帧率可以得到更流畅、更逼真的动画。
帧延迟的高低可以通过帧时间(Frame Time)来判定。我们参考显示器的 60Hz 刷新率进行计算,它意味着每秒刷新 60 帧,每帧大约用时 16.7 毫秒。画面中每帧生成时间如果与 16.7 毫秒很接近,那么全程画面的帧数就很稳定,更接近理想的 60 帧每秒。
如果每帧生成时间高于 16.7 毫秒,也就意味着渲染这一场景所花费的时间比其他帧更多,造成画面跟不上,进而带来显示卡顿。
手机的 CPU 处理速率、屏幕尺寸、内存及显存的大小都影响着 APP 帧率的大小,这些因素在一定程度上约束着准备数据和数据传到屏幕的时间。再者,GUI 软件架构在一定程度上也影响着应用帧率的大小。
在同等机器环境下,除去 CPU、屏幕尺寸及系统 GUI 等固有数据传输耗时,要提升应用 FPS 就要减少视图渲染的时间。
1、尽量不要在刷新时做耗时操作,例如准备数据,创建图片,图片变换等,数据和图片都应该在之前就加载到内存中,图片变换用 canvas 的变换来实现。
2、同一个界面中多个动画重叠出现时,尽量将动画的刷新过程统一刷新,避免频繁的 invalidate,尤其是多个动画有时序上的关系时更应该统一。
3、尽量使用带有参数的 invalidate 来刷新,这样可以减少很多运算量。
APP也需要关注FPS、Jank及卡顿率。只是需要区分使用场景,如:
只需关注FPS,理论FPS应该为0,否则,说明有冗余刷新,容易引起手机发热及耗电。
只需关注FPS,FPS处于合适值即可,无需高频刷新。
需要关注FPS、Jank及卡顿率。手机交互灵敏度就是来源于此,Android系统才出黄油计划Jank。一般滑动状态下,帧率越高越好,Jank越小越好。
需要关注FPS、Jank及卡顿率,视频卡顿直接影响用户。视频一般帧率18-24帧,Jank=0。比如微信播放视频、视频播放器等。
注:
引用来源
⑤ 如何测量Android应用的帧率FPS
测量Android应用的帧率FPS的方法如下:
首先打开设置,进行如下操作(“设置”->"开发者选项",然后勾选“GPU显示配置文件”),以打开GPU呈现模式分析。如图:
⑥ 如何测量android应用的帧率fps和统计
Android应用的帧率FPS是衡量应用流畅度的一个非常重要的指标,可以根据FPS对应用做一些优化,那么在开发过程中如何来测量我们的应用的FPS呢?
工具/原料
Eclipse
三星GT-P3110
在设置里打开GPU呈现模式分析。点击Android设备的“设置”->"开发者选项",然后勾选“GPU显示配置文件”。
从图中可以看出来,我这个应用的流畅度是很低的,正常情况下帧率应该在16ms左右,如果1秒60帧的话,而且Execute时间太长!所以是需要进行优化的。
是不是很简单,如果觉得有用,请为小编投上支持的一票,小编会继续努力谢谢你的支持哦。
方法/步骤
⑦ 如何测量Android应用的帧率FPS
通过 [设置]->[开发者选项]->[GPU呈现模式分析] ->[在屏幕上显示为条形图] 进行直观的取样,截图如下:
绘制过程中的不同颜色具有不同的含义,详细解释请移步>> 官网查看更多。
那么是不是说我只需要打开界面去数一下超过绿色阈值的柱状图有多少就可以观察我们应用的流畅度了?然而并没有,因为这个方式获取到的渲染时间只是UI主线程上的绘制行为,目前我所接手的项目,采用的方式是捕捉相机的数据然后放到GPU中去进行绘制,有单独的绘制线程,单独的视图,所以这个方案并不适合我手上的项目。