GNU/Linux >> Linux の 問題 >  >> Linux

trace-cmdを使用したカーネルトレース

前回の記事では、ftraceの使用方法を説明しました カーネル関数をトレースします。 ftraceの使用 ファイルの書き込みと読み取りは面倒になる可能性があるため、ラッパーを使用して、トレースの有効化と無効化、フィルターの設定、出力の表示、出力のクリアなどのオプションを含むコマンドを実行しました。

trace-cmdコマンドは、これを行うのに役立つユーティリティです。この記事では、trace-cmdを使用します ftraceで実行したのと同じタスクを実行します 記事。その記事を頻繁に参照しているので、この記事を読む前に読むことをお勧めします。

trace-cmdをインストール

この記事のコマンドをrootユーザーとして実行します。

ftrace メカニズムはカーネルに組み込まれており、次のコマンドで有効になっていることを確認できます:

# mount | grep tracefs
none on /sys/kernel/tracing type tracefs (rw,relatime,seclabel)

ただし、trace-cmdをインストールする必要があります ユーティリティを手動で。

# dnf install trace-cmd -y
利用可能なトレーサーを一覧表示する

ftraceを使用する場合 、ファイルの内容を表示して、使用可能なトレーサーを確認する必要があります。しかし、trace-cmdを使用します 、この情報は次のコマンドで取得できます:

# trace-cmd list -t
hwlat blk mmiotrace function_graph wakeup_dl wakeup_rt wakeup function nop
関数トレーサーを有効にする

以前の記事では、2つのトレーサーを使用しましたが、ここでも同じことを行います。最初のトレーサー、functionを有効にします 、with:

$ trace-cmd start -p function
  plugin 'function'
トレース出力を表示

トレーサーを有効にすると、showを使用して出力を表示できます。 引数。これは、例を短くするために最初の20行のみを示しています(出力の説明については、以前の記事を参照してください):

# trace-cmd show | head -20
## tracer: function
#
# entries-in-buffer/entries-written: 410142/3380032   #P:8
#
#                                _-----=> irqs-off
#                               / _----=> need-resched
#                              | / _---=> hardirq/softirq
#                              || / _--=> preempt-depth
#                              ||| /     delay
#           TASK-PID     CPU#  ||||   TIMESTAMP  FUNCTION
#              | |         |   ||||      |         |
           gdbus-2606    [004] ..s. 10520.538759: __msecs_to_jiffies <-rebalance_domains
           gdbus-2606    [004] ..s. 10520.538760: load_balance <-rebalance_domains
           gdbus-2606    [004] ..s. 10520.538761: idle_cpu <-load_balance
           gdbus-2606    [004] ..s. 10520.538762: group_balance_cpu <-load_balance
           gdbus-2606    [004] ..s. 10520.538762: find_busiest_group <-load_balance
           gdbus-2606    [004] ..s. 10520.538763: update_group_capacity <-update_sd_lb_stats.constprop.0
           gdbus-2606    [004] ..s. 10520.538763: __msecs_to_jiffies <-update_group_capacity
           gdbus-2606    [004] ..s. 10520.538765: idle_cpu <-update_sd_lb_stats.constprop.0
           gdbus-2606    [004] ..s. 10520.538766: __msecs_to_jiffies <-rebalance_domains

トレースを停止し、バッファーをクリアします

トレースは引き続きバックグラウンドで実行され、showを使用して出力を表示し続けることができます 。

トレースを停止するには、trace-cmdを実行します stopで 引数:

# trace-cmd stop

バッファをクリアするには、clearで実行します 引数:

# trace-cmd clear

function_graphトレーサーを有効にする

2番目のトレーサーfunction_graphを有効にします 、実行することにより:

# trace-cmd start -p function_graph
  plugin 'function_graph'

もう一度、showを使用して出力を表示します 口論。予想どおり、出力は最初のトレース出力とわずかに異なります。今回はfunction callsが含まれています チェーン:

