XRay Instrumentation

版本

1 從 2016-11-08 開始

簡介

XRay 是一種函數呼叫追蹤系統,它結合了編譯器插入的檢測點和一個可以在執行時動態啟用和停用檢測的執行時函式庫。

有關 XRay 的更多高階資訊,請參閱 XRay 白皮書

本文檔描述如何在 LLVM 中使用 XRay。

LLVM 中的 XRay

XRay 由三個主要部分組成

  • 編譯器插入的檢測點。

  • 一個用於在執行時啟用/停用追蹤的執行時函式庫。

  • 一套用於分析追蹤的工具。

    **注意:**自 2018 年 7 月 25 日起,XRay 僅適用於執行 Linux 的以下架構:x86_64、arm7(無 thumb)、aarch64、powerpc64le、mips、mipsel、mips64、mips64el、NetBSD:x86_64、FreeBSD:x86_64 和 OpenBSD:x86_64。

編譯器插入的檢測點以最終生成的二進制檔案中的 nop-sleds 的形式出現,以及一個名為 xray_instr_map 的 ELF 區段,其中包含指向這些檢測點的項目。執行時函式庫依賴於能夠訪問 xray_instr_map 的項目,並在執行時覆蓋檢測點。

使用 XRay

您可以通過以下幾種方式使用 XRay

  • 檢測您的 C/C++/Objective-C/Objective-C++ 應用程式。

  • 使用正確的函數屬性生成 LLVM IR。

本節的其餘部分將介紹這些主要方法,以及稍後如何自訂 XRay 在 XRay 檢測的二進制檔案中的行為。

檢測您的 C/C++/Objective-C 應用程式

為您的應用程式取得 XRay 檢測的最簡單方法是在您的 clang 呼叫中啟用 -fxray-instrument 旗標。

舉例來說

clang -fxray-instrument ...

默認情況下,具有至少 200 條指令(或包含循環)的函數將獲得 XRay 檢測點。您可以通過 -fxray-instruction-threshold= 旗標調整該數字

clang -fxray-instrument -fxray-instruction-threshold=1 ...

可以使用 -fxray-ignore-loops 來停用迴圈偵測,僅使用指令閾值。您也可以使用原始碼層級屬性,特別設定您二進制檔案中的函式,使其始終或永不進行檢測。您可以使用 GCC 風格的屬性或 C++11 風格的屬性來完成此操作。

[[clang::xray_always_instrument]] void always_instrumented();

[[clang::xray_never_instrument]] void never_instrumented();

void alt_always_instrumented() __attribute__((xray_always_instrument));

void alt_never_instrumented() __attribute__((xray_never_instrument));

連結二進制檔案時,您可以手動連結 XRay Runtime Library,或使用 clang 並搭配 -fxray-instrument 旗標自動連結。或者,您可以從 compiler-rt 靜態連結 XRay 執行時程式庫 - 這些封存檔案將採用 libclang_rt.xray-{arch} 的名稱,其中 {arch} 是 clang 支援的助記符 (x86_64、arm7 等)。

LLVM 函式屬性

如果您直接使用 LLVM IR,則可以將 function-instrument 字串屬性添加到您的函式中,以獲得與 C/C++/Objective-C 原始碼層級屬性類似的效果

define i32 @always_instrument() uwtable "function-instrument"="xray-always" {
  ; ...
}

define i32 @never_instrument() uwtable "function-instrument"="xray-never" {
  ; ...
}

您也可以設定 xray-instruction-threshold 屬性,並為函式在被檢測之前應該包含的指令數量提供一個數值字串值。

define i32 @maybe_instrument() uwtable "xray-instruction-threshold"="2" {
  ; ...
}

特殊案例檔案

可以透過使用特殊案例檔案來添加屬性,而不是將它們添加到原始程式碼檔案中。您可以使用此方法從檔案中標記某些函式和類別,使其永遠、始終或使用第一個參數記錄進行檢測。檔案格式如下所述

# Comments are supported
[always]
fun:always_instrument
fun:log_arg1=arg1 # Log the first argument for the function

[never]
fun:never_instrument

可以透過 -fxray-attr-list= 旗標將這些檔案提供給 clang。您可以透過多個旗標實例載入多個檔案。

XRay 執行時程式庫

