鹅厂优文 | 企点PC端性能测试-UI卡顿分析
作者:付煜 | 腾讯SNG系统工程师
一、背景
PC端的测试过程中会碰到一些性能问题,例如UI卡顿,内存泄漏等等,为了找到原因,做了很多的调研和尝试,也总结了一些方法。本文以一个企点融合工作台测试中发现的案例说明如何获得UI卡顿数据,以及如何分析数据,定位问题
二、案例介绍
点击工作台拨号盘时,数字按钮的响应可以感觉到明显的卡顿。以下是修复前和修复后的效果对比
三、工具介绍
目前业界用的比较多的Windows性能测试工具主要有:
-
WPT(Windows performance toolkit)
:微软官方的性能测试工具,集成在Windows SDK中 -
UIforETW
:开源工具,下载地址
在前期的调研中,WPT
可以说是 “举步维艰“,而UIforETW
则是“纵享丝滑”,基于以下原因,最终选择了UIforETW
:
WPT |
UIforETW |
|
---|---|---|
资料 |
文档少且简单:包括官网和第三方文档 |
文档丰富:约160篇文章和4个视频 |
使用门槛 |
门槛高:自定义配置较多 |
门槛低:默认配置完善 |
其实无论是WPT
还是UIforETW
都是基于Xperf
的工具,而Xperf
的基础又是ETW(Event Tracing for Windows)
,ETW
是一个生产者消费者模式的系统,它提供了内核级的事件跟踪能力。
ETW
有三个成员组成:
- Controllers,负责启动停止Event Tracing Session,负责启用停止Providers。
- Providers,负责向Event Tracing Session中输出事件。
- Consumers,从Event Tracing Session中获取事件。
具体的原理请参考Xperf原理
四、案例分析
只要UI 线程Delay时间超过200 ms,Microsoft-Windows-Win32k
Provider就会记录事件,并在UI Delay图中显示
1、测试场景
鼠标点击工作台拨号盘任意数字按钮5次
2、数据获取
点击Start Tracing
后,复现卡顿现场,接着点击Save Trace Buffers
即可,生成的数据文件显示在Traces
栏
双击打开数据文件,左侧的Graph Explorer展示了获取到的图形列表,包含了System Activity,CPU Usage,File I/O等,找到UI Delay图形
双击大图展示如下:
从图中可以看到,QiDian(7320)的3840线程总共有5次卡顿,每次卡了约0.5s,共约2.7s
3、卡顿分析
选择5次卡顿的任意一次进行分析,打开CPU(Precise)图形,找到QiDian.exe(7320)和3840线程
简单介绍一下图中表格列的含义:
-
New Thread Id
: 即将开始执行线程(即将切换到运行状态的线程)Id -
New Thread Stack
:即将开始执行线程的调用栈 -
Time Since Last
:线程处于准备状态和等待状态的时间和 -
Count
:上下文切换次数 -
CPU Usage(in view)
:CPU耗时
结合UI Delay图和CPU图形可知,线程3840卡了约0.5 s,其中只有10 ms消耗了CPU,所以这个线程是空闲挂起状态。
为了查看具体的调用栈,在Trace
下配置PDB符号表路径并加载符号表
将Time Since Last
排序后,查看New Thread Stack
列,依次展开
可以很清楚的看到,上图中CCicEvent:Wait
进行了1次上下文切换, 将UI线程从533 ms的挂起的状态切换到运行状态
继续往New Thread Stack
的上面看,从图中可以很清楚的看到,企点应用层调用了LoadKeyboardLayoutW
方法,消耗了约0.54 s
找到源代码:
void functionA(INT id, Event* pEvent, Data* pData)
{
...
hkl=LoadKeyboardLayout(_T("0x0409"),KLF_ACTIVATE);
if (hkl==NULL)
{
return ;
}
ActivateKeyboardLayout(hkl,KLF_SETFORPROCESS);
HWND hWnd;
...
}
通过分析得知,这部分代码是开关输入法,由于工作台拨号盘限制输入的类型为英文,所以在点击按钮时会调用LoadKeybordLayout
和ActivateKeyboardLayout
装载并激活输入法,导致了UI上的卡顿。
定位原因后,解决方案:直接在输入法编辑状态过滤,避免开关输入法
五、总结
本文以一个案例介绍了如何分析客户端卡顿问题的思路和方法,另一方面,Windows性能问题除了UI卡顿外,还包括内存泄漏,磁盘读取等等,而UIforETW
是一个十分强大的工具,对其他的windows性能问题也能够很好的支持,目前对它的了解只是冰山一角,还需要继续的探索和实践。
- No.012 Integer to Roman
- 黑帽SEO剖析之手法篇
- IOS学习1——IOS应用程序的生命周期及基本架构
- 浅议“全局变量”、“多线程”和“编译器陷阱”
- Java实现的图片合并方法,支持水平和垂直合并
- OC学习15——文件I/O体系
- 用惯了ORM,居然不会写分页SQL了
- OC学习14——谓词
- 如何在32位系统中使用ROP+Return-to-dl来绕过ASLR+DEP
- 如何使用Twitter构建C;C服务器
- 【Python语言】Scikit-learn 快速入门
- 抽象SQL查询:SQL-MAP技术的使用
- 简析60度CMS的Cookies欺骗漏洞
- OC学习13——Foundation框架中的集合
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ClickHouse王炸功能即将来袭?
- 搭建Amoeba实现MySQL主从数据库读写分离
- 如何在centos7上看墙外的世界
- 远程仓库的使用
- 破解某交(y)友(p)app的VIP&&半自动im机器人
- 关于compareTo使用的几种情况
- 高通量数据中批次效应的鉴定和处理(二)
- 通过ansible管理docker容器
- HBASE 技术细节 读取与写入 Region Split与合并介绍
- django2.2+Daphne+nginx+supervisor 生产环境部署
- Python 爬虫进阶必备 | 趣解某不可逆加密(短文警告)
- confluence6.3安装与破解
- git分支
- git使用介绍
- jenkins添加git地址时报错问题