使用 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 日誌通常很有用;例如,Catapult 無法顯示某些 ftrace 事件(尤其是特定於供應商的事件)。但是,Catapult 的時間戳與跟踪中的第一個事件或 atrace 轉儲的特定時間戳相關,而原始 ftrace 時間戳基於 Linux 內核中的特定絕對時鐘源。

從 Catapult 事件中查找給定的 ftrace 事件:

  1. 打開原始 ftrace 日誌。默認情況下,最新版本的 systrace 中的跟踪是壓縮的:
    • 如果您使用--no-compress捕獲了您的 systrace,則它位於以 BEGIN TRACE 開頭的部分的 html 文件中。
    • 如果沒有,請從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解析生成的跟踪,找到所需的事件,然後在原始跟踪中獲取附近的堆棧跟踪。

使用 lockstat

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

但是,lockstat 使用調試鎖定基礎結構,這對許多其他應用程序很有用。每個從事設備啟動工作的人都應該想辦法讓該選項在每個設備上工作,因為有時你想“如果我能打開LOCK_STAT ,我可以在五分鐘內確認或反駁這個問題,而不是五天。”


如果您可以使用 config 選項啟動內核,則鎖定跟踪類似於 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 服務擴展,允許您添加設備特定的跟踪點/類別。跟踪點與 perfetto、atrace/systrace 和設備上的系統跟踪應用程序集成。

用於實現跟踪點/類別的 API 是:

  • listCategories() 生成(vec<TracingCategory> 類別);
  • enableCategories(vec<string> categories) 生成(狀態狀態);
  • disableAllCategories() 生成(狀態狀態);
有關詳細信息,請參閱AOSP中的 HAL 定義和默認實現: