jank检测工具原理和实现过程总结

背景

目前可以监控应用fps及jank数据的产品在用的有perfdog和itest;但perfdog已经开始收费,而itest无法监控到(3D)游戏的数据;
因此需要自研一款可以满足业务需求的jank数据检测工具。

业务需求

  • 数据监控范围:fps数据、jank数据、bigjank数据
  • 展示:图表形式实时展示数据、每秒截图在图表上显示
  • 操作:低门槛图形化操作
  • 实时性:数据秒级检测
  • 准确性:以perfdog为参考,数据尽量靠拢
  • 监控对象类型:普通应用+游戏

实现过程

帧数据获取方案选型

Choreographer.FrameCallback获取数据

原理

在 Android 系统中,实现绘制的类叫Choreographer;一次屏幕刷新完成后,将产生 VSync 信号并通知 Choreographer。
Choreographer 收到通知依次处理 Input、Animation、Draw,这三个过程都是通过 FrameCallback 回调的方式完成的。

而 FrameCallback#doFrame(long frameTimeNanos) 方法中可以得到 VSync 到来的时间戳,这样就能得到连续两帧开始渲染之间的间隔,将该值近似作为上一帧的渲染耗时。

实现 FrameCallback 接口,并通过 Choreographer#postFrameCallback() 方法将其跟 Input、Animation、Draw 这些回调一起塞入主线程的消息队列,就能源源不断的获取每一帧的渲染时间戳,每一个 VSync 的时间戳代表一帧,这样可以得到某段时间内渲染完成的帧数,二者相除即可得到帧率。

优点
  • 系统函数的方式获取值,起源于 Facebook 在 DroidCon 的分享,数据准确没有争议。
  • 基于该原理有已实现的开源工具fpsview
缺点
  • 该方案需要集成在项目源码内使用,存在使用门槛。
  • 因业务需求,部分指标需要靠拢perfdog,需要对fpsviewer进行二次开发。
  • 该方案为移动端方案,难以实现截图展示。

gfxinfo获取数据

原理

通过adb命令

adb shell dumpsys gfxinfo < PACKAGE_NAME > 

可以获取到android系统的最近127帧信息(各系统不同可能会有差异),类似如下样式:

         * 结果样式:
         * XXXX/XXXX.AAA/VVVV (visibility=0) 对应Activity
         * Draw     Prepare Process Execute
         * 7.31     5.07    6.63    0.99  
         * 50.00    21.64   44.89   6.06
         * 50.00    10.52   6.58    2.79
         * 20.21    2.36    6.78    2.51
         * 33.46    0.62    13.44   1.24
         * 10.30    0.21    6.07    1.55
         * 50.00    11.42   10.51   3.61
         * 0.84     7.79    15.48   32.71
         * 7.56     0.80    11.23   1.56
         * 46.13    2.58    7.29    1.16
         * 50.00    3.66    12.06   1.49
         * 12.26    0.31    5.29    0.84
         * 2.97     1.14    8.17    1.62
         * 6.26     0.84    9.47    2.72
         * ......
         */

Draw: 表示在Java中创建显示列表部分中,OnDraw()方法占用的时间;
Prepare: 准备时间;
Process: 表示渲染引擎执行显示列表所花的时间,view越多,时间就越长;
Execute: 表示把一帧数据发送到屏幕上排版显示实际花费的时间,其实是实际显示帧数据的后台缓存区与前台缓冲区交换后并将前台缓冲区的内容显示到屏幕上的时间。

将上面的四个时间加起来就是绘制一帧所需要的时间。

优点
  • Google官方接口,数据准确可信
  • 通过shell命令的形式获取数据,可扩展性强
缺点
  • 不支持surface view数据的获取

SurfaceFlinger获取数据

原理

通过adb命令

adb shell dumpsys SurfaceFlinger --latency < VIEW_NAME > 

可以获取到android系统的最近127帧信息(各系统不同可能会有差异),类似如下样式:

53476438728     53483331194     53476438728    
53774334579     53783331182     53774334579    
53804473320     53833331180     53804473320    
53821433876     53849997846     53821433876    
54482172942     54499997820     54482172942    
62828275267     62849997486     62828275267    
77744212604     77749996890     77744212604
137676463526    137683327826    137676463526
197665365491    197683325426    197665365491
257656215141    257666656360    257656215141
317667889815    317666653960    317667889815
377658368227    377666651560    377658368227
437659404105    437666649160    437659404105
497680028798    497683313426    497680028798
557661828695    557666644360    557661828695
617669142813    617683308626    617669142813
677664261743    677683306226    677664261743
...

第一列t1: when the app started to draw (开始绘制图像的瞬时时间);
第二列t2: the vsync immediately preceding SF submitting the frame to the h/w (VSYNC信令将软件SF帧传递给硬件HW之前的垂直同步时间),也就是对应上面所说的软件Vsync;
第三列t3: timestamp immediately after SF submitted that frame to the h/w (SF将帧传递给HW的瞬时时间,及完成绘制的瞬时时间)。

