测试
由于构建配置和嵌入目标的广泛多样性,Perfetto 的测试策略相当复杂。
常见测试目标(所有平台/检出):
perfetto_unittests:
与平台无关的单元测试。
perfetto_integrationtests:
端到端测试,涉及基于 protobuf 的 IPC 传输和 ftrace
集成(仅限 Linux/Android)。
perfetto_benchmarks:
基准测试跟踪以下性能:(i) trace 写入,(ii) trace 回读
以及 (iii) ftrace 原始管道 -> protobuf 翻译。
运行测试
在 Linux / MacOS 上
tools/ninja -C out/default perfetto_{unittests,integrationtests,benchmarks}
out/default/perfetto_unittests --gtest_helpperfetto_integrationtests 要求在 Linux 上当前用户可以
读取/写入 ftrace debugfs 目录:
sudo chown -R $USER /sys/kernel/debug/tracing在 Android 上
- 通过
adb连接设备 - 启动内置模拟器(支持 Linux 和 MacOS):
tools/install-build-deps --android
tools/run_android_emulator &- 运行测试(在模拟器或物理设备上):
tools/run_android_test out/default perfetto_unittests持续测试
Perfetto 在各种位置进行测试:
Perfetto CI: https://ci.perfetto.dev/ 从独立检出构建和运行 perfetto_{unittests,integrationtests,benchmarks}。 基准测试以简化形式运行以进行冒烟测试。 有关更多详细信息,请参阅 此文档。
Android CI(参见 go/apct 和 go/apct-guide):
仅运行 perfetto_integrationtests
Android 预提交(TreeHugger) :
在提交每个 external/perfetto 的 AOSP CL 之前运行。
Android CTS(用于确保 API 兼容性的 Android 测试套件): 内部滚动运行。
请注意,Perfetto CI 使用独立构建系统,其他构建为 Android 树的一部分。
单元测试
Perfetto 中大多数代码在类级别都存在单元测试。它们 确保每个类大致按预期工作。
单元测试目前在 ci.perfetto.dev 和 build.chromium.org 上运行。 在 APCT 和 Treehugger 上运行单元测试正在进行中。
集成测试
集成测试确保子系统(特别是 ftrace 和 IPC 层) 和 Perfetto 作为整体在端到端方面正确工作。
集成测试可以在两种配置中运行:
1. 生产模式(仅限 Android)
此模式假设 tracing 服务(traced)和 OS 探测
服务(traced_probes)都已运行。在此模式下,测试仅启用
消费者端点并测试与生产
服务的交互。这是我们的 Android CTS 和 APCT 测试的工作方式。
2. 独立模式: 在测试本身中启动守护程序,然后针对它们进行测试。 这是独立构建的测试方式。这是在 Linux 和 MacOS 上 运行集成测试的唯一受支持的方式。
Trace Processor 差异测试
Trace Processor 主要使用所谓的"差异测试"而非单元测试进行测试。在处理解析 trace 的代码时,单元测试已被证明过于脆弱——每当解析逻辑重构时,它们都需要繁琐的机械更新——因此单元测试仅用于 Trace Processor 其余部分所基于的低层构建块。其他所有内容(解析事件、表 schema、stdlib 模块、动态表)都由差异测试覆盖。
对于这些测试,Trace Processor 解析已知的 trace 并执行查询字符串或文件。然后比较这些查询的输出(即"差异")与预期输出文件,并突出显示差异。
编写 metric 时也有类似的差异测试——不使用查询,而是使用 metric 名称,预期输出字符串包含计算 metric 的预期结果。
这些测试(对于查询和 metric)可以运行如下:
tools/ninja -C <out directory>
tools/diff_test_trace_processor.py <out directory>/trace_processor_shellTIP: 查询差异测试预期只有单个查询,该查询在整个文件中产生输出(通常在末尾)。
调用 SELECT RUN_METRIC('metric file') 可能会混淆此检查,因为此查询会生成一些隐藏输出。
为了解决此问题,如果查询只有名为 suppress_query_output 的列,即使它有输出,也将被忽略(例如,
SELECT RUN_METRIC('metric file') as suppress_query_output)
添加新的差异测试
所有差异测试位于 test/trace_processor 下的 tests{_category_name}.py 文件中,作为类的方法。要添加新测试,在合适的 Python 文件中添加一个以 test_ 开头的新方法。
方法不能接受参数,必须返回一个 DiffTestBlueprint:
class DiffTestBlueprint:
trace: Union[Path, Json, Systrace, TextProto]
query: Union[str, Path, Metric]
out: Union[Path, Json, Csv, TextProto]Trace 和 _Out_:对于 Path 以外的每种类型,对象的内容将被视为文件内容,因此必须遵循相同的规则。
_Query_:对于 metric 测试,只需提供 metric 名称。对于查询测试,可以是原始 SQL 语句,例如 "SELECT * FROM SLICE",或 .sql 文件的路径。
NOTE: 运行 tools/diff_test_trace_processor.py 之前,需要先构建 trace_processor_shell 及相关 proto 描述符。最简单的方法是在首次和每次更改 Trace Processor 代码时运行 tools/ninja -C <out directory>。
选择差异测试的添加位置
diff_tests/ 包含与 Trace Processor 不同区域对应的目录:
- stdlib:专注于 PerfettoSQL 标准库的测试,包括 prelude 和常规模块。子目录通常对应
perfetto_sql/stdlib中的目录。 - parser:专注于确保不同 trace 格式被正确解析且相应的内置表被填充的测试。
- syntax:专注于 PerfettoSQL 核心语法的测试(例如
CREATE PERFETTO TABLE、CREATE PERFETTO FUNCTION)。
场景:正在添加新的 stdlib 模块 foo/bar.sql。
_答案_:将测试添加到 stdlib/foo/bar_tests.py。
场景:正在解析一个新事件,测试的重点是确保该事件被正确解析。
_答案_:在 parser 子目录之一中添加测试。如果存在相关目录(例如 sched、power),优先将测试添加到现有目录中。
场景:正在添加新的动态表,测试的重点是确保动态表被正确计算。
_答案_:将测试添加到 stdlib/dynamic_tables。
场景:正在修改 Trace Processor 的内部实现,测试旨在确保 Trace Processor 正确过滤/排序重要的内置表。
_答案_:将测试添加到 parser/core_tables。
UI 像素差异测试
像素测试用于确保核心用户旅程正常工作,方法是验证它们
与黄金屏幕截图逐像素相同。它们使用无头
chrome 加载网页并截图,然后逐像素比较
黄金屏幕截图。你可以使用 ui/run-integrationtests 运行这些测试。
当一定数量的像素不同时,这些测试会失败。如果这些 测试失败,你需要调查差异并确定其是否有意。如果 这是所需的更改,你需要在 linux 机器上更新屏幕截图 以使 CI 通过。你可以通过生成和上传新的基线来更新它们(这需要通过 gcloud 访问 google 存储桶,只有 googlers 可以访问,googlers 可以 [在此](https://g3doc.corp.google.com/cloud/sdk/g3doc/index.md#installing-and-using-the-cloud-sdk)安装 gcloud)。
默认情况下,测试在 docker 容器中运行,除非传递 -no-docker。
建议使用容器以获得稳定和可重现的
测试环境,特别是对于重新设置基线,否则非常可能
在 CI 上运行时屏幕截图不匹配。
ui/run-integrationtests --rebaseline
tools/test_data upload完成后,你可以提交并上传作为 CL 的一部分,导致 CI 使用你的新屏幕截图。
注意:如果你看到失败的差异测试,你可以通过使用以 ui-test-artifacts/index.html 结尾的链接在 CI 上查看像素差异。该页面上报告包含已更改的屏幕截图以及接受更改的命令(如果这些更改是需要的)。
Android CTS 测试
CTS 测试确保任何修改 Android 的供应商保持与平台 API 的合规性。
这些测试包括上述集成测试的子集,并添加了更多复杂的测试,确保平台(例如 Android 应用程序等)和 Perfetto 之间的交互没有被破坏。
相关的目标是 CtsPerfettoProducerApp 和 CtsPerfettoTestCases。一旦这些构建完成,应运行以下命令:
adb push $ANDROID_HOST_OUT/cts/android-cts/testcases/CtsPerfettoTestCases64 /data/local/tmp/
adb install -r $ANDROID_HOST_OUT/cts/android-cts/testcases/CtsPerfettoProducerApp.apk接下来,应在设备上运行名为 android.perfetto.producer 的应用程序。
最后,应运行以下命令:
adb shell /data/local/tmp/CtsPerfettoTestCases64Chromium waterfall
Perfetto 通过 此自动滚轮 不断滚入 chromium 的 //third_party/perfetto。
Chromium CI 运行 perfetto_unittests 目标,如 buildbot 配置 中定义的。
你也可以在提交之前针对 Chromium 的 CI / TryBots 测试待定的 Perfetto CL。当你进行更棘手的 API 更改或测试 Perfetto CI 未涵盖的平台(例如 Windows、MacOS)时,这可能很有用,允许你在提交之前验证补丁(然后它最终会自动滚入 Chromium)。
为此,首先确保你已上传拉取请求到 GitHub。
接下来,创建一个新的 Chromium CL 来修改 Chromium 的 //src/DEPS 文件。
如果你最近上传了更改,修改 src/third_party/perfetto 的 DEPS 条目中的 git commit hash 可能就足够了:
'src/third_party/perfetto':
Var('chromium_git') + '/external/github.com/google/perfetto/' + '@' + '8fe19f55468ee227e99c1a682bd8c0e8f7e5bcdb',将 git hash 替换为你最新补丁集的 commit hash。
或者,你可以添加 hooks 来在 Chromium 当前的 third_party/perfetto 修订版之上修补待定的 CL。为此,将以下条目添加到 Chromium 的 //src/DEPS 文件中的 hooks 数组,将 refs/pull/XXXX/head 修改为适合你的拉取请求的值。
{
'name': 'fetch_custom_patch',
'pattern': '.',
'action': [ 'git', '-C', 'src/third_party/perfetto/',
'fetch', 'https://github.com/google/perfetto.git',
'refs/pull/XXXX/head',
],
},
{
'name': 'apply_custom_patch',
'pattern': '.',
'action': ['git', '-C', 'src/third_party/perfetto/',
'-c', 'user.name=Custom Patch', '-c', 'user.email=custompatch@example.com',
'cherry-pick', 'FETCH_HEAD',
],
},如果你想针对 Chrome 的 SDK 构建测试你的更改,你可以将 Cq-Include-Trybots: 行添加到 gerrit 中的更改描述中以用于 perfetto SDK trybots(一旦 Chrome 迁移到 SDK 完成,这将不再需要,请参阅 跟踪 bug):
Cq-Include-Trybots: luci.chromium.try:linux-perfetto-rel
Cq-Include-Trybots: luci.chromium.try:android-perfetto-rel
Cq-Include-Trybots: luci.chromium.try:mac-perfetto-rel
Cq-Include-Trybots: luci.chromium.try:win-perfetto-rel