我正在尝试监视进程在执行过程中调用哪些函数。我的目标是知道一个过程在每个功能中花费了多少时间。函数被推送到堆栈并在函数调用返回时弹出。我想知道内核代码在推送和弹出实际发生的位置。
我在void *stack
中找到了task_struct
字段。我不确定这是否是我要找的领域。如果是,那么知道如何更新它的方法是什么?
我必须编写一个将使用此代码的模块。在这种情况下请帮助我。
答案 0 :(得分:2)
函数被推送到堆栈并在函数调用返回时弹出。我想知道内核代码在推送和弹出实际发生的位置。
它不会发生在内核代码中,它由处理器完成。即当x86汇编CPU找到call
指令时,它会将IP
推送到堆栈,而ret
指令将弹出该值。
您可以使用call
修补内核中的每个ret
和call my_tracing_routine
指令并在那里记录指令指针,而不是将控制传递给原始被调用者/调用者。有一些工具:LTTng,SystemTap和内核接口,如kprobes,ftrace ......这种方法称为跟踪。
但如果补丁所有指令,即使用SystemTap探测器kernel.function("*")
,则会导致性能下降,并可能导致系统崩溃。所以,你不能测量每个函数调用,但你可以测量每个第N个函数调用,并希望你得到相同的结果,但是你需要大示例(即运行几分钟的程序) - 称为 profiling 。
Linux附带了分析器perf
:
# perf record -- dd if=/dev/zero of=/dev/null
...
^C
# perf report
9.75% dd [kernel.kallsyms] [k] __clear_user
6.69% dd [kernel.kallsyms] [k] __audit_syscall_exit
5.61% dd [kernel.kallsyms] [k] fsnotify
4.73% dd [kernel.kallsyms] [k] system_call_after_swapgs
4.37% dd [kernel.kallsyms] [k] system_call
...
您也可以使用-g
来收集呼叫链。默认情况下,perf
使用CPU性能计数器,因此在N个CPU周期后,中断被引发,并且perf处理程序(它已嵌入到内核中)保存IP
。
如果您希望收集堆栈,可以使用SystemTap执行此操作:
# stap --all-modules -e '
probe timer.profile {
if(execname() == "dd") {
println("----");
print_backtrace(); }
}' -c 'dd if=/dev/zero of=/dev/null'
...
----
0xffffffff813e714d : _raw_spin_unlock_irq+0x32/0x3c [kernel]
0xffffffff81047bb9 : spin_unlock_irq+0x9/0xb [kernel]
0xffffffff8104ac68 : get_signal_to_deliver+0x4f0/0x528 [kernel]
0xffffffff8100216f : do_signal+0x48/0x4b1 [kernel]
0xffffffff81002608 : do_notify_resume+0x30/0x63 [kernel]
0xffffffff813edd6a : int_signal+0x12/0x17 [kernel]
在此示例中,SystemTap使用timer.profile
探针附加到perf事件cpu-clock
。为此,它生成,构建和加载内核模块。您可以使用stap -k -p 3