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

目录

前言:

开篇前述:

一、设计初衷

二、设定预期倒推查找解决方案

设计实现部分

一、确定数据来源原因(dumpsys SurfaceFlinger --latency)

二、根据需求确定计算规则

三、代码实现

四、监控数据可视化交互结果设计


前言:

在 Android App 的持续集成测试中,流畅度是一个非常重要的指标,它表示应用程序的运行流畅程度。流畅度的评价通常可以通过监控应用程序的 CPU、内存、GPU 等资源的使用情况来进行评价。 

开篇前述:

由于采购机械臂测试性能用例和屏幕实际帧率变化,最终工具方案实现后搁置,拿出来” 晒晒 “。

一、设计初衷

1、面临用户和公司内领导试用中反馈的卡顿问题,思考如何能有效量化评估?
2、如何在尝试复现卡顿的过程中持续监控 FPS 和丢帧情况?

二、设定预期倒推查找解决方案

1、无 root 权限限制,可直接采集数据计算 FPS、丢帧率、最大单帧间隔。
2、控制脚本影响,不要使监控脚本成为 “负担”。
3、数据获取灵活,即可控制台实时输出数据,也可以后台长时间监控。
4、设计评价得分标准,可按:百分比 * 用例单项评分量化每条用例,从而计算总分使用。

设计实现部分

参考了网上现有的 FPS 计算方式原理,绕来绕去也没有满足自己的预期需求,索性自己从数据源出发自己设计脚本计算逻辑处理。参考如下​
用第三方库 (surface_stats_collector.py) 获取 AndroidFPS 过程分析 (用第三方库 (surface_stats_collector.py) 获取 AndroidFPS 过程分析 · TesterHome)
如何准确评测 Android 应用的流畅度? (http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=75&extra=page%3D1)

一、确定数据来源原因(dumpsys SurfaceFlinger --latency)

1、可以清零重新记录,避免如何分清哪些数据是上次的。(dumpsys SurfaceFlinger --latency-clear)
2、按 window 获取数据,可以配合手工操作逐一获取每个 case 的流畅度。
3、历史记录 127 行数据,按 60 帧算可记录 2.12S 数据,从而不用频繁获取。(最终考虑设定 1.6S 间隔刷新数据。)

二、根据需求确定计算规则

1、有刷新则计算帧率,无刷新则不输出数据。
原因:
(1)要做成监控指定窗口流畅度的功能,所以要控制无意义数据。
(2)配合手工操作,静置状态不输出,操作停止后直接刷新数据,从而使数据和操作对应。
2、间隔 500ms 以上则判定为操作延迟,每到间隔 500ms 情况发生重新计算帧率。
原因:
(1)一般做 monkey 压力测试设置的是 500ms 间隔
(2)一般用户操作频率间隔是大于 500ms 情况
3、每次采样数据大于等于 1 帧则计算 FPS,丢帧率,最大帧间隔。
原因:帧数/总耗时=帧率,所以无论有多少帧都可以直接计算
4、设定流畅度评价规则:
(1)满足 KPI 帧率则达成一半需求,占比 50%
(2)小于 KPI 单帧耗时比例评价画面变化是否稳定,占比 40%
(3)单帧渲染峰值代表瞬时卡顿最大影响,占比 10%
5、代码实现过程中遇到一坑:SurfaceFlinger 中同一帧存在间隔复用情况,即相同一行数据间隔几帧出现两次。(通过监控微信红包点击后的弹出框的帧率发现的。)
补充规则:发生两帧同步时间做差小于第一行帧刷新周期,则总时间 + 帧刷新周期,上一帧数据=前一帧同步时间 + 帧刷新周期,总帧数 +1

三、代码实现

#!/system/bin/sh

