使用 ftrace

ftrace 是一個調試工具,用於了解 Linux 核心內部發生的情況。以下各節詳細介紹了基本 ftrace 功能、ftrace 與 atrace(捕捉核心事件)的用法以及動態 ftrace。

有關 systrace 不提供的高級 ftrace 功能的詳細信息,請參閱<kernel tree>/Documentation/trace/ftrace.txt處的 ftrace 文件。

使用 atrace 擷取核心事件

atrace ( frameworks/native/cmds/atrace ) 使用 ftrace 擷取核心事件。反過來,systrace.py(或更高版本的Catapult中的 run_systrace.py )使用 adb 在裝置上執行 atrace。 atrace 執行以下操作:

  • 透過設定屬性 ( debug.atrace.tags.enableflags ) 設定使用者模式追蹤。
  • 透過寫入適當的 ftrace sysfs 節點來啟用所需的 ftrace 功能。但是,由於 ftrace 支援更多功能,您可以自行設定一些 sysfs 節點,然後使用 atrace。

除了啟動時追蹤之外,請依靠使用 atrace 將屬性設定為適當的值。該屬性是一個位元掩碼,除了查看相應的標頭(該標頭可能會在 Android 版本之間發生變化)之外,沒有什麼好方法可以確定正確的值。

啟用 ftrace 事件

ftrace sysfs 節點位於/sys/kernel/tracing中,追蹤事件在/sys/kernel/tracing/events中分為幾類。

若要依類別啟用事件,請使用:

echo 1 > /sys/kernel/tracing/events/irq/enable

若要基於每個事件啟用事件,請使用:

echo 1 > /sys/kernel/tracing/events/sched/sched_wakeup/enable

如果透過寫入 sysfs 節點啟用了額外事件,則它們不會被 atrace 重設。 Qualcomm 裝置啟動的常見模式是啟用kgsl (GPU)和mdss (顯示管道)追蹤點,然後使用 atrace 或systrace

adb shell "echo 1 > /sys/kernel/tracing/events/mdss/enable"
adb shell "echo 1 > /sys/kernel/tracing/events/kgsl/enable"
./systrace.py sched freq idle am wm gfx view binder_driver irq workq ss sync -t 10 -b 96000 -o full_trace.html

您也可以在不使用 atrace 或 systrace 的情況下使用 ftrace,當您需要僅內核追蹤(或您已經花時間手動編寫使用者模式追蹤屬性)時,這非常有用。僅運行 ftrace:

  1. 將緩衝區大小設定為足夠大的值以供追蹤:
    echo 96000 > /sys/kernel/tracing/buffer_size_kb
    
  2. 啟用追蹤:
    echo 1 > /sys/kernel/tracing/tracing_on
    
  3. 執行測試,然後停用追蹤:
    echo 0 > /sys/kernel/tracing/tracing_on
    
  4. 轉儲追蹤:
    cat /sys/kernel/tracing/trace > /data/local/tmp/trace_output
    

trace_output 以文字形式給出追蹤。若要使用 Catapult 對其進行視覺化,請從 GitHub 取得Catapult 儲存庫並執行trace2html:

catapult/tracing/bin/trace2html ~/path/to/trace_file

預設情況下,這會將trace_file.html寫入同一目錄中。

關聯事件

同時查看 Catapult 視覺化和 ftrace 日誌通常很有用;例如,某些 ftrace 事件(尤其是特定於供應商的事件)無法透過 Catapult 進行視覺化。然而,Catapult 的時間戳記要么與追蹤中的第一個事件相關,要么與 atrace 轉儲的特定時間戳相關,而原始 ftrace 時間戳則基於 Linux 核心中的特定絕對時鐘來源。

要從 Catapult 事件中尋找給定的 ftrace 事件:

  1. 開啟原始 ftrace 日誌。預設情況下,最新版本的 systrace 中的追蹤是壓縮的:
    • 如果您使用--no-compress擷取了 systrace,則該檔案位於 html 檔案中以 BEGIN TRACE 開頭的部分。
    • 如果沒有,請從Catapult 樹( tracing/bin/html2trace ) 執行 html2trace 以解壓縮追蹤。
  2. 在 Catapult 視覺化中尋找相對時間戳。
  3. 在追蹤的開頭找到包含tracing_mark_sync的行。它應該看起來像這樣:
    <5134>-5134  (-----) [003] ...1    68.104349: tracing_mark_write: trace_event_clock_sync: parent_ts=68.104286
    

    如果此行不存在(或如果您使用 ftrace 而不使用 atrace),則計時將相對於 ftrace 日誌中的第一個事件。
    1. 將相對時間戳記(以毫秒為單位)加到parent_ts中的值(以秒為單位)。
    2. 搜尋新的時間戳。

