性能脚本

性能脚本是驱动浏览器运行特定基准测试(例如页面加载或底层调用)并生成指标的程序。

我们目前在 perftest 中支持两种类型(但很容易添加新的类型)

  • xpcshell 一个经典的 xpcshell 测试,转变为性能测试

  • browsertime 一个 browsertime 脚本,它运行一个完整的浏览器并通过 Selenium 客户端控制它。

  • mochitest 一个经典的 mochitest 测试,转变为性能测试

为了符合性能测试的标准,这两种类型都需要元数据。

对于我们支持的这两种 JavaScript 模块,元数据通过模块中的 perfMetadata 映射变量提供,或者在使用 Node 时通过 module.exports 变量提供。

以下是字段列表:

  • owner: 所有者(个人或团队)的名称 [必填]

  • author: 测试的作者

  • name: 测试的名称 [必填]

  • description: 简短描述 [必填]

  • longDescription: 详细描述

  • options: 用于运行测试的选项

  • supportedBrowsers: 支持的浏览器列表(或“Any”)

  • supportedPlatforms: 支持的平台列表(或“Any”)

  • tags 描述测试的一系列标签

测试使用测试清单和 moz.build 文件中的 PERFTESTS_MANIFESTS 变量进行注册 - 最佳实践是将此文件命名为 perftest.toml

此类文件的示例:https://searchfox.org/mozilla-central/source/testing/performance/perftest.toml

xpcshell

xpcshell 测试是普通的 xpcshell 测试,另外还有两件事:

  • 如上一节所述的 perfMetadata 变量

  • 调用 info(“perfMetrics”, …) 将指标发送到 perftest 框架。

以下是一个此类指标调用的示例:

# compute some speed metrics
let speed = 12345;
info("perfMetrics", JSON.stringify({ speed }));

Mochitest

类似于 xpcshell 测试,这些是标准的 mochitest 测试,带有一些额外的内容:

  • 如上一节所述的 perfMetadata 变量

  • 调用 info("perfMetrics", ...) 将指标发送到 perftest 框架

请注意,perfMetadata 变量可以存在于 Mochitest HTML 测试文件中的任何 <script>...</script> 元素中。 perfMetadata 变量在 Mochitest 测试中还需要一些其他设置。这些是 manifestmanifest_flavor 选项

var perfMetadata = {
  owner: "Performance Team",
  name: "Test test",
  description: "N/A",
  options: {
    default: {
      perfherder: true,
      perfherder_metrics: [
        { name: "Registration", unit: "ms" },
      ],
      manifest: "perftest.toml",
      manifest_flavor: "plain",
      extra_args: [
        "headless",
      ]
    },
  },
};

extra_args 设置提供了一个区域,用于为该测试提供自定义的 Mochitest 命令行参数。

以下是一个生成指标调用的示例:

# compute some speed metrics
let speed = 12345;
info("perfMetrics", JSON.stringify({ speed }));

现有的 Mochitest 单元测试可以通过这些修改来兼容 mozperftest,但请注意,这样做存在一些问题:

  • 在硬件上运行 mochitest 测试的单元测试问题

  • 在一个清单中运行测试的多个配置

在本文档顶部,您可以找到一些关于为添加专门用于运行性能测试的新清单推荐方法的信息。

在本地,mozperftest 使用 ./mach test 来运行您的测试。在尝试通过 ./mach perftest 运行测试之前,始终确保您的测试在 ./mach test 中正常工作。在 CI 中,我们使用自定义的“远程”运行,它直接运行 Mochitest,跳过 ./mach test

如果一切设置正确,在本地运行性能测试将像这样简单:

./mach perftest <path/to/my/mochitest-test.html>

自定义脚本

自定义脚本测试使用自定义/临时脚本执行测试。目前,仅通过 ScriptShellRunner 支持 shell 脚本。将来,可以通过添加新的测试层来支持其他类型的脚本。这些类型的脚本支持 custom-script 风格下的移动和桌面测试。

自定义 Shell 脚本

shell 脚本测试必须在代码中的某个位置包含以下字段作为注释:

# Name: name-of-test
# Owner: Name/team that owns the test
# Description: Description of the test

可选地,它还可以包含以 Options: 开头的行来表示任何默认选项。这些选项类似于其他测试层。对于这些自定义脚本测试,此字段中需要一个有效的 JSON 字符串。

这些脚本有一个为其定义的 BROWSER_BINARY,它将指向正在测试的二进制文件(或移动设备上的包名称)。默认情况下,这是 Firefox。如果需要不同的二进制文件,可以使用 --binary 指定它,或者如果应用程序已知并且可以自动找到(不保证)则使用 --app

