关于 android 通过 python 统计 fps

本文介绍了一种使用Python脚本配合第三方库统计Android设备上应用FPS的方法。通过调用adb命令并利用SurfaceFlinger组件获取帧率数据,该脚本能够帮助开发者分析应用性能,并提供了一个简单的例子来演示如何计算平均FPS。

用了这个第三方库
https://github.com/ChromiumWebApps/chromium/tree/master/build/android/pylib

然后如下代码:

<span class="c"># -*- coding: utf8 -*-</span>
<span class="kn">import</span> <span class="nn">os</span><span class="o">,</span> <span class="nn">time</span><span class="c">#, sys</span>
<span class="kn">from</span> <span class="nn">pylib</span> <span class="kn">import</span> <span class="n">android_commands</span><span class="p">,</span> <span class="n">surface_stats_collector</span>

<span class="n">resultList</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">deviceText</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">popen</span><span class="p">(</span><span class="s">'adb devices'</span><span class="p">)</span>
<span class="n">textList</span> <span class="o">=</span> <span class="n">deviceText</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span>
<span class="n">deviceName</span> <span class="o">=</span> <span class="n">textList</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">adb</span> <span class="o">=</span> <span class="n">android_commands</span><span class="o">.</span><span class="n">AndroidCommands</span><span class="p">(</span><span class="n">deviceName</span><span class="p">)</span>
<span class="n">collector</span> <span class="o">=</span> <span class="n">surface_stats_collector</span><span class="o">.</span><span class="n">SurfaceStatsCollector</span><span class="p">(</span><span class="n">adb</span><span class="p">,</span> <span class="n">activityName</span><span class="p">,</span><span class="mf">0.5</span><span class="p">)</span>
<span class="n">collector</span><span class="o">.</span><span class="n">DisableWarningAboutEmptyData</span><span class="p">()</span>
<span class="n">collector</span><span class="o">.</span><span class="n">Start</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">50</span><span class="p">):</span>    <span class="c">#循环50次,主要方便自己的实现,其他实现方法请另行实现;</span>
    <span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.3</span><span class="p">)</span>
    <span class="n">results</span> <span class="o">=</span> <span class="n">collector</span><span class="o">.</span><span class="n">SampleResults</span><span class="p">()</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">results</span><span class="p">:</span>
        <span class="k">pass</span>
    <span class="k">else</span><span class="p">:</span> 
        <span class="n">resultList</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span><span class="p">))</span>
        <span class="n">results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">print_str</span><span class="p">()</span>
<span class="n">collector</span><span class="o">.</span><span class="n">Stop</span><span class="p">()</span>
<span class="n">a</span> <span class="o">=</span> <span class="n">resultList</span><span class="p">[</span><span class="mi">3</span><span class="p">:</span><span class="o">-</span><span class="mi">3</span><span class="p">]</span>
<span class="k">print</span> <span class="s">u"平均值:"</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="nb">float</span><span class="p">(</span><span class="nb">sum</span><span class="p">(</span><span class="n">a</span><span class="p">)</span><span class="o">/</span><span class="nb">len</span><span class="p">(</span><span class="n">a</span><span class="p">)))</span><span class="o">+</span><span class="s">u" ; 最小值:"</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="nb">min</span><span class="p">(</span><span class="n">a</span><span class="p">))</span>

代码写得不怎的,请无视。

运行上述脚本,在对应的activity操作,即可统计当前操作的fps值了。

跑一边看看:

看库的源码,原理是使用"adb shell dumpsys SurfaceFlinger --latency <window name>"进行循环统计实现的。

代码中有如下注释:

<span class="k">def</span> <span class="nf">_GetSurfaceFlingerFrameData</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="s">"""Returns collected SurfaceFlinger frame timing data.

    Returns:
      A tuple containing:
      - The display's nominal refresh period in seconds.
      - A list of timestamps signifying frame presentation times in seconds.
      The return value may be (None, None) if there was no data collected (for
      example, if the app was closed before the collector thread has finished).
    """</span>
    <span class="c"># adb shell dumpsys SurfaceFlinger --latency <window name></span>
    <span class="c"># prints some information about the last 128 frames displayed in</span>
    <span class="c"># that window.</span>
    <span class="c"># The data returned looks like this:</span>
    <span class="c"># 16954612</span>
    <span class="c"># 7657467895508   7657482691352   7657493499756</span>
    <span class="c"># 7657484466553   7657499645964   7657511077881</span>
    <span class="c"># 7657500793457   7657516600576   7657527404785</span>
    <span class="c"># (...)</span>
    <span class="c">#</span>
    <span class="c"># The first line is the refresh period (here 16.95 ms), it is followed</span>
    <span class="c"># by 128 lines w/ 3 timestamps in nanosecond each:</span>
    <span class="c"># A) when the app started to draw</span>
    <span class="c"># B) the vsync immediately preceding SF submitting the frame to the h/w</span>
    <span class="c"># C) timestamp immediately after SF submitted that frame to the h/w</span>
    <span class="c">#</span>
    <span class="c"># The difference between the 1st and 3rd timestamp is the frame-latency.</span>
    <span class="c"># An interesting data is when the frame latency crosses a refresh period</span>
    <span class="c"># boundary, this can be calculated this way:</span>
    <span class="c">#</span>
    <span class="c"># ceil((C - A) / refresh-period)</span>
    <span class="c">#</span>
    <span class="c"># (each time the number above changes, we have a "jank").</span>
    <span class="c"># If this happens a lot during an animation, the animation appears</span>
    <span class="c"># janky, even if it runs at 60 fps in average.</span>
    <span class="c">#</span>
    <span class="c"># We use the special "SurfaceView" window name because the statistics for</span>
    <span class="c"># the activity's main window are not updated when the main web content is</span>
    <span class="c"># composited into a SurfaceView.</span>
    <span class="n">results</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_adb</span><span class="o">.</span><span class="n">RunShellCommand</span><span class="p">(</span><span class="s">'dumpsys SurfaceFlinger --latency '</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">_activity</span><span class="p">)</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nb">len</span><span class="p">(</span><span class="n">results</span><span class="p">):</span>
      <span class="k">return</span> <span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span>

英语烂,脑容量有限,一直看不明白,有大神帮帮忙解析一下哈(原谅我伸手党)。



 =================================================以下是回复帖=================================================================

1.

循环50次, 间隔0.3s, 得到50个数据。然后掐头去尾, 计算下平均值。好像是大概10s内的fps平均值。
adb shell dumpsys SurfaceFlinger 本身能打印出fps 里面会有更细致的帧数计算数据。细节我也了解的不太多。

surface_stats_collector.SurfaceStatsCollector函数里面应该有你想要的逻辑。 你可以帖一下欣赏下。

2.

一般某个过程发生了丢帧, 是在几秒内的, 10s有点太长, 不过还可以接受. 大部分的卡顿都在2s以上. 10s内平均也能差不多通过平均值看出来.

Android 开发中,查看应用的率(FPS)是性能优化的重要一环。Android Studio 提供了多种工具和方式来帮助开发者实时监测应用的率表现。 ### 使用 Android Studio 的 Profiler 工具 Android Studio 自带的 **Profiler** 工具可以实时查看 CPU、内存、网络和能耗的使用情况,同时也支持查看率信息。 #### 步骤如下: 1. 运行应用后,在 Android Studio 底部点击 **Profiler** 标签。 2. 选择连接的设备和运行的应用进程。 3. 在 CPU 部分,点击“**Record**”按钮开始记录 CPU 活动。 4. 在记录期间,可以观察到的执行时间,每的耗时越接近 16ms(即 60FPS),说明率越稳定。 5. 通过分析主线程的执行堆栈,可以定位卡顿的具体原因。 ```java // Profiler 工具无法直接显示 FPS 数值,但可以通过 CPU Profiling 查看每的执行时间。 // 例如,以下代码可以用于插入自定义标记以辅助分析: Trace.beginSection("CustomFrameMarker"); // 执行某些绘制或计算逻辑 Trace.endSection(); ``` ### 使用 adb 命令查看率 通过命令行工具 `adb` 可以使用以下命令来获取率数据: ```bash adb shell dumpsys gfxinfo <package_name> ``` 该命令会输出应用的图形渲染信息,包括最近 120 的绘制时间。通过这些数据可以估算出率表现。重点关注输出中的 **View hierarchy** 和 **Profile data in ms** 部分。 如果需要持续监测率,可以使用: ```bash adb shell service call SurfaceFlinger 1002 ``` 此命令需要设备具有 root 权限,并且在部分设备上可能不适用。它会返回当前屏幕刷新率或应用率信息。 ### 使用第三方库或工具 一些第三方性能监控库(如 [Emmagee](https://github.com/Netease/Emmagee) 或 [FPSMonitor](https://github.com/friendlyrobotnz/FPSMonitor))可以集成到应用中,用于实时显示率信息。这些库通常通过在主线程中插入计时逻辑,统计每秒绘制的数,并在屏幕上显示 FPS 数值。 例如,使用 FPSMonitor 的集成方式: ```gradle implementation 'nz.co.fortytwo:fpsmonitor:1.0.0' ``` 在 `Application` 类或 `MainActivity` 中启用监控: ```java FPSMonitor.start(this); ``` ### 使用 Systrace 进行深度分析 Systrace 是 Android 提供的系统级性能分析工具,可以追踪应用与系统资源的交互情况,包括的渲染路径。 运行 Systrace 的命令如下: ```bash python -m systrace --time=10 --app=<package_name> --viewers=chart ``` 该命令将记录 10 秒的应用运行轨迹,并生成 HTML 报告。在报告中可以查看每的渲染时间,并分析是否出现现象。 ### 总结 Android 提供了多种方式来查看率(FPS),从 Android Studio 的 Profiler 到 adb 命令,再到第三方库和 Systrace 工具,开发者可以根据需求选择适合的工具进行性能分析。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值