编辑注: 这篇文章也在 2017 年性能日历 上发布。
这是一个关于 Mozilla 在台北的工程团队的故事,他们被赋予了测量性能和解决 Firefox 中一些特定性能瓶颈的任务。这也是关于用户报告的性能问题被转化为可操作见解的故事。这是我们如何开发 Hasal 的故事,这是一个用于测试不同浏览器之间 Web 性能的框架。Hasal 采取了一种新的测试方法,在过程中考虑了用户的感知。
早在 2016 年,Firefox 的性能就存在问题。我们有很多问题需要解决。其中一个关键问题与用户关于 Firefox 在办公 Web 应用程序中的性能问题的报告有关,包括缓慢的页面加载以及迟缓的响应时间。
我们认真对待这些问题,并在日常工作中也遇到过很多类似的问题,因此,找出这些性能问题的根本原因是我们最优先的任务。不幸的是,用户的情绪往往不具体,这使得识别具体问题并评估其影响变得很困难。因此,我们决定采取一种新的方法。
我们试图在不使用 WebDriver 的情况下实现一个框架,WebDriver 依赖于专门的浏览器 API 和 JavaScript 注入来操作浏览器。相反,我们使用了 Sikuli,它向计算机提交类似本机的 I/O 信号来模拟用户操作。我们构建了一个框架,允许您在 Web 应用程序上定义精确的用户交互,并使用图像识别和实时测量来测量输入延迟时间,而不是使用 DOM 事件。
经过大约一年的努力,我们成功地实现了 Hasal,用于比较不同浏览器在各种 Web 应用程序上的实际输入延迟。
什么是实际输入延迟?
根据 Google 的 “使用 RAIL 模式测量性能”,实际输入延迟是关键指标之一,它将 Web 性能的测量范围扩展到页面加载之外,并专注于响应能力和应用内导航。
在典型的 Web 应用程序中,浏览器花费大部分时间等待网络资源下载和运行 JavaScript。Hasal 实现的目标是专注于后者,这意味着我们测量的是从 I/O 事件到用户感知到的 Web 应用程序的第一个响应之间经过的时间。因此,我们只测量从用户输入到屏幕初始变化的时间。我们将这种时间测量定义为实际输入延迟。
实现概念
基本概念
我们的目标是实现一个从用户感知角度构建的工具。我们设计了工作流程,以便每个模拟的用户步骤都基于图像识别,每个数值测量都基于视觉分析。
基本流程
我们的框架基于 PyUnit 框架 并结合了 Sikuli。您可以在上面的图中看到我们的工作流程。首先,我们在 setup()
函数中有一些先决条件任务。接下来,它在指定测试的 run()
函数中执行模拟的用户步骤。最后,我们从 teardown()
函数中获得最终输出。
每个模拟的用户交互都会被截屏以供分析。Hasal 依赖于视频录制和图像提取来获得所需的结果。我们如何做到这一点的细节将在接下来的几段中解释。
运行细节
在进入 run()
函数时,我们通过 JVM(Java 虚拟机)向屏幕上的特定图标、图像或区域发送模拟的 I/O 事件。这样,我们就模拟了人们与 Web 应用程序交互的方式。此外,我们同时通过 JVM 将事件日志发送到终端。这被认为是识别 I/O 事件何时触发的标记。
视频分析
在 teardown()
函数中,Hasal 完成桌面视频录制并开始分析视频。获取测量时间的基本原理是计算两个关键帧之间实际播放的帧数。第一个关键帧是在终端出现指示时标记的,我们假设终端显示的指示与提交 I/O 事件之间几乎没有时间延迟。第二个关键帧是浏览器特定区域中的第一次屏幕变化。换句话说,第二个关键帧是 Web 应用程序首次响应的指示。
通过计算第一个关键帧和第二个关键帧之间的实际帧数,我们可以获得 Web 应用程序对用户操作的实际响应时间。例如,如果我们以 90fps(每秒帧数)录制,并且如上图所示,两个关键帧之间有 10 帧,那么我们将获得 111.11 毫秒的实际输入延迟。
实际输入延迟的示例
为了更好地说明如何从 Web 应用程序上定义的用户交互到使用 Hasal 进行实际输入延迟测量,以下是我们来自我们 “社交”类别(如我们在之前关于性能测试的文章中所述)的测试用例之一的示例。
在一个测试场景中,我们 测量了从初始点击到聊天屏幕显示的实际输入延迟。以下是测试步骤。这些步骤是已翻译成链接脚本的步骤
用户想要在 Facebook 上打开聊天窗口。因此,他们从好友列表中选择一位好友,点击相应好友以启动窗口并等待窗口加载。
设置
- 打开浏览器并在 URL 栏中输入 URL
- 登录 Facebook 并等待页面完全加载
- 确保好友列表没有隐藏
运行
- 将鼠标光标移动到好友列表中的某个头像
- 拍摄快照(快照 1)
- 发送 MouseDown 事件
- 发送 MouseUp 事件并同时将消息发送到终端控制台并拍摄快照(快照 2)
- 等待聊天窗口启动
拆卸
- 关闭聊天屏幕
- 关闭浏览器
输入延迟的结果将根据快照 1、2 和从视频转换的帧来得出实际播放的帧数。
有关如何测试每个 Web 应用程序的更多详细信息,请参见 存储库。
当前结果
- Firefox Quantum 中的性能改进
该框架最初的目标是在特定 Web 应用程序中找出 Firefox 与其他浏览器之间的性能差异。完成对目标应用程序的检查后,我们开始帮助寻找其他主要 Web 应用程序中的性能差距。