# trace-cmd show | head -20
## tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
 4)   0.079 us    |        } /* rcu_all_qs */
 4)   0.327 us    |      } /* __cond_resched */
 4)   0.081 us    |      rcu_read_unlock_strict();
 4)               |      __cond_resched() {
 4)   0.078 us    |        rcu_all_qs();
 4)   0.243 us    |      }
 4)   0.080 us    |      rcu_read_unlock_strict();
 4)               |      __cond_resched() {
 4)   0.078 us    |        rcu_all_qs();
 4)   0.241 us    |      }
 4)   0.080 us    |      rcu_read_unlock_strict();
 4)               |      __cond_resched() {
 4)   0.079 us    |        rcu_all_qs();
 4)   0.235 us    |      }
 4)   0.095 us    |      rcu_read_unlock_strict();
 4)               |      __cond_resched() {

stopを使用します およびclear トレースを停止してバッファをクリアするコマンド:

# trace-cmd stop
# trace-cmd clear
トレースを微調整して深度を増やします

関数呼び出しの詳細を確認したい場合は、トレーサーを微調整できます:

# trace-cmd start -p function_graph --max-graph-depth 5
  plugin 'function_graph'

この出力を以前に見たものと比較すると、ネストされた関数呼び出しがさらに表示されるはずです。

# trace-cmd show | head -20
## tracer: function_graph
#
# CPU  DURATION                  FUNCTION CALLS
# |     |   |                     |   |   |   |
 6)               |        __fget_light() {
 6)   0.804 us    |          __fget_files();
 6)   2.708 us    |        }
 6)   3.650 us    |      } /* __fdget */
 6)   0.547 us    |      eventfd_poll();
 6)   0.535 us    |      fput();
 6)               |      __fdget() {
 6)               |        __fget_light() {
 6)   0.946 us    |          __fget_files();
 6)   1.895 us    |        }
 6)   2.849 us    |      }
 6)               |      sock_poll() {
 6)   0.651 us    |        unix_poll();
 6)   1.905 us    |      }
 6)   0.475 us    |      fput();
 6)               |      __fdget() {
トレースするために利用可能な関数を学ぶ

特定の関数のみをトレースし、残りを無視する場合は、正確な関数名を知っている必要があります。 listで入手できます 引数の後に-fが続く 。この例では、一般的なカーネル関数kmallocを検索します 、カーネルにメモリを割り当てるために使用されます:

# trace-cmd list -f | grep kmalloc
bpf_map_kmalloc_node
mempool_kmalloc
__traceiter_kmalloc
__traceiter_kmalloc_node
kmalloc_slab
kmalloc_order
kmalloc_order_trace
kmalloc_large_node
__kmalloc
__kmalloc_track_caller
__kmalloc_node
__kmalloc_node_track_caller
[...]

テストシステムで使用できる関数の総数は次のとおりです。

# trace-cmd list -f | wc -l
63165
カーネルモジュール関連の関数をトレースします

特定のカーネルモジュールに関連する関数をトレースすることもできます。 kvmをトレースしたいとします。 カーネルモジュール関連の機能。モジュールがロードされていることを確認します:

# lsmod  | grep kvm_intel
kvm_intel             335872  0
kvm                   987136  1 kvm_intel

trace-cmdを実行します もう一度list 引数、および出力から、grep ]で終わる行の場合 。これにより、カーネルモジュールが除外されます。次に、grep カーネルモジュールkvm_intel 、そしてそのカーネルモジュールに関連するすべての関数が表示されるはずです:

# trace-cmd list -f | grep ]$  | grep kvm_intel
vmx_can_emulate_instruction [kvm_intel]
vmx_update_emulated_instruction [kvm_intel]
vmx_setup_uret_msr [kvm_intel]
vmx_set_identity_map_addr [kvm_intel]
handle_machine_check [kvm_intel]
handle_triple_fault [kvm_intel]
vmx_patch_hypercall [kvm_intel]

[...]

vmx_dump_dtsel [kvm_intel]
vmx_dump_sel [kvm_intel]

その他のLinuxリソース

  • Linuxコマンドのチートシート
  • 高度なLinuxコマンドのチートシート
  • 無料のオンラインコース:RHELの技術概要
  • Linuxネットワーキングのチートシート
  • SELinuxチートシート
  • Linuxの一般的なコマンドのチートシート
  • Linuxコンテナとは何ですか?
  • 最新のLinux記事
トレース固有の関数

関心のある関数を見つける方法がわかったので、その知識を例として使用します。以前の記事と同様に、ファイルシステム関連の関数をトレースしてみてください。テストシステムにあるファイルシステムはext4でした 。

この手順は少し異なります。 startの代わりに 、recordを使用してコマンドを実行します 引数の後に、トレースする関数の「パターン」が続きます。また、必要なトレーサーを指定する必要があります。この場合、それはfunction_graphです 。コマンドは、 Ctrl + C でトレースを停止するまで、トレースの記録を続行します 。したがって、数秒後、 Ctrl + Cを押します トレースを停止するには:

# trace-cmd list -f | grep ^ext4_

# trace-cmd record -l ext4_* -p function_graph
  plugin 'function_graph'
Hit Ctrl^C to stop recording
^C
CPU0 data recorded at offset=0x856000
    8192 bytes in size
[...]
記録されたトレースを表示

以前に記録したトレースを表示するには、reportを指定してコマンドを実行します 口論。出力から、フィルターが機能したことは明らかであり、ext4関連の関数トレースのみが表示されます:

