前回の記事では、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をメモします。
# 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ページを参照して、他の便利なコマンドを試してください。