測試產生器

在用戶端,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 ...

執行指定的測試。「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 Nightly Test)

注意

Makefile 測試套件已過時。請考慮改用基於 cmake 的 lnt runtest test-suite 模式。它會積極維護,收集額外的指標(例如程式碼大小),並具有額外功能(例如產生和使用 PGO 資料)。

nt 內建測試執行 LLVM 測試套件執行和效能測試,以「nightly test」配置進行。此測試允許執行許多不同的應用程式和基準測試 (例如 SPEC),具有各種編譯選項,並在幾種不同的配置中(例如,使用 LLVM 編譯器,如 clangllvm-gcc,在使用 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 引數用於衍生此測試器的名稱(結合關於受測編譯器的某些推斷資訊)。此名稱用作測試機器的簡短識別碼;通常它應該是機器的hostname或負責測試人員的姓名。-j 16 引數是選用的,在本例中,它指定測試應使用最多 16 個處理程序平行執行。

在本例中,我們可以從輸出中看到測試建立了一個新的沙箱目錄,然後在該沙箱中的子目錄中執行了測試。測試在測試進行中輸出有限的摘要資訊。完整資訊可以在測試建置目錄中的 .log 檔案中找到(例如,configure.logtest.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 - 要在其上執行測試的遠端機器的hostname。

  • 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 瀏覽此資訊,如 http://blog.llvm.org/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 bisectzorg 儲存庫的一部分,允許透過建置快取輕鬆二分搜尋某些述詞。有效使用 llvmlab 的關鍵是設計良好的述詞命令 - 在「pass」時以零退出,在「fail」時以非零退出。

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.dev.org.tw/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 )