# trace-cmd report | head -20
[...]
cpus=8
       trace-cmd-12697 [000] 11303.928103: funcgraph_entry:                   |  ext4_show_options() {
       trace-cmd-12697 [000] 11303.928104: funcgraph_entry:        0.187 us   |    ext4_get_dummy_policy();
       trace-cmd-12697 [000] 11303.928105: funcgraph_exit:         1.583 us   |  }
       trace-cmd-12697 [000] 11303.928122: funcgraph_entry:                   |  ext4_create() {
       trace-cmd-12697 [000] 11303.928122: funcgraph_entry:                   |    ext4_alloc_inode() {
       trace-cmd-12697 [000] 11303.928123: funcgraph_entry:        0.101 us   |      ext4_es_init_tree();
       trace-cmd-12697 [000] 11303.928123: funcgraph_entry:        0.083 us   |      ext4_init_pending_tree();
       trace-cmd-12697 [000] 11303.928123: funcgraph_entry:        0.141 us   |      ext4_fc_init_inode();
       trace-cmd-12697 [000] 11303.928123: funcgraph_exit:         0.931 us   |    }
       trace-cmd-12697 [000] 11303.928124: funcgraph_entry:        0.081 us   |    ext4_get_dummy_policy();
       trace-cmd-12697 [000] 11303.928124: funcgraph_entry:        0.133 us   |    ext4_get_group_desc();
       trace-cmd-12697 [000] 11303.928124: funcgraph_entry:        0.115 us   |    ext4_free_inodes_count();
       trace-cmd-12697 [000] 11303.928124: funcgraph_entry:        0.114 us   |    ext4_get_group_desc();
特定のPIDをトレースする

特定の永続識別子(PID)に関連する関数をトレースするとします。別のターミナルを開き、実行中のシェルのPIDをメモします。

# echo $$
10885

recordを実行します もう一度コマンドを実行し、-Pを使用してPIDを渡します オプション。今回は、ターミナルを実行します(つまり、 Ctrl + C を押さないでください) まだ):

# trace-cmd record -P 10885 -p function_graph
  plugin 'function_graph'
Hit Ctrl^C to stop recording
シェルでいくつかのアクティビティを実行します

特定のPIDでシェルを実行していた他のターミナルに戻り、lsなどのコマンドを実行します。 ファイルを一覧表示するには:

# ls
Temp-9b61f280-fdc1-4512-9211-5c60f764d702
tracker-extract-3-files.1000
v8-compile-cache-1000
[...]

トレースを有効にしたターミナルに戻り、 Ctrl + Cを押します。 トレースを停止するには:

# trace-cmd record -P 10885 -p function_graph
  plugin 'function_graph'
Hit Ctrl^C to stop recording
^C
CPU1 data recorded at offset=0x856000
    618496 bytes in size
[...]

トレースの出力では、左側にPIDとBashシェルが表示され、右側にそれに関連する関数呼び出しが表示されます。これは、トレースを絞り込むのに非常に便利です。

# trace-cmd report  | head -20

cpus=8
          <idle>-0     [001] 11555.380581: funcgraph_entry:                   |  switch_mm_irqs_off() {
          <idle>-0     [001] 11555.380583: funcgraph_entry:        1.703 us   |    load_new_mm_cr3();
          <idle>-0     [001] 11555.380586: funcgraph_entry:        0.493 us   |    switch_ldt();
          <idle>-0     [001] 11555.380587: funcgraph_exit:         7.235 us   |  }
            bash-10885 [001] 11555.380589: funcgraph_entry:        1.046 us   |  finish_task_switch.isra.0();
            bash-10885 [001] 11555.380591: funcgraph_entry:                   |  __fdget() {
            bash-10885 [001] 11555.380592: funcgraph_entry:        2.036 us   |    __fget_light();
            bash-10885 [001] 11555.380594: funcgraph_exit:         3.256 us   |  }
            bash-10885 [001] 11555.380595: funcgraph_entry:                   |  tty_poll() {
            bash-10885 [001] 11555.380597: funcgraph_entry:                   |    tty_ldisc_ref_wait() {
            bash-10885 [001] 11555.380598: funcgraph_entry:                   |      ldsem_down_read() {
            bash-10885 [001] 11555.380598: funcgraph_entry:                   |        __cond_resched() {
試してみてください

これらの簡単な例は、trace-cmdの使用方法を示しています 基になるftraceの代わりに メカニズムは使いやすく、ここでは取り上げなかった多くの機能を含め、豊富な機能を備えています。詳細を確認して改善するには、manページを参照して、他の便利なコマンドを試してください。


Linux
  1. 簡単な例で独自の Linux カーネル モジュールを作成する方法

  2. CentOS / RHEL :Yum によるカーネル更新の除外

  3. GDB と QEMU を使用して Linux カーネルをデバッグするには?

  1. glibc の代わりに libc を使用して Linux ディストリビューションを構築できますか?

  2. QEMU を使用した Linux カーネルのデバッグ

  3. Qemu をカーネル パニック時にエラーで終了させることはできますか?

  1. Linuxカーネルをftraceで分析する

  2. Dpkgでカーネルアップデートをブロックしますか?

  3. カーネル4.10.0-20-genericでモジュールBtusbをロードする際のエラー?