show_help() {
echo "
Usage: sh fps.sh [ -t target_FPS ] [ -w monitor_window ] [ -k KPI ] [ -f csv_path ] [ -h ]

Show: FU(s) LU(s) Date FPS Frames jank MFS(ms) OKT SS(%)

    FU(s): Uptime of the first frame.
    LU(s): Uptime of the last frame.
    Date: The date and time of LU.
    FPS: Frames Per Second.
    Frames: All frames of a loop.
    jank: When the frame latency crosses a refresh period, jank is added one.
    MFS(ms): Max Frame Spacing.
    OKT: Over KPI Times. The KPI is the used time of one frame.
    SS(%): Smoothness Score. SS=(FPS/target FPS)*60+(KPI/MFS)*20+(1-OKPIT/Frames)*20
           IF FPS > target FPS: FPS/The target FPS=1
           IF KPI > MFS: KPI/MFS=1
    WN: the window number of same name's window. Eg. SurfaceView

POSIX options | GNU long options

    -t   | --target         The target FPS of the choosed window. Default: 60
    -w   | --window         The choosed window. Default: no window.
    -k   | --KPI            The used time of a frame. Default: KPI=1000/The target FPS.
    -f   | --file           The path of the csv file. Default: output result to console.
    -h   | --help           Display this help and exit
"
}

file=""
window=""
target=60
KPI=16
while :
do
    case $1 in
        -h | --help)
            show_help
            exit 0
            ;;
        -t | --target)
            shift
            target=$1
            KPI=$((1000/$1))
            shift
            ;;
        -w | --window)
            shift
            window="$1"
            shift
            ;;
        -k | --KPI)
            shift
            KPI=$1
            shift
            ;;
        -f | --file)
            shift
            file="$1"
            shift
            ;;
        --) # End of all options
            shift
            break
            ;;
        *)  # no more options. Stop while loop
            break
            ;;  
    esac
done

if [ -f /data/local/tmp/busybox ];then
    export bb="/data/local/tmp/busybox"
else
    echo "No /data/local/tmp/busybox"
    exit
fi
if [ -f /data/local/tmp/stop ];then
    $bb rm /data/local/tmp/stop
fi

if [ -f /data/local/tmp/FPS.pid ];then
    pid=`cat /data/local/tmp/FPS.pid`
    if [ -f /proc/$pid/cmdline ];then
        if [ `$bb awk 'NR==1{print $1}' /proc/$pid/cmdline`"a" == "sha" ];then
            echo "The $pid is sh command."
            exit
        fi
    fi
fi
echo $$ >/data/local/tmp/FPS.pid

if [ $target -le 60 -a $target -gt 0 ];then
    sleep_t=1600000
else
    echo "$target is out of (0-60]"
    exit
fi
mac=`cat /sys/class/net/*/address|$bb sed -n '1p'|$bb tr -d ':'`
model=`getprop ro.product.model|$bb sed 's/ /_/g'`
build=`getprop ro.build.fingerprint`
if [ -z $build ];then
    build=`getprop ro.build.description`
fi

uptime=`$bb awk -v T="$EPOCHREALTIME" 'NR==3{printf("%.6f",T-$3/1000000000+8*3600)}' /proc/timer_list`
if [ -z "$file" ];then
    echo ""
    echo `date +%Y/%m/%d" "%H:%M:%S`": $window"
    if [ `$bb awk -F. '{print $1}' /proc/uptime` -lt 1000 ];then
        echo -e "FU(s) \tLU(s) \tDate \t\t\tFPS:$target\tFrames\tjank\tjank2\tMFS(ms)\tOKT:$KPI\tSS(%)\tWN"
    else
        echo -e "FU(s) \t\tLU(s) \t\tDate \t\t\tFPS:$target\tFrames\tjank\tjank2\tMFS(ms)\tOKT:$KPI\tSS(%)\tWN"
    fi
    while true;do
        dumpsys SurfaceFlinger --latency-clear
        $bb usleep $sleep_t
        dumpsys SurfaceFlinger --latency "$window"|$bb awk -v time=$uptime -v target=$target -v kpi=$KPI '{if(NR==1){r=$1/1000000;if(r<0)r=$1/1000;b=0;n=0;w=1}else{if(n>0&&$0=="")O=1;if(NF==3&&$2!=0&&$2!=9223372036854775807){x=($3-$1)/1000000/r;if(b==0){b=$2;n=1;d=0;D=0;if(x<=1)C=r;if(x>1){d+=1;C=int(x)*r;if(x%1>0)C+=r};if(x>2)D+=1;m=r;o=0}else{c=($2-b)/1000000;if(c>500){O=1}else{n+=1;if(c>=r){C+=c;if(c>kpi)o+=1;if(c>=m)m=c;if(x>1)d+=1;if(x>2)D+=1;b=$2}else{C+=r;b=sprintf("%.0f",b+r*1000000)}}};if(n==1)s=sprintf("%.3f",$2/1000000000)};if(n>0&&O==1){O=0;if(n==1)t=sprintf("%.3f",s+C/1000);else t=sprintf("%.3f",b/1000000000);T=strftime("%F %T",time+t)"."sprintf("%.0f",(time+t)%1*1000);f=sprintf("%.2f",n*1000/C);m=sprintf("%.0f",m);g=f/target;if(g>1)g=1;h=kpi/m;if(h>1)h=1;e=sprintf("%.2f",g*60+h*20+(1-o/n)*20);print s"\t"t"\t"T"\t"f+0"\t"n"\t"d"\t"D"\t"m"\t"o"\t"e"\t"w;n=0;if($0==""){b=0;w+=1}else{b=$2;n=1;d=0;D=0;if(x<=1)C=r;if(x>1){d+=1;C=int(x)*r;if(x%1>0)C+=r};if(x>2)D+=1;m=r;o=0}}}}'
        if [ -f /data/local/tmp/stop ];then
            break
        fi
    done