XRay 執行時程式庫是 compiler-rt 專案的一部分,該專案實作了執行插入檢測點的修補和取消修補的執行時元件。當您使用 clang 連結您的二進制檔案和 -fxray-instrument 旗標時,它將自動連結 XRay 執行時程式庫。

XRay 執行時的預設實作將在 main 啟動之前啟用 XRay 檢測,這適用於壽命較短的應用程式。此實作還會記錄所有函式進入和退出事件,這可能會導致生成的追蹤中包含大量記錄。

此外,預設情況下,XRay 追蹤檔的名稱為 xray-log.XXXXXX,其中 XXXXXX 部分是隨機生成的。

可以透過 XRAY_OPTIONS 環境變數控制這些選項,我們在下方列出了選項及其預設值。

選項

類型

預設值

說明

patch_premain

布林值

false

是否在 main 之前修補檢測點。

xray_mode

const char*

""

main 之前安裝和初始化的預設模式。

xray_logfile_base

const char*

xray-log.

XRay 日誌檔的檔案名基底。

verbosity

int

0

執行時詳細資訊級別。

如果您選擇不使用 XRay 運行時附帶的預設日誌記錄實現,以及/或控制 XRay 工具執行的時間/方式,您可以直接使用 XRay API 來執行此操作。為此,您需要包含來自 compiler-rt xray 目錄的 xray_log_interface.h。我們在下面列出重要的 API 函數。

  • __xray_log_register_mode(...):針對字串模式識別碼註冊日誌記錄實現。該實現是 xray/xray_log_interface.h 中定義的 XRayLogImpl 的實例。

  • __xray_log_select_mode(...):選擇要安裝的模式,與字串模式識別碼相關聯。只有使用 __xray_log_register_mode(...) 註冊的實現才能使用此函數選擇。

  • __xray_log_init_mode(...):此函數允許初始化和重新初始化已安裝的日誌記錄實現。有關詳細資訊,請參閱 xray/xray_log_interface.h,它是 XRay compiler-rt 安裝的一部分。

初始化日誌記錄實現後,可以通過 __xray_log_finalize() 函數完成實現來“停止”它。完成例程與初始化相反。完成後,可以通過 __xray_log_flushLog() 函數清除實現的數據。對於支持內存中處理的實現,這些實現應該註冊一個迭代器函數,以通過 __xray_log_set_buffer_iterator(...) 提供對數據的訪問,從而允許調用 __xray_log_process_buffers(...) 函數的代碼處理內存中的數據。

所有這些都在 xray/xray_log_interface.h 標頭中進行了更好的解釋。

基本模式

XRay 支持一種基本日誌記錄模式,該模式將跟踪應用的執行,並定期附加到單個日誌。可以通過在 XRAY_OPTIONS 環境變數中設置 xray_mode=xray-basic 來安裝/啟用此模式。與 patch_premain=true 結合使用,可以允許從頭到尾跟踪應用程序。

與通過 __xray_log_select_mode(...) 安裝的所有其他模式一樣,可以使用 __xray_log_init_mode(...) 函數配置實現,提供模式字符串和標誌選項。可以在 XRAY_BASIC_OPTIONS 環境變數中提供特定於基本模式的默認值。

飛行數據記錄器模式

XRay 支援一種日誌記錄模式,允許應用程序只捕獲固定大小記憶體的事件。飛行數據記錄器 (FDR) 模式的工作原理非常類似於飛機的「黑盒子」,它不斷將數據記錄到記憶體中一個固定大小的循環緩衝佇列中,並以程式設計方式提供數據,直到緩衝區完成並清空。若要在您的應用程式上使用 FDR 模式,您可以將 XRAY_OPTIONS 環境變數中的 xray_mode 變數設為 xray-fdr。您可以在 XRAY_FDR_OPTIONS 環境變數中提供 FDR 模式實作的其他選項。程式設計配置可以透過呼叫 __xray_log_init_mode("xray-fdr", <configuration string>) 來完成,一旦它被選擇/安裝。

當緩衝區被清空到磁碟時,結果是一個由 XRay FDR 格式 描述的二進制追蹤格式

當 FDR 模式開啟時,它將持續寫入和循環使用記憶體緩衝區,直到日誌記錄實作完成為止,此時可以清空它並在稍後重新初始化。要以程式設計方式執行此操作,我們遵循以下提供的工作流程

// Patch the sleds, if we haven't yet.
auto patch_status = __xray_patch();

// Maybe handle the patch_status errors.

// When we want to flush the log, we need to finalize it first, to give
// threads a chance to return buffers to the queue.
auto finalize_status = __xray_log_finalize();
if (finalize_status != XRAY_LOG_FINALIZED) {
  // maybe retry, or bail out.
}

// At this point, we are sure that the log is finalized, so we may try
// flushing the log.
auto flush_status = __xray_log_flushLog();
if (flush_status != XRAY_LOG_FLUSHED) {
  // maybe retry, or bail out.
}

FDR 模式實作的預設設定將建立名稱與基本日誌實作類似的日誌,但將具有不同的日誌格式。所有追蹤分析工具(以及追蹤讀取程式庫)都將支援所有版本的 FDR 模式格式,因為我們將來會新增更多功能和記錄類型。

**注意:**我們不承諾在更新我們支援的日誌版本時提供永久支援。格式的淘汰將在開發人員郵件清單上宣佈和討論。

追蹤分析工具

我們目前在 LLVM 中有一個追蹤分析工具的雛形,可以在 tools/llvm-xray 目錄中找到。 llvm-xray 工具目前支援以下子命令

  • extract:從二進制文件中提取檢測映射,並以 YAML 格式返回。

  • account:使用各種排序選項和輸出格式(支援 CSV、YAML 和控制台友好的 TEXT)執行基本函數調用統計。

  • convert:將 XRay 日誌文件從一種格式轉換為另一種格式。我們可以將二進制 XRay 追蹤(基本和 FDR 模式)轉換為 YAML、flame-graph 友好的文字格式,以及 Chrome 追蹤檢視器 (catapult) <https://github.com/catapult-project/catapult> 格式。

  • graph:生成 XRay 追蹤中發現的函數之間的函數調用關係的 DOT 圖。

  • stack:從 XRay 追蹤中的函數調用時間線重建函數調用堆疊。

這些子命令使用在 LLVM 發行版中作為 XRay 程式庫一部分的各種程式庫組件。它們是

  • llvm/XRay/Trace.h:一個追蹤讀取程式庫,用於將支援格式的 XRay 追蹤方便地載入到方便的記憶體表示中。所有處理追蹤的分析工具都使用此實作。

  • llvm/XRay/Graph.h:一個半泛型圖形類型,由 graph 子命令使用,方便地表示函數呼叫圖,並將統計數據與邊和頂點相關聯。

  • llvm/XRay/InstrumentationMap.h:一個方便的工具,用於分析 XRay 插樁後的目標文件和二進制文件中的插樁映射。extractstack 子命令使用這個特定的函式庫。

最小化二進制文件大小

XRay 支援多個不同的插樁點,包括 function-entryfunction-exitcustomtyped 點。這些點可以使用 -fxray-instrumentation-bundle= 標誌單獨啟用。例如,如果您只想插樁函數入口和自訂點,您可以指定

clang -fxray-instrument -fxray-instrumentation-bundle=function-entry,custom ...

這將完全省略其他 sled 類型,減少二進制文件大小。您也可以使用插樁群組僅插樁函數的抽樣子集。例如,要僅插樁四分之一的可用函數,請調用

clang -fxray-instrument -fxray-function-groups=4

將根據函數名稱的雜湊任意選擇一個子集。要對不同的子集進行抽樣,您可以使用 -fxray-selected-function-group= 指定一個群組編號,範圍從 0 到 xray-function-groups - 1。這些選項可以一起使用,以生成具有不同插樁子集的多個二進制文件。如果您只需要在執行時控制哪些函數被追蹤,那麼最好使用 XRay 執行時函式庫的 __xray_patch_function() 方法選擇性地修補和取消修補您需要的函數。

未來的工作

目前正在進行許多工作,以擴展圍繞 XRay 插樁系統構建的工具集。

追蹤分析工具

  • 目前正在努力整合或開發工具,以視覺化 XRay 追蹤的結果。特別是,stack 工具正在擴展,以輸出允許繪製圖表和探索每個呼叫堆疊中時間長度的格式。

  • 對於大型插樁二進制文件,生成的 XRay 追蹤的大小可能會很快變得難以處理。我們正在努力整合修剪技術和啟發式方法,以便分析工具篩選追蹤並僅顯示相關信息。

更多平台

我們期待將 XRay 移植到更多架構和操作系統的貢獻。