测试生成器¶
在客户端,LNT 带有一系列内置的测试数据生成器。本节重点介绍 LLVM 测试套件(又名夜间测试)生成器,因为它是在 LNT 基础设施中运行的主要测试,但请注意,LNT 还包括针对其他有趣数据片段的测试,例如 Clang 编译时间性能。
LNT 还使添加新的测试数据生成器变得容易,并包含自定义数据导入器(例如,将构建机器构建信息导入)和动态测试数据生成器(例如,利用基础设施绘制图形)的示例。
运行本地服务器¶
设置本地 LNT 服务器以查看测试结果非常有用,无论是个人使用还是在将结果提交到公共服务器之前预览结果。要为测试设置一次性服务器
# Create a new installation in /tmp/FOO.
$ lnt create /tmp/FOO
created LNT configuration in '/tmp/FOO'
...
# Run a local LNT server.
$ lnt runserver /tmp/FOO &> /tmp/FOO/runserver.log &
[2] 69694
# Watch the server log.
$ tail -f /tmp/FOO/runserver.log
* Running on https://127.0.0.1:8000/
...
运行测试¶
内置测试旨在通过 lnt
工具运行。以下工具可用于处理内置测试
lnt showtests
列出可用的测试。测试使用可扩展的架构定义。待办:指向有关如何添加新测试的文档。
lnt runtest [<run options>] <test name> ... test arguments ...
运行指定的测试。run 工具本身接受许多对所有测试通用的选项。最常见的选项是
--submit=<url>
,它指定在测试完成后将结果提交到的服务器。有关可用选项的更多信息,请参阅lnt runtest --help
。其余选项将传递给测试工具本身。这些选项特定于测试,但行为良好的测试应该响应
lnt runtest <test name> --help
。下一节提供了有关内置测试的具体文档。
内置测试¶
LLVM CMake 测试套件¶
llvm 测试套件可以使用 test-suite
内置测试运行。
通过 CMake 和 lit 运行测试套件使用不同的 LNT 测试
rm -rf /tmp/BAR
lnt runtest test-suite \
--sandbox /tmp/BAR \
--cc ~/llvm.obj.64/Release+Asserts/bin/clang \
--cxx ~/llvm.obj.64/Release+Asserts/bin/clang++ \
--use-cmake=/usr/local/bin/cmake \
--use-lit=~/llvm/utils/lit/lit.py \
--test-suite ~/llvm-test-suite \
--cmake-cache Release
由于 CMake 测试套件使用 lit 运行测试并比较其输出,因此 LNT 需要知道 LLVM lit 安装的路径。测试套件在 CMake 缓存中保存一些常见配置。--cmake-cache
标志和 --cmake-define
标志允许您更改 LNT 如何为测试套件运行配置 cmake。
LLVM Makefile 测试套件(又名 LLVM 夜间测试)¶
注意
Makefile 测试套件已弃用。请考虑改用基于 cmake 的 lnt runtest test-suite
模式。它得到积极维护,收集代码大小等其他指标,并具有额外的功能,例如生成和使用 PGO 数据。
nt
内置测试运行 LLVM 测试套件执行和性能测试,采用“夜间测试”配置。此测试允许运行许多不同的应用程序和基准测试(例如,SPEC),使用各种编译选项,以及在几种不同的配置中(例如,使用 LLVM 编译器,如 clang
或 llvm-gcc
,在 LLVM JIT 编译器下运行使用 LLVM lli
位码解释器,或测试新的代码生成器传递)。
nt
测试需要 LLVM 测试套件存储库、一个可工作的 LLVM 编译器以及一个 LLVM 源代码和构建树。目前,预计 LLVM 构建树已在 Release+Asserts 配置中构建。与之前的 NewNightlyTest.pl
不同,nt
工具不会签出或构建任何内容,预计用户会管理他们自己的 LLVM 源代码和构建树。理想情况下,每个组件都应基于相同的 LLVM 版本(除了 LLVM 测试套件),但这并非必需。
测试在用户指定的沙盒目录中运行 LLVM 测试套件构建和执行。默认情况下,每个测试运行将在沙盒中的带时间戳的目录中进行,并将结果保留在周围以进行事后分析。目前,用户负责清理这些目录以管理磁盘空间。
始终预计测试使用树外构建运行 - 这是一个更稳健的模型,允许在许多测试运行之间共享相同的源树。当前的一个限制是,如果执行树内构建,然后执行树外构建,则 LLVM 测试套件存储库将无法正常工作。LLVM 测试套件存储库必须保持原始状态非常重要。
以下命令显示了在本地构建上运行 nt
测试套件的示例
$ rm -rf /tmp/BAR
$ lnt runtest nt \
--sandbox /tmp/BAR \
--cc ~/llvm.obj.64/Release+Asserts/bin/clang \
--cxx ~/llvm.obj.64/Release+Asserts/bin/clang++ \
--llvm-src ~/llvm \
--llvm-obj ~/llvm.obj.64 \
--test-suite ~/llvm-test-suite \
TESTER_NAME \
-j 16
2010-04-17 23:46:40: using nickname: 'TESTER_NAME__clang_DEV__i386'
2010-04-17 23:46:40: creating sandbox: '/tmp/BAR'
2010-04-17 23:46:40: starting test in '/private/tmp/BAR/test-2010-04-17_23-46-40'
2010-04-17 23:46:40: configuring...
2010-04-17 23:46:50: testing...
2010-04-17 23:51:04: loading test data...
2010-04-17 23:51:05: generating report: '/private/tmp/BAR/test-2010-04-17_23-46-40/report.json'
前七个参数都是必需的 - 它们指定沙盒路径、要测试的编译器以及所需源代码和构建的路径。TESTER_NAME
参数用于派生此测试器的名称(与有关正在测试的编译器的一些推断信息结合使用)。此名称用作测试机的简短标识符;通常它应该是机器的主机名或负责测试器的人员的姓名。-j 16
参数是可选的,在这种情况下,它指定测试应使用最多 16 个进程并行运行。
在这种情况下,我们可以从输出中看到测试创建了一个新的沙盒目录,然后在该沙盒中的子目录中运行测试。在测试进行过程中,测试输出了一些有限的摘要信息。完整的详细信息可以在测试构建目录中的 .log 文件中找到(例如,configure.log
和 test.log
)。
最后的测试步骤是在测试目录中生成测试报告。现在可以将此报告直接提交到 LNT 服务器。例如,如果我们有一个像前面描述的那样运行的本地服务器,我们可以运行
$ lnt submit https://127.0.0.1:8000/submitRun \
/tmp/BAR/test-2010-04-17_23-46-40/report.json
STATUS: 0
OUTPUT:
IMPORT: /tmp/FOO/lnt_tmp/data-2010-04-17_16-54-35ytpQm_.plist
LOAD TIME: 0.34s
IMPORT TIME: 5.23s
ADDED: 1 machines
ADDED: 1 runs
ADDED: 1990 tests
COMMITTING RESULT: DONE
TOTAL IMPORT TIME: 5.57s
并在我们的本地服务器上查看结果。
基于 LNT 的 NT 测试模块¶
为了支持更复杂的测试,或者不容易集成到 LLVM 测试套件模块更严格的 SingleSource 或 MultiSource 布局中的测试,nt
内置测试提供了一种机制,用于 LLVM 测试套件测试,这些测试仅定义扩展测试模块。这些测试将用户配置参数传递给测试运行,并期望以 LNT 本地格式返回测试结果。
测试模块通过在 LLVM 测试套件存储库中 LNTBased
根目录的子目录中提供 TestModule
文件来定义。TestModule
文件应是格式良好的 Python 模块,它提供一个 test_class
全局变量,该变量应为 lnt.tests.nt.TestModule
抽象基类的子类。
测试类应覆盖 execute_test
方法,该方法传递一个包含应用于测试执行的 NT 用户参数的选项字典,并且测试应将测试结果作为 lnt.testing.TestSamples
对象列表返回。
execute_test
方法传递以下选项来描述有关模块本身的信息
MODULENAME
- 模块的名称(主要用于生成结构良好的测试名称)。
SRCROOT
- 模块源目录的路径。
OBJROOT
- 模块应用于临时输出(构建产品)的目录的路径。该目录保证存在,但不保证是干净的。
该方法传递以下选项,这些选项适用于如何执行测试
THREADS
- 测试期间要运行的并行进程数。
BUILD_THREADS
- 构建测试(如果适用)时要使用的并行进程数。
该方法传递以下选项,这些选项指定如何以及是否远程执行测试。如果存在任何这些参数,则保证所有参数都存在。
REMOTE_HOST
- 要在其中执行测试的远程机器的主机名。
REMOTE_USER
- 要以其身份登录远程机器的用户。
REMOTE_PORT
- 要连接到的远程机器的端口。
REMOTE_CLIENT
- 用于连接远程机器的兼容rsh
的客户端。
该方法传递以下选项,用于指定如何构建测试
CC
- 要使用的 C 编译器命令。
CXX
- 要使用的 C++ 编译器命令。
CFLAGS
- 用于构建 C 代码的编译器标志。
CXXFLAGS
- 用于构建 C++ 代码的编译器标志。
该方法传递以下可选参数,用于指定用于各种命令的环境
COMPILE_ENVIRONMENT_OVERRIDES
[可选] - 如果给出,则为编译时要使用的env
样式的环境覆盖列表。
LINK_ENVIRONMENT_OVERRIDES
[可选] - 如果给出,则为链接时要使用的env
样式的环境覆盖列表。
EXECUTION_ENVIRONMENT_OVERRIDES
[可选] - 如果给出,则为执行测试时要使用的env
样式的环境覆盖列表。
有关更多信息,请参阅 LLVM 测试套件存储库中 LNT/Examples
目录下的示例测试。
捕获 Linux perf 性能分析信息¶
在测试套件中使用 CMake 驱动程序时,LNT 还可以使用 linux perf 捕获性能分析信息。然后可以通过 LNT webUI 探索这些信息,如 https://blog.llvm.net.cn/2016/06/using-lnt-to-track-performance.html 所示。
要捕获这些性能分析信息,请使用命令行选项 --use-perf=all
。一个使用此选项评估生成代码性能的典型命令行如下所示
lnt runtest test-suite \
--sandbox SANDBOX \
--cc ~/bin/clang \
--use-cmake=/usr/local/bin/cmake \
--use-lit=~/llvm/utils/lit/lit.py \
--test-suite ~/llvm-test-suite \
--benchmarking-only \
--build-threads 8 \
--threads 1 \
--use-perf=all \
--exec-multisample=5 \
--run-under 'taskset -c 1'
二分查找:--single-result
和 --single-result-predicate
¶
基于 CMake 的测试套件的 LNT 驱动程序附带了用于使用 llvmlab bisect
对一致性和性能更改进行二分查找的帮助程序。
llvmlab bisect
是 zorg
存储库的一部分,允许通过构建缓存轻松地对某些谓词进行二分查找。有效使用 llvmlab
的关键是设计一个良好的谓词命令 - 一个在“通过”时退出状态为零,在“失败”时退出状态为非零的命令。
LNT 通常运行一个或多个测试,然后生成测试报告。除非发生内部错误,否则它始终以状态零退出。 --single-result
参数更改了 LNT 的行为 - 它只会运行一个特定的测试,并将谓词应用于该测试的结果以确定 LNT 的退出状态。
--single-result-predicate
参数定义要使用的谓词。这是一个在包含多个预设变量的上下文中执行的 Python 表达式
status
- 布尔值,表示通过或失败(通过为 True,失败为 False)。
exec_time
- 执行时间(请注意,exec
是 Python 中的保留关键字!)
compile
(或compile_time
) - 编译时间
测试返回的任何指标,例如“score”或“hash”,也会添加到上下文中。
默认谓词只是 status
- 因此,这可以用于开箱即用地调试正确性回归。也可以使用更复杂的谓词;例如,exec_time < 3.0
将假设“良好”结果花费的时间少于 3 秒进行二分查找。
使用 llvmlab
调试性能改进的完整示例
llvmlab bisect --min-rev=261265 --max-rev=261369 \
lnt runtest test-suite \
--cc '%(path)s/bin/clang' \
--sandbox SANDBOX \
--test-suite /work/llvm-test-suite \
--use-lit lit \
--run-under 'taskset -c 5' \
--cflags '-O3 -mthumb -mcpu=cortex-a57' \
--single-result MultiSource/Benchmarks/TSVC/Expansion-flt/Expansion-flt \
--single-result-predicate 'exec_time > 8.0'
生成诊断报告¶
测试套件模块可以生成诊断报告,这可能有助于了解基准测试中发生了什么
lnt runtest test-suite \
--sandbox /tmp/BAR \
--cc ~/llvm.obj.64/Release+Asserts/bin/clang \
--cxx ~/llvm.obj.64/Release+Asserts/bin/clang++ \
--use-cmake=/usr/local/bin/cmake \
--use-lit=~/llvm/utils/lit/lit.py \
--test-suite ~/llvm-test-suite \
--cmake-cache Release \
--diagnose --only-test SingleSource/Benchmarks/Stanford/Bubblesort
这将多次运行测试套件,并在报告目录中收集有用的信息。该报告收集了许多内容,例如执行配置文件、编译时间报告、中间文件、二进制文件和构建信息。
交叉编译¶
在使用 cmake 驱动程序的交叉编译设置中运行测试套件的最佳方法是尽可能使用 cmake 内置的交叉编译支持。实际上,推荐的交叉编译方法是使用 cmake 工具链文件(请参阅 https://cmake.com.cn/cmake/help/v3.0/manual/cmake-toolchains.7.html#cross-compiling)
在 X86 机器上针对 AArch64 linux 进行交叉编译的示例命令行如下所示
lnt runtest test-suite \
--sandbox SANDBOX \
--test-suite /work/llvm-test-suite \
--use-lit lit \
--cppflags="-O3" \
--run-under=$HOME/dev/aarch64-emu/aarch64-qemu.sh \
--cmake-define=CMAKE_TOOLCHAIN_FILE:FILEPATH=$HOME/clang_aarch64_linux.cmake
这里的关键部分是 CMAKE_TOOLCHAIN_FILE 定义。由于您正在进行交叉编译,因此您可能需要一个 –run-under 命令,因为生成的二进制文件可能无法在您的开发机器上本地运行,但需要执行其他操作(例如在 qemu 模拟器下运行或将二进制文件传输到开发板)。此处不再详细解释。
在您的工具链文件中,务必指定定义工具链的 cmake 变量必须缓存在 CMakeCache.txt 中,因为 lnt 在需要为 json 报告构建元数据时会从此处读取它们。下面是一个示例。使变量出现在 CMakeCache.txt 中的重要关键字是“CACHE STRING “” FORCE”
$ cat clang_aarch64_linux.cmake
set(CMAKE_SYSTEM_NAME Linux )
set(triple aarch64-linux-gnu )
set(CMAKE_C_COMPILER /home/user/build/bin/clang CACHE STRING "" FORCE)
set(CMAKE_C_COMPILER_TARGET ${triple} CACHE STRING "" FORCE)
set(CMAKE_CXX_COMPILER /home/user/build/bin/clang++ CACHE STRING "" FORCE)
set(CMAKE_CXX_COMPILER_TARGET ${triple} CACHE STRING "" FORCE)
set(CMAKE_SYSROOT /home/user/aarch64-emu/sysroot-glibc-linaro-2.23-2016.11-aarch64-linux-gnu )
set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN /home/user/aarch64-emu/gcc-linaro-6.2.1-2016.11-x86_64_aarch64-linux-gnu )
set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN /home/user/aarch64-emu/gcc-linaro-6.2.1-2016.11-x86_64_aarch64-linux-gnu )