else
    start_time="`date +%Y/%m/%d" "%H:%M:%S`"
    echo "PID:$$\nWindow:$window\nT-FPS:$target\nKPI:$KPI\nStart time:$start_time\nmodel:$model\nmac:$mac\nbuild:$build"
    echo "FU(s),LU(s),Date:$window,FPS:$target,Frames,jank,jank2,MFS(ms),OKT:$KPI,SS(%),WN" >$file
    while true;do
        dumpsys SurfaceFlinger --latency-clear
        if [ -f /data/local/tmp/stop ];then
            echo "Stop Time:`date +%Y/%m/%d" "%H:%M:%S`"
            break
        fi
        $bb usleep $sleep_t
        dumpsys SurfaceFlinger --latency "$window"|$bb awk -v time=$uptime -v target=$target -v kpi=$KPI '{if(NR==1){r=$1/1000000;if(r<0)r=$1/1000;b=0;n=0;w=1}else{if(n>0&&$0=="")O=1;if(NF==3&&$2!=0&&$2!=9223372036854775807){x=($3-$1)/1000000/r;if(b==0){b=$2;n=1;d=0;D=0;if(x<=1)C=r;if(x>1){d+=1;C=int(x)*r;if(x%1>0)C+=r};if(x>2)D+=1;m=r;o=0}else{c=($2-b)/1000000;if(c>500){O=1}else{n+=1;if(c>=r){C+=c;if(c>kpi)o+=1;if(c>=m)m=c;if(x>1)d+=1;if(x>2)D+=1;b=$2}else{C+=r;b=sprintf("%.0f",b+r*1000000)}}};if(n==1)s=sprintf("%.3f",$2/1000000000)};if(n>0&&O==1){O=0;if(n==1)t=sprintf("%.3f",s+C/1000);else t=sprintf("%.3f",b/1000000000);T=strftime("%F %T",time+t)"."sprintf("%.0f",(time+t)%1*1000);f=sprintf("%.2f",n*1000/C);m=sprintf("%.0f",m);g=f/target;if(g>1)g=1;h=kpi/m;if(h>1)h=1;e=sprintf("%.2f",g*60+h*20+(1-o/n)*20);print s","t","T","f+0","n","d","D","m","o","e","w;n=0;if($0==""){b=0;w+=1}else{b=$2;n=1;d=0;D=0;if(x<=1)C=r;if(x>1){d+=1;C=int(x)*r;if(x%1>0)C+=r};if(x>2)D+=1;m=r;o=0}}}}' >>$file
    done
fi

四、监控数据可视化交互结果设计

