systemtap Tutorial 2,Tracing

原文:https://sourceware.org/systemtap/tutorial/2_Tracing.html

2 Tracing

       最简单地使用 systemTap 就是跟踪一个事件,比如在程序中插入打印语句。这通常是解决问题的第一步:通过查看发生事情的历史来探索。

        这样比较简单,它只要求SystemTap在每个事件中打印一些内容。要用脚本语言表达这一点,您需要说明在哪里进行探测以及打印什么。

2.1 Where to probe

       SystemTap支持许多内置事件。SystemTap附带的脚本库(每个脚本都称为“Tapset”)可以根据内置系列定义其他脚本。有关这些和许多其他探测点族的详细信息,请参见Stapprobes手册页。所有这些事件都使用统一的语法和点分隔的参数化标识符来命名:

begin

The startup of the systemtap session.
endThe end of the systemtap session.
kernel.function("sys_open")The entry to the function named sys_open in the kernel.
syscall.close.returnThe return from the close system call.
module("ext3").statement(0xdeadbeef)The addressed instruction in the ext3 filesystem driver.
timer.ms(200)A timer that fires every 200 milliseconds.
timer.profileA timer that fires periodically on every CPU.
perf.hw.cache_missesA particular number of CPU cache misses have occurred.
procfs("status").readA process trying to read a synthetic file.
process("a.out").statement("*@main.c:200")

Line 200 of the a.out program.

        假设您希望跟踪源文件中的所有函数条目和出口,比如内核中的 net/socket.c。kernel.function探测点让您可以轻松地表达这一点,因为SystemTap检查内核的调试信息,将对象代码与源代码关联起来。它就像一个调试器:如果可以命名或放置它,就可以对它进行探测。使用 kernel.function(“*@net/socket.c”)。调用函数项1和kernel.function(“*@net/socket.c”)。返回以获取匹配的出口。注意在函数名部分和后面的@filename部分使用通配符。如果要精确地限制搜索,还可以将通配符放入文件名,甚至添加冒号(:)和行号。由于SystemTap将在每个与探测点匹配的地方放置一个单独的探测,一些通配符可以扩展到数百或数千个探测,因此请注意您要求的内容。

        识别探测点后,将显示SystemTap脚本的框架。probe关键字引入一个探测点,或它们的逗号分隔列表。下面的和括号包含所有列出的探测点的处理程序。

       probe kernel.function("*@net/socket.c") { }

       probe kernel.function("*@net/socket.c").return { }

       您可以按原样运行此脚本,但如果处理程序为空,则不会有输出。把这两行放到一个新文件中。运行stap-v文件。随时使用^C终止它。(-v选项告诉SystemTap在处理期间打印更多详细的消息。尝试-h选项查看更多选项。)

2.2 What to print

        由于您对输入和退出的每个函数感兴趣,因此应该为每个函数打印一行,其中包含函数名。为了使该列表易于读取,SystemTap应缩进行,以便其他跟踪函数调用的函数嵌套得更深。要将每个进程与可能同时运行的其他进程区分开来,SystemTap还应在行中打印进程ID。

        SystemTap提供了各种上下文数据,可以进行格式化。它们通常作为函数调用出现在处理程序中,如图[*]中所示。有关这些函数和tapset库中定义的更多内容,请参见函数::*手册页,但下面是一个示例:

tid()

The id of the current thread.
pid()The process (task group) id of the current thread.
uid()The id of the current user.
execname()The name of the current process.
cpu()The current cpu number.
gettimeofday_s()Number of seconds since epoch.
get_cycles()Snapshot of hardware cycle counter.
pp()A string describing the probe point being currently handled.
ppfunc()If known, the the function name in which this probe was placed.
$$varsIf available, a pretty-printed listing of all local variables in scope.
print_backtrace()If possible, print a kernel backtrace.
print_ubacktrace()If possible, print a user-space backtrace.

        返回的值可以是字符串或数字。print()内置函数接受任何一个作为其唯一参数。或者,您可以使用c-style printf()内置的格式参数,其格式参数可能包括字符串的%s,数字的%d。printf和其他函数采用逗号分隔的参数。不要忘了结尾处的“n”。还有更多的打印/格式化功能。

       Tapset库中一个特别方便的功能是线程缩进。给定一个indentation delta参数,它在内部为每个线程存储一个缩进计数器(tid()),并返回一个字符串,其中包含一些通用跟踪数据和适当数量的缩进空间。通用数据包括时间戳(自线程的初始缩进以来的微秒数)、进程名和线程ID本身。因此,它不仅给出了调用哪些函数的概念,还给出了调用这些函数的人,以及调用这些函数需要多长时间。图[*]显示了完成的脚本。它缺少对exit()函数的调用,因此当您希望停止跟踪时,需要用^C中断它。

            

2.3 Exercises

1,使用-l选项systemtap列出所有以单词“nit”命名的内核函数。

2,使用与图[*]中相同的线程缩进探测处理程序跟踪一些系统调用(使用syscall.name和.return探测点)。使用

$$parms和$$return打印参数。解释结果。

3,通过从第一个探测中删除.call修饰符来更改图[*]。注意函数入口和函数返回现在不再匹配了。这是因为现在第一个探针将同时匹配正常函数条目和内联函数。尝试将.call修饰符放回原处,然后添加另一个probe,仅用于probe kernel.function(“*@net/socket.c”)。inline在probe处理程序中可以使用什么printf语句来在.call和.return线程缩进输出之间很好地显示inline函数项?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值