测试生产者¶
在客户端,LNT 自带许多内置的测试数据生产者。本节重点介绍 LLVM 测试套件(又名 nightly test)生成器,因为它是在 LNT 基础设施上运行的主要测试,但请注意,LNT 还包括其他有趣的数据测试,例如 Clang 编译时性能。
LNT 还使添加新的测试数据生产者变得容易,并包括自定义数据导入器(例如,将 buildbot 构建信息导入到)和动态测试数据生成器(例如,滥用基础设施来绘制图表,例如)的示例。
运行本地服务器¶
设置本地 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
列出可用测试。测试使用可扩展架构定义。FIXME:指向关于如何添加新测试的文档。
lnt runtest [<run options>] <test name> ... test arguments ...
运行指定的测试。运行工具本身接受许多所有测试通用的选项。最常见的选项是
--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 Nightly Test)¶
注意
Makefile 测试套件已弃用。请考虑使用基于 cmake 的 lnt runtest test-suite
模式。它正在积极维护,收集额外的指标(如代码大小),并具有额外的功能,例如生成和使用 PGO 数据。
nt
内置测试在“nightly test”配置中运行 LLVM 测试套件执行和性能测试。此测试允许运行许多不同的应用程序和基准测试(例如,SPEC),具有各种编译选项,以及在几种不同的配置中(例如,使用像 clang
或 llvm-gcc
这样的 LLVM 编译器,使用 LLVM lli
位代码解释器在 LLVM JIT 编译器下运行,或测试新的代码生成器 pass)。
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 профили (profile) 信息¶
当在测试套件中使用 CMake 驱动程序时,LNT 还可以使用 linux perf 捕获 профили (profile) 信息。然后可以通过 LNT WebUI 浏览此信息,如 https://blog.llvm.net.cn/2016/06/using-lnt-to-track-performance.html 所示。
要捕获这些 профили (profiles),请使用命令行选项 --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-based 测试套件的 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
这将多次运行测试套件,在报告目录中收集有用的信息。该报告收集许多内容,例如执行 профили (profiles)、编译器时间报告、中间文件、二进制文件和构建信息。
交叉编译¶
在具有 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 )