既然设计了数据监控的形式,自然要设计配套的数据可视化呈现方式
1、呈现数据
(1)x 轴为同步时间点,每次采样数据为起始时间点到采样结束时间的一条横线。
(2)y 轴数据为平均 FPS、超 KPI 帧数比例、和流畅度得分。左右双 y 轴设计,左侧为帧率,右侧为百分比。
(3)两次数据起始时间间隔超 500ms 则断开
(4)每点交互数据显示此次原始数据记录
(5)按每次间隔时间超过 500ms 为准计算每次操作对应的响应时长,作图呈现。持续监控情况则每超 10 秒计算一次。
2、一次监视频控播放窗口结果图实例:

下方总趋势图是可选的,鼠标按住左键拖动选取查看范围。

  作为一位过来人也是希望大家少走一些弯路

在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。

(软件测试相关资料,自动化测试相关资料,技术问题答疑等等)

相信能使你更好的进步!

点击下方小卡片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/46133.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ES6基础知识二:ES6中数组新增了哪些扩展?

一、扩展运算符的应用 ES6通过扩展元素符…&#xff0c;好比 rest 参数的逆运算&#xff0c;将一个数组转为用逗号分隔的参数序列 console.log(...[1, 2, 3]) // 1 2 3console.log(1, ...[2, 3, 4], 5) // 1 2 3 4 5[...document.querySelectorAll(div)] // [<div>, &l…

APISIX 安全评估

