測試產生器

在客戶端,LNT 附帶許多內建的測試數據產生器。本節重點介紹 LLVM 測試套件(又稱夜間測試)產生器,因為它是使用 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 [<執行 選項>] <測試 名稱> ... 測試 參數 ...

執行指定的測試。執行工具本身接受許多所有測試共用的選項。最常見的選項是 --submit=<網址>,它指定在測試完成後要將結果提交到的伺服器。如需可用選項的詳細資訊,請參閱 lnt runtest --help

其餘選項會傳遞給測試工具本身。這些選項是特定於測試的,但良好的測試應該回應 lnt runtest <test name> --help。以下章節提供有關內建測試的特定文件。

內建測試

LLVM CMake 測試套件

可以使用 test-suite 內建測試來執行 llvm 測試套件。

透過 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 編譯器,如 clangllvm-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.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 - 要在其上執行測試的遠端主機名稱。

  • 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 Web UI 瀏覽這些資訊,如 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 的關鍵是設計一個良好的述詞命令 - 一個在「通過」時以零退出,在「失敗」時以非零退出。

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 模擬器下執行,或將二進位檔案傳輸到開發板)。這裡不會進一步說明。

在工具鏈檔案中,重要的是要指定必須在 CMakeCache.txt 中快取定義工具鏈的 cmake 變數,因為 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 )