android-cn / android-discuss

Android 问题交流讨论坛, 微信公众号:codekk, 网站:
https://github.com/android-cn/android-discuss/issues
Apache License 2.0
4.08k stars 536 forks source link

[问答]如何获取android程序流畅度(SM: SMoothness) #236

Open inexistence opened 9 years ago

inexistence commented 9 years ago

《如何量化Android应用的“卡”?—流畅度原理&定义篇》一文中,提到了

可以在Choreographer的回调FrameCallback中,按秒计数表示当前App的流畅程度,即流畅度SM(SMoothness)。

没大理解这里具体是怎么实现的,求教。

harryhappy commented 8 years ago

反编译他们看了一眼,监听系统log实现的。代码里有句log

do much thing in main thread 巴拉巴拉的 不太靠谱,尝试写了一下 似乎不太好用

LLin233 commented 8 years ago

每一帧渲染的时候log一次, 然后算下fps吧

Harry notifications@github.com于2015年12月15日周二 下午6:14写道: 反编译他们看了一眼,监听系统log实现的。代码里有句log

do much thing in main thread 巴拉巴拉的 不太靠谱,尝试写了一下 似乎不太好用

— Reply to this email directly or view it on GitHub .

harryhappy commented 8 years ago

@LLin233 仔细看了一下,上面写的是文章里提到的另外一个概念“丢帧”数。 监听 Choreographer 中 doFrame()中的一句log Log.i(TAG, "Skipped " + skippedFrames + " frames! " + "The application may be doing too much work on its main thread."); http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.0.2_r1/android/view/Choreographer.java?av=f 还是不知道SM: SMoothness这个值是怎么实现的

harryhappy commented 8 years ago

反编译了,代码里主要有两个service: SMLogService SMDataService

SMLogService 比较清晰就是在监听log, SMDataService 看不懂在搞什么啊 大家一起看看 通过监听log获取丢帧数的那个地方比较清晰,SM获取还是不清晰 dex2jar 反编译的好像有丢失信息,大家一起看看smali

yoomaz commented 8 years ago

Choreographer 的api里这样描述这个类的 :Each Looper thread has its own choreographer ,但是我只能打出一个log的数值,难道是因为16ms一此,太快了log打印不出来》

xiaosongluo commented 8 years ago

SM(Smooth,流畅度)、SF(SkippedFrame,跳帧)

基础数据来源背景: 从Android 4.1(版本代号为Jelly Bean)开始,Android OS开发团队便引入了三个核心元素,即VSYNC、Triple Buffer和Choreographer力图解决严重影响Android口碑问题之一的UI流畅性差的问题。 而其中,Choreographer的主要功能是,当收到VSYNC信号时,在doFrame()里去调用使用者通过postCallback设置的回调函数。目前一共定义了三种类型的回调,它们分别是: CALLBACK_INPUT:优先级最高,和输入事件处理有关。 CALLBACK_ANIMATION:优先级其次,和Animation的处理有关。 CALLBACK_TRAVERSAL:优先级最低,和UI等控件绘制有关。这个函数里面主要是检查当前窗口当前状态,比如说是否依然可见,尺寸,方向,布局是否发生改变(可能是由前面的用户输入触发的),分别调用performMeasure(), performLayout(), performDraw()来完成测量,布局和绘制工作。 由于VSYNC信号每16.6ms产生一次(具体时间依据系统实现),因此理想情况下每秒可执行绘制相关操作60次。但实际情况是,CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL中任意一个节点都有可能因为存在耗时操作而导致doFrame()无法在16.6ms内完成,从而无法在接下来的VSYNC信号到达时进行处理。 因此,SM(Smooth,流畅度)、SF(SkippedFrame,跳帧均选用Choreographer中doFrame()实际执行的次数作为基础数据。

指标计算方法: SF(SkippedFrame,跳帧),即为某个应用程序在单位时间1秒内,跳过执行Choreographer中doFrame()的次数。 SM(Smooth,流畅度),即为某个应用程序在单位时间1秒内,实际执行Choreographer中doFrame()的次数。在获取SF数值的基础上,SM=60-SF。 连续跳帧,与SF的不同在于,它将跳帧按其连续跳帧数进行统计,用以衡量单位时间内的卡顿程度。

指标获取方式: 相关源码:http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/view/Choreographer.java#Choreographer.doFrame%28long%2Cint%29

void More ...doFrame(long frameTimeNanos, int frame) { 510 final long startNanos; 511 synchronized (mLock) { 512 if (!mFrameScheduled) { 513 return; // no work to do 514 } 515 516 startNanos = System.nanoTime(); 517 final long jitterNanos = startNanos - frameTimeNanos; 518 if (jitterNanos >= mFrameIntervalNanos) { 519 final long skippedFrames = jitterNanos / mFrameIntervalNanos; 520 if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { 521 Log.i(TAG, "Skipped " + skippedFrames + " frames! " 522 + "The application may be doing too much work on its main thread."); 523 } 524 final long lastFrameOffset = jitterNanos % mFrameIntervalNanos; 525 if (DEBUG) { 526 Log.d(TAG, "Missed vsync by " + (jitterNanos * 0.000001f) + " ms " 527 + "which is more than the frame interval of " 528 + (mFrameIntervalNanos * 0.000001f) + " ms! " 529 + "Skipping " + skippedFrames + " frames and setting frame " 530 + "time to " + (lastFrameOffset * 0.000001f) + " ms in the past."); 531 } 532 frameTimeNanos = startNanos - lastFrameOffset; 533 } 534 535 if (frameTimeNanos < mLastFrameTimeNanos) { 536 if (DEBUG) { 537 Log.d(TAG, "Frame time appears to be going backwards. May be due to a " 538 + "previously skipped frame. Waiting for next vsync."); 539 } 540 scheduleVsyncLocked(); 541 return; 542 } 543 544 mFrameScheduled = false; 545 mLastFrameTimeNanos = frameTimeNanos; 546 }

SF(SkippedFrame,跳帧),注:SM(Smooth,流畅度)的获取方式基于SF(SkippedFrame,跳帧)的获取,SM=60-SF 通过注入的方式,获取skippedFrames的数值,并进行处理,通过GT测试工具实现。

xiaosongluo commented 8 years ago

GT工具的开源的地址:https://github.com/TencentOpen/GT

harryhappy commented 8 years ago

https://github.com/TencentOpen/GT 哦哦哦 开源了啊 研究下源码吧。