将第i行和第i-1行t2相减,即可得到第i帧的绘制耗时。

优点
  • 可获取view数据类型多,兼容游戏和视频场景
  • 通过shell命令的形式获取数据,可扩展性强
缺点
  • 多view时,需手动汇总数据
  • 数据统计口径和Google的gfxinfo存在差异,理论上gfxinfo的数据更正式

选型结论:SurfaceFlinger作为数据获取方案

综上各方案原理和优缺点,集合业务本身的应用场景(普通应用+游戏),符合全部业务需求的方案只有SurfaceFlinger;

以下工具开发实现过程将基于SurfaceFlinger方案描述。

帧数据加工处理

帧数据获取和处理流程

由于通过SurfaceFlinger方案获取的数据,如果在屏幕不动时,将始终获取到最后一次画面的值;因此,需要每间隔一段时间,执行一次clear操作,整体流程如下:

adb shell dumpsys SurfaceFlinger --latency-clear 执行数据清零 ------>
等待一秒,等待新数据生成 ------>
adb shell dumpsys SurfaceFlinger --latency < VIEW_NAME > 执行获取数据 ------>
计算数据,传输至前端展示 ------>
循环以上..

fps数据计算

每次执行dumpsys SurfaceFlinger --latency < VIEW_NAME > 后,计算汇总出一个fps;
计算规则为:

frame的总数N:127行中的非0行数
绘制的时间T:设t=当前行t2 - 上一行的t2,求出所有行的和∑t
fps=N/T

jank、bigjank数据计算

出于业务方要求,jank和bigjank采用腾讯PerfDog的计算方式:
PerfDog Jank计算方法:

    同时满足两条件,则认为是一次卡顿Jank.

    ①Display FrameTime>前三帧平均耗时2倍。

    ②Display FrameTime>两帧电影帧耗时 (1000ms/24*2≈83.33ms)。

    同时满足两条件,则认为是一次严重卡顿BigJank.

    ①Display FrameTime >前三帧平均耗时2倍。

    ②Display FrameTime >三帧电影帧耗时(1000ms/24*3=125ms)。  

多view数据聚合处理

在实际的数据获取过程中,发现一个应用会同时存在多个surfaceview和view;因此,如果只针对topactivity获取数据,并不能保证一定存在数据;在实际开发中,通过同时获取所有surfaceview&view的数据后进行数据聚合处理来规避这种问题。

具体的方式是:

  1. 通过adb shell dumpsys SurfaceFlinger | grep {packname}获取当前所有view添加进列表
  2. 循环该列表,获取所有view的帧数据
  3. 对每个view的帧数据进行处理,提取出fps、jank、bigjank数据
  4. 根据展示所有问题的原则,将所有view的jank和bigjank数据相加进行最终展示;将各view的fps相加(为0则不处理)取平均值后进行展示

数据展示实现

前端展示方案

整体前端展示以独立前端项目的形式,采用react实现,ui组件使用ant design,其中图表组件使用ant charts。

后端数据获取&处理方案

整体后端数据获取&处理以独立后端项目的形式,采用Django实现。

截图方案

由于原始的adb截图速度太慢,不满足需求,因此截图方案采用hook系统的函数实现;采用java编写,以jar包的形式放在sdcard目录下,通过

export CLASSPATH=/sdcard/shot.jar;exec app_process /sdcard Shot /sdcard/{shot_name}

的形式调用。

数据传输方案

数据传输分为两个方案:
一次性的数据沟通,如:获取设备信息、获取应用app列表、开始/结束测试等,使用http协议进行;
连续的数据传输,如:监控数据传输,出于性能考量,使用websocket进行。

项目本地化方案

由于Django+React的形式使用起来较为麻烦,需要各自进行服务部署;因此这里采用本地化包装的形式,具体流程如下:

  1. 将react项目build后,产物放置于Django项目下;这样前端项目可以免部署使用了;
  2. 将Django项目采用pyinstaller打包成可独立执行的windows程序;这样可以使用命令行在任一windows机器上无需部署直接启动Django;
  3. 采用pyqt编写项目启动器作为项目的启动入口,使用pyqt的web组件自动加载后端网址,实现一键启动。

项目展示

工具初始化界面

原始界面.png

工具选择应用界面

选择应用.png

工具录制和展示数据界面

录制界面.png

引用文档

Android屏幕刷新机制

Android屏幕刷新机制—VSync、Choreographer 全面理解

fpsviewer—实时显示fps,监控Android卡顿的可视化工具

android帧的绘制过程以及fps的获取

Android UI性能测试——使用 Gfxinfo 衡量性能

shell 脚本通过 dumpsys SurfaceFlinger --latency 数据计算 FPS 和评价流畅度

PerfDog客户端> Jank卡顿及stutter卡顿率说明

App性能测试揭秘(Android篇)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260