我们致力于使用 Hasal 框架来测量和改进 Firefox Quantum 的性能。随着时间的推移,我们在不同 Web 应用程序的实际输入延迟方面看到了巨大的改进。在上图中,我们可以看到 Firefox Quantum 的响应时间提高了 6 倍。根据 Hasal 的结果,我们已经提交了 200 多个错误报告,其中 80% 以上已在我们的 Firefox Quantum 版本中修复。
其他发现
我们有时会在我们的测试中看到一些性能回归,而我们对浏览器没有进行任何实际更改。在与相应的第三方 Web 服务提供商确认后,我们发现我们能够通过我们的测试检测到他们方面的性能回归。
Hasal 框架的局限性
Hasal 的工作一直是实施和测试的不断迭代方法。在整个开发过程中,我们与 Mozilla 的其他工程团队密切合作,使 Hasal 尽可能有用。但是,仍然存在一些局限性,需要牢记
测量时间受 FPS 限制
由于我们的测量基于捕获的帧,因此一帧内的任何操作都无法通过此框架测量。在我们的实验室环境中,我们以 90fps 的速度录制,此阈值为 11.11ms,任何快于 11.11ms 的响应都无法检测到。
开销在不同的浏览器中可能会有所不同
由于该框架严重依赖于捕获桌面视频,因此可能会引入开销。我们已尝试选择一个开销很小的记录器,该记录器直接从硬件录制。但是,这种方法可能会在不同的浏览器中引入不同的开销,因为利用图形卡计算能力的实现方式不同。
JVM 版本也会影响测量的时长
由于 Hasal 方法也严重依赖于假设,即向终端发送指示器应该比向浏览器发送 I/O 事件只有很短的延迟,我们已经进行了大量的分析以确保该假设是正确的。根据我们的分析结果,我们几乎可以肯定。但是,我们仍然发现不同的 JVM 版本可能会在某些环境中破坏我们的假设。有时,较新的 JVM 版本可能会增加在向终端发送指示器和发送 I/O 事件之间的时间延迟。实际上,我们发现升级 Java 引入了 20ms 的延迟。
展望
虽然当前的 Hasal 实现已被证明对指导修复关键性能问题的工程工作很有用,但我们还需要解决一些开放问题,才能使 Hasal 成为用于测试性能的通用框架。
可移植性
此框架是许多工具的组合。因此,它需要一个耗时的安装脚本才能部署该框架。这也增加了使用的障碍,因为在其他环境中安装和复制我们的测试结果很困难。因此,在未来,我们将努力使其在其他环境中更容易安装和使用。
移动设备
我们框架的总体概念也应该适用于移动设备。但是,我们可能需要在继续之前更改一些内容。首先,视频记录器可能需要替换为快照或屏幕截图软件,以最大限度地降低 CPU 电力消耗并提高效率。此外,连接到移动设备的主机应负责计算结果。
降低开销
我们已经讨论过依赖软件桌面视频记录器可能会在某些情况下引入不可忽略的开销的问题。因此,我们也考虑了另一种解决方案来记录整个桌面屏幕。例如,外部 HDMI 记录器或外部高速摄像机将是我们进一步研究的潜在选择。
分析
当您发现一个存在重大性能问题的场景时,通常会为此提交一个错误。但是,错误不会提供测试过程中的详细信息,例如采取下一步行动所需的详细分析器数据。这在我们目前的框架中缺失。很难找到一种方法将实际的视觉表示与代码堆栈结合起来。但我们正在尝试通过分析器中的指示器和标记将它们集成在一起。这可以帮助我们了解同一时间轴中的两件不同的事情,并让工程师更多地了解情况。
请告诉我们您的想法,谢谢!

关于 Shako Ho
我从事软件开发工作已有 13 年,其中最近 9 年专注于性能测量、测试自动化、测试顾问和 Scrum 流程。最近,我特别感兴趣的是性能测量,并且拥有从头开始开发性能测量框架的丰富经验。无论我担任什么角色,我一直专注于使整个产品的测试高效且质量驱动。
关于 Kan-Ru Chen
领导性能团队,致力于解决 Mozilla 中的 Quantum 流和稳定性问题。还负责 IPC 和随机 DOM/布局/GFXs/小部件错误。
关于 Walter Chen
我目前在台湾为 Mozilla 工作。我是一名软件工程师。我喜欢去不同的地点旅行。
3 条评论