一旦为 shell 脚本测试设置好所有内容,就可以使用以下命令运行它:

./mach perftest <path/to/custom-script.sh>

警报

此风格/层启用在本地运行所有产生性能警报的测试。它可以运行没有任何选项的基本测试,或者通过传递 --alert-exact 选项运行在 CI 中运行测试时使用的完全相同的命令。 --alert-tests 选项也可用于指定应从警报中运行哪些测试。

以下命令可用作运行给定警报编号的所有测试的示例:

./mach perftest <ALERT-NUMBER>

请注意,此层没有可用的测试,新测试永远不应该使用此层。

Browsertime

使用 browsertime 层,性能场景是 Node 模块,它至少实现了一个异步函数,该函数将在浏览器启动后由框架调用。该函数获取一个 webdriver 会话,并且可以与浏览器交互。

您可以编写复杂、交互式的场景来模拟用户旅程,并收集各种指标。

完整的文档可在 此处 获取。

mozilla-central 存储库在 testing/performance 中有一些性能测试脚本,将来应该在组件中添加更多脚本。

按照惯例,性能测试以 perftest_ 为前缀,以便 perftest 命令识别。

性能测试至少实现了一个异步函数,该函数在 node 的 module.exports 中发布为 test。该函数接收两个对象:

  • context,其中包含:

    • options - 从 CLI 发送到 Browsertime 的所有选项

    • log - 日志系统的一个实例,以便您可以从导航脚本中记录日志

    • index - 运行的索引,以便您可以跟踪当前正在运行的是哪个运行

    • storageManager - Browsertime 存储管理器,可以帮助您读取/存储文件到磁盘

    • selenium.webdriver - Selenium WebDriver 公共 API 对象

    • selenium.driver - 正在驱动当前浏览器版本的 WebDriver 的实例化版本

  • command 提供与浏览器交互的 API。它是 selenium 客户端的包装器 完整的文档在此处

以下是一个访问 BBC 首页并点击链接的测试示例:

"use strict";

async function setUp(context) {
  context.log.info("setUp example!");
}

async function test(context, commands) {
    await commands.navigate("https://www.bbc.com/");

    // Wait for browser to settle
    await commands.wait.byTime(10000);

    // Start the measurement
    await commands.measure.start("pageload");

    // Click on the link and wait for page complete check to finish.
    await commands.click.byClassNameAndWait("block-link__overlay-link");

    // Stop and collect the measurement
    await commands.measure.stop();
}

async function tearDown(context) {
  context.log.info("tearDown example!");
}

module.exports = {
    setUp,
    test,
    tearDown,
    owner: "Performance Team",
    test_name: "BBC",
    description: "Measures pageload performance when clicking on a link from the bbc.com",
    supportedBrowsers: "Any",
    supportePlatforms: "Any",
};

除了 test 函数之外,脚本还可以实现 setUptearDown 函数,以便在测试之前和之后运行一些代码。这些函数将只调用一次,而 test 函数可能会调用多次(通过 iterations 选项)

钩子

Python 模块可用于在运行生命周期中运行函数。可用的钩子有:

  • before_iterations(args) 在一切开始之前运行。获取 args,可以对其进行更改。 args 参数还包含一个 virtualenv 变量,可用于安装 Python 包(例如,通过 install_package)。

  • before_runs(env) 在测试启动之前运行。可用于更改运行环境。

  • after_runs(env) 在测试完成后运行。

  • on_exception(env, layer, exception) 在任何异常时调用。提供发生异常的层和异常。如果钩子返回 True,则忽略异常并继续测试。如果钩子返回 False,则忽略异常并且测试立即结束。钩子还可以重新引发异常或引发其自己的异常。

在下面的示例中,before_runs 钩子正在动态设置选项,因此用户不必在命令行中提供它们。

from mozperftest.browser.browsertime import add_options

url = "'https://www.example.com'"

common_options = [("processStartTime", "true"),
                  ("firefox.disableBrowsertimeExtension", "true"),
                  ("firefox.android.intentArgument", "'-a'"),
                  ("firefox.android.intentArgument", "'android.intent.action.VIEW'"),
                  ("firefox.android.intentArgument", "'-d'"),
                  ("firefox.android.intentArgument", url)]


def before_runs(env, **kw):
    add_options(env, common_options)

要使用此钩子模块,可以将其传递给 –hooks 选项。

$  ./mach perftest --hooks hooks.py perftest_example.js