宋宝華:Ftraceに関する完全なケース

6557 ワード

本文は転載で,著作権は作者の所有である.商業転載は著者に連絡して許可を得てください.非商業転載は出典を明記してください.
作者:宋宝華
出典:微信公衆番号linuxコードフィールド(id:linuxdev)
Ftraceの概要
FtraceはLinuxがコードレベルの実践分析を行う最も有効なツールの一つであり、例えばシステム呼び出しを行うと、出てくる時間が長すぎて、時間がどこにかかったのか知りたいので、Ftraceを利用して1レベルの時間分布を追跡することができます.
Ftraceケース
procモジュールを書き、procの読み取りと書き込みのエントリを含む.test_proc_show()わざとkillを呼び出したtime()の関数でkill_time()の関数は、mdelay(2)とkill_を呼び出します.moretime()の関数で、この関数はmdelay(2)を呼び出します.
kill_time()の関数とkill_moretime()関数の前にnoinlineが追加され、コンパイラinlineによって最適化されないようにします.
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


static unsigned int variable;
static struct proc_dir_entry *test_dir, *test_entry;


static noinline void kill_moretime(void)
{
mdelay(2);
}


static noinline void kill_time(void)
{
mdelay(2);
kill_moretime();
}


static int test_proc_show(struct seq_file *seq, void *v)
{
unsigned int *ptr_var = seq->private;
kill_time();
seq_printf(seq, "%u
", *ptr_var); return 0; } 
 static ssize_t test_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct seq_file *seq = file->private_data; unsigned int *ptr_var = seq->private; int err; char *kbuffer; 
         if (!buffer || count > PAGE_SIZE - 1)                 return -EINVAL; 
 kbuffer = (char *)__get_free_page(GFP_KERNEL); if (!kbuffer) return -ENOMEM; 
 err = -EFAULT; if (copy_from_user(kbuffer, buffer, count)) goto out; kbuffer[count] = '\0'; 
 *ptr_var = simple_strtoul(kbuffer, NULL, 10); return count; 
 out: free_page((unsigned long)buffer); return err; } 
 static int test_proc_open(struct inode *inode, struct file *file) { return single_open(file, test_proc_show, PDE_DATA(inode)); } 
 static const struct file_operations test_proc_fops = { .owner = THIS_MODULE, .open = test_proc_open, .read = seq_read, .write = test_proc_write, .llseek = seq_lseek, .release = single_release, }; 
 static __init int test_proc_init(void) { test_dir = proc_mkdir("test_dir", NULL); if (test_dir) { test_entry = proc_create_data("test_rw",0666, test_dir, &test_proc_fops, &variable); if (test_entry) return 0; } 
 return -ENOMEM; } module_init(test_proc_init); 
 static __exit void test_proc_cleanup(void) { remove_proc_entry("test_rw", test_dir); remove_proc_entry("test_dir", NULL); } module_exit(test_proc_cleanup); 
 MODULE_AUTHOR("Barry Song "); MODULE_DESCRIPTION("proc exmaple"); MODULE_LICENSE("GPL v2");

モジュールに対応するMakefileは次のとおりです.
KVERS = $(shell uname -r)


# Kernel modules
obj-m += proc.o


# Specify flags for the module compilation.
#EXTRA_CFLAGS=-g -O0


build: kernel_modules


kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules


clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean

コンパイルおよびロード:
$ make
baohua@baohua-perf:~/develop/training/debug/ftrace/proc$ 
$ sudo insmod proc.ko
[sudo] password for baohua: 

その後/procディレクトリの下/proc/test_dir/test_rwファイルは読み書き可能です.
次はFtraceでtestを追跡しますproc_show()という関数.
ftraceを起動するすべてのコマンドをスクリプトfunctionに書きます.shの中:
#!/bin/bash


debugfs=/sys/kernel/debug
echo nop > $debugfs/tracing/current_tracer
echo 0 > $debugfs/tracing/tracing_on
echo $$ > $debugfs/tracing/set_ftrace_pid
echo function_graph > $debugfs/tracing/current_tracer
#replace test_proc_show by your function name
echo test_proc_show > $debugfs/tracing/set_graph_function
echo 1 > $debugfs/tracing/tracing_on
exec "$@"

そしてこのスクリプトでcat/proc/test_を起動しますdir/test_rw、これでftraceの下test_proc_show()関数はtraceされます.
# ./function.sh cat /proc/test_dir/test_rw
0

トレースの結果を読み込みます.# cat /sys/kernel/debug/tracing/trace > 1
次にvimでこのファイル1を開くと、このファイルは600行以上あります.
见えないほど长い!!
Ftrace結果はどう読みますか?
Ftrace結果はどう読みますか?答えはとても簡単です.葉の関数なら、この関数の前に直接時間を表示します.葉でない場合は、}まで待ってから、次の図に時間を表示します.
遅延が大きい部分には、+、#などの特殊な記号があります.
 '$' - greater than 1 second
 '@' - greater than 100 milisecond
 '*' - greater than 10 milisecond
 '#' - greater than 1000 microsecond
 '!' - greater than 100 microsecond
 '+' - greater than 10 microsecond
 ' ' - less than or equal to 10 microsecond.

vimはFtraceを折りたたむ
上のFtraceファイルは大きすぎて、見えないほど大きいです.私たちはvimで折り畳むことができますが、vimの特別な配置が必要です.私はそれを私の~ディレクトリに保存しました.名前は.fungraph-vim:
" Enable folding for ftrace function_graph traces.
"
" To use, :source this file while viewing a function_graph trace, or use vim's
" -S option to load from the command-line together with a trace.  You can then
" use the usual vim fold commands, such as "za", to open and close nested
" functions.  While closed, a fold will show the total time taken for a call,
" as would normally appear on the line with the closing brace.  Folded
" functions will not include finish_task_switch(), so folding should remain
" relatively sane even through a context switch.
"
" Note that this will almost certainly only work well with a
" single-CPU trace (e.g. trace-cmd report --cpu 1).


function! FunctionGraphFoldExpr(lnum)
  let line = getline(a:lnum)
  if line[-1:] == '{'
    if line =~ 'finish_task_switch() {$'
      return '>1'
    endif
    return 'a1'
  elseif line[-1:] == '}'
    return 's1'
  else
    return '='
  endif
endfunction


function! FunctionGraphFoldText()
  let s = split(getline(v:foldstart), '|', 1)
  if getline(v:foldend+1) =~ 'finish_task_switch() {$'
    let s[2] = ' task switch  '
  else
    let e = split(getline(v:foldend), '|', 1)
    let s[2] = e[2]
  endif
  return join(s, '|')
endfunction


setlocal foldexpr=FunctionGraphFoldExpr(v:lnum)
setlocal foldtext=FunctionGraphFoldText()
setlocal foldcolumn=12
setlocal foldmethod=expr

その後vimをこのテンプレートに設定して、前の600行以上のファイルを開きます. vim -S ~/.fungraph-vim 1
私たちが見ている様子は
カーソルを5行目に移動し、キーボードでzaを叩くと、次のように展開できます.
6行目のkill_を展開し続けますtime()を押してza:
Z、aの2つのボタンを使って、Ftraceの結果を検索したり展開したりすることができます.
最後に、https://github.com/brendangre...Ftraceの機能をよくパッケージ化して統合し、perf-toolsでFtraceを使用することをお勧めします.効果はよりよく、より簡単です.
時間があればperf-toolsについて話します.
微信公众号:linux阅码场(id:linuxdev)