背景 有大佬已经对 [apisix攻击面](https://ricterz.me/posts/2021-07-05-apache-apisix-attack- surface-research.txt)做过总结。 本文记录一下自己之前的评估过程。 分析过程 评估哪些模块&#xff1f; 首先我需要知道要评估啥&#xff0c;就像搞渗透时&#xff0c;我得…

Websocket协议-http协议-tcp协议区别和相同点

通讯形式 单工通讯-数据只能单向传送一方来发送数据&#xff0c;另一方来接收数据 半双工通讯-数据能双向传送但不能同时双向传送 全双工通讯-数据能够同时双向传送和接受 注&#xff1a;http的通讯方式是分版本 http1.0&#xff1a;单工。因为是短连接&#xff0c;客户端…

【设计模式——学习笔记】23种设计模式——建造者模式Builder(原理讲解+应用场景介绍+案例介绍+Java代码实现)

介绍 建造者模式又叫生成器模式&#xff0c;是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别)&#xff0c;使这个抽象过程的不同实现方法可以构造出不同属性的对象建造者模式是一步一步创建一个复杂的对象&#xff0c;它允许用户只通过指定复杂对象的类型和…

C 程序 运算符

文章目录 1、算术运算符2、关系运算符3、逻辑运算符4、位运算符5、赋值运算符6、杂项运算符 ↦ sizeof & 三元7、运算符优先级 1、算术运算符 #include <stdio.h>int main() {int a 21;int b 10;int c ;c a b;printf("Line 1 - c 的值是 %d\n", c );c …

【mac系统】mac系统调整妙控鼠标速度

当下环境&#xff1a; mac系统版本&#xff0c;其他系统应该也可以&#xff0c;大家可以自行试下&#xff1a; 鼠标 mac妙控鼠标&#xff0c;型号A1657 问题描述&#xff1a; 通过mac系统自带的鼠标速度调节按钮&#xff0c;调到最大后还是感觉移动速度哦过慢 问题解决&…

Cesium态势标绘专题-矩形(标绘+编辑)

标绘专题介绍:态势标绘专题介绍_总要学点什么的博客-CSDN博客 入口文件:Cesium态势标绘专题-入口_总要学点什么的博客-CSDN博客 辅助文件:Cesium态势标绘专题-辅助文件_总要学点什么的博客-CSDN博客 本专题没有废话,只有代码,代码中涉及到的引入文件方法,从上面三个链…

网站实现下载apk安装包

目录 1、背景说明2、效果图3、具体实现3.1 界面代码3.2 js代码 4、说明4.1 存在异常4.2 解决方案 5、参考资料 1、背景说明 有时需要将写好的apk安装包在局域网内部进行发布&#xff0c;具体实现非常简单&#xff0c;如下所示 2、效果图 进入到网站后&#xff0c;点击下载按…

STM32MP157驱动开发——按键驱动(tasklet)

文章目录 “tasklet”机制&#xff1a;内核函数定义 tasklet使能/ 禁止 tasklet调度 tasklet删除 tasklet tasklet软中断方式的按键驱动程序(stm32mp157)tasklet使用方法&#xff1a;button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “tasklet”机制&#xff1a; …

Stable Diffusion服务环境搭建(远程服务版)

Stable Diffusion服务环境搭建&#xff08;远程服务版&#xff09; Stable Diffusion是什么 Stable diffusion是一个基于Latent Diffusion Models&#xff08;潜在扩散模型&#xff0c;LDMs&#xff09;的文图生成&#xff08;text-to-image&#xff09;模型。具体来说&#…

学生公寓报修管理系统的设计与实现(论文+源码)_kaic

摘 要 随着科技的发展&#xff0c;信息化的管理手段早以在人们生活的各个方面取代了传统的管理手段&#xff0c;以先进管理理念为基础的现代化信息管理系统已经成为了许多机构的必备工具。在如今大学的校园里&#xff0c;有着许许多多的信息化管理系统&#xff0c;如图书管理系…

前端面试题汇总大全!

文章目录 前端面试题汇总大全&#xff08;含答案超详细&#xff09;-- 持续更新一、HTML 篇1.xhtml和html有什么区别2.行内元素有哪些&#xff1f;块级元素有哪些&#xff1f; 空(void)元素有那些&#xff1f;行内元素和块级元素有什么区别3. 简述一下你对 HTML 语义化的理解&a…

【数学建模】为什么存在最优策略?

一、说明 在进行优化回归过程&#xff0c;首先要看看是否存在最优策略&#xff1f; 在有限马尔可夫决策过程 &#xff08;MDP&#xff09; 中&#xff0c;最优策略被定义为同时最大化所有状态值的策略。换句话说&#xff0c;如果存在最优策略&#xff0c;则最大化状态 s 值的策…

组件化开发复习

1.vue的根组件使用 // 1.创建appconst app Vue.createApp({// data: option apidata() {return {message: "Hello Vue",counter: 0,counter2: 0,content: ""}},watch: {content(newValue) {console.log("content:", newValue)}}}) createApp 函…

【升职加薪秘籍】我在服务监控方面的实践(3)-机器监控

大家好,我是蓝胖子&#xff0c;关于性能分析的视频和文章我也大大小小出了有一二十篇了&#xff0c;算是已经有了一个系列&#xff0c;之前的代码已经上传到github.com/HobbyBear/performance-analyze&#xff0c;接下来这段时间我将在之前内容的基础上&#xff0c;结合自己在公…

C语言---动态内存管理

C语言—动态内存管理 文章目录 C语言---动态内存管理1. 为什么要进行动态内存分配1.1 动态内存管理所在的区域 2. 动态内存函数的介绍2.1 malloc2.1.1 malloc语法2.1.2 malloc具体实例 2.2 free2.2.1 free语法2.2.2 free具体实例 2.3 calloc2.3.1 calloc语法2.3.2 calloc具体实…

42. 接雨水

题目介绍 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3…

OpenShift 4 - 可观测性之用 OpenTelemetry+Jaeger 实现 Distributed Tracing

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在支持 OpenShift 4.13 的环境中验证 文章目录 技术架构部署 Distributed Tracing 运行环境安装测试应用并进行观测跟踪参考 说明&#xff1a; 本文使用的测试应用采用的是 “手动 Instrumentation” 方式在…

Linux系列---【CentOS 7通过MSTSC连接远程桌面】

安装对应的yum源 yum list lightdm xorgxrdp xrdp 可以看到这些软件都在epel中&#xff0c;如果没有的话&#xff0c;请先安装对应的yum源。命令如下&#xff1a; yum install -y epel-release 确认yum源没有问题之后&#xff0c;我们就可以进行安装了。 安装lightdm xorgxrdp…

【C语言】嵌入式C语言项目管理利器:深入理解Makefile的应用与实践

目录 一、makedile的概述 1、案例引入 2、makefile 3、Makefile优点 二、makefile的语法规则 1、语法规则 2、简单实战 三、makefile的变量 1、自定义变量 2、系统环境变量 3、预定义变量 4、高级makefile 一、makedile的概述 1、案例引入 gcc a.c b.c c.c ‐o …