這些步驟應該讓您親臨(或至少非常接近)活動現場。

使用動態 ftrace

當 systrace 和標準 ftrace 不夠時,還有最後一個可用的方法:動態 ftrace 。動態 ftrace 涉及啟動後重寫核心程式碼,因此出於安全原因,它在生產核心中不可用。然而,2015 年和 2016 年的每一個棘手的效能錯誤最終都是使用動態 ftrace 造成的。它對於偵錯不間斷睡眠特別強大,因為每次點擊觸發不間斷睡眠的函數時,您都可以在核心中取得堆疊追蹤。您還可以調試禁用中斷和搶佔的部分,這對於證明問題非常有用。

若要開啟動態 ftrace,請編輯核心的 defconfig:

  1. 刪除 CONFIG_STRICT_MEMORY_RWX(如果存在)。如果您使用的是 3.18 或更高版本以及 arm64,則它不存在。
  2. 加入以下內容:CONFIG_DYNAMIC_FTRACE=y、CONFIG_FUNCTION_TRACER=y、CONFIG_IRQSOFF_TRACER=y、CONFIG_FUNCTION_PROFILER=y 和 CONFIG_PREEMPT_TRACER=y
  3. 重建並啟動新核心。
  4. 執行以下命令來檢查可用的追蹤器:
    cat /sys/kernel/tracing/available_tracers
    
  5. 確認指令回傳functionirqsoffpreemptoffpreemptirqsoff
  6. 執行以下命令以確保動態 ftrace 正常運作:
    cat /sys/kernel/tracing/available_filter_functions | grep <a function you care about>
    

完成這些步驟後,您就可以使用動態 ftrace、函數分析器、irqsoff 分析器和 preemptoff 分析器。我們強烈建議在使用它們之前閱讀有關這些主題的 ftrace 文檔,因為它們功能強大但很複雜。 irqsoff 和 preemptoff 主要用於確認驅動程式可能將中斷或搶佔關閉時間過長。

函數分析器是解決效能問題的最佳選擇,通常用於尋找函數的呼叫位置。


如果函數分析器中的資料不夠具體,您可以將 ftrace 追蹤點與函數分析器結合。 ftrace 事件可以按照與平常完全相同的方式啟用,並且它們將與您的追蹤交錯。如果您想要偵錯的特定函數偶爾出現長時間不間斷的睡眠,這非常有用:將 ftrace 濾鏡設定為您想要的函數,啟用追蹤點,進行追蹤。您可以使用trace2html解析產生的跟踪,找到所需的事件,然後在原始追蹤中取得附近的堆疊追蹤。

使用鎖定狀態

有時,ftrace 還不夠,您確實需要調試似乎是核心鎖爭用的情況。還有一個值得嘗試的核心選項: CONFIG_LOCK_STAT 。這是最後的手段,因為在 Android 裝置上工作非常困難,因為它會使核心的大小超出大多數裝置的處理能力。

但是,lockstat 使用偵錯鎖定基礎結構,這對於許多其他應用程式很有用。每個從事設備啟動工作的人都應該想出某種方法讓該選項在每個設備上工作,因為有時您想「如果我可以打開LOCK_STAT ,我就可以在五分鐘內確認或反駁這個問題,而不是五天。”


如果您可以使用配置選項啟動內核,則鎖定追蹤類似於 ftrace:

  1. 啟用追蹤:
    echo 1 > /proc/sys/kernel/lock_stat
    
  2. 運行你的測試。
  3. 停用追蹤:
    echo 0 > /proc/sys/kernel/lock_stat
    
  4. 轉儲你的痕跡:
    cat /proc/lock_stat > /data/local/tmp/lock_stat
    

如需解釋結果輸出的協助,請參閱<kernel>/Documentation/locking/lockstat.txt處的 lockstat 文件。

使用供應商追蹤點

首先使用上游追蹤點,但有時您需要使用供應商追蹤點:

  { "gfx",        "Graphics",         ATRACE_TAG_GRAPHICS, {
        { OPT,      "events/mdss/enable" },
        { OPT,      "events/sde/enable" },
        { OPT,      "events/mali_systrace/enable" },
    } },

追蹤點可透過 HAL 服務進行擴展,讓您可以新增裝置特定的追蹤點/類別。 Tracepoints 與 perfetto、atrace/systrace 和裝置上系統追蹤應用程式整合。

用於實作追蹤點/類別的 API 是:

  • listCategories()生成(vec<TracingCategory>類別);
  • enableCategories(vec<string>categories) 生成 (Status 狀態);
  • disableAllCategories() 生成 (Status 狀態);
更多資訊請參考AOSP中的 HAL 定義和預設實作: