1 概念
1.1 功能
LTT是一个用于跟踪系统详细运行状态和流程的工具,它可以跟踪记录系统中的特定事件。这些事件包括:
系统调用的进入和退出
陷阱/中断(Trap / Irq)的进入和退出
进程调度事件
内核定时器
进程管理相关事件:创建 ,唤醒,信号处理等等
文件系统相关事件:Open / Read / Write / Seek / Ioctl 等等
内存管理相关事件:内存分配/释放等
其他事件:IPC / Socket/ 网络 等等
此外 Ltt还提供了自定义和记录需要跟踪的事件类型的函数接口。
1.2 结构
LTT主要由4个部分组成:
内核代码补丁:LTT目前还没有纳入正式的官方内核,在内核中的部分代码需要打Patch来获得,主要是修改了上述各类事件的相关代码,添加了Trace的调用代码
内核模块:Trace功能的主要实现部分,记录内核事件,并和用户空间的守护进程进行交互
用户空间的守护进程:从LTT的内核模块中获取事件相关数据,并写入文件。
数据分析应用程序:读取守护进程生成的数据文件,加以分析,并以更加可读的方式(图表等)显示出来。
除此之外,LTT还具备自定义和跟踪用户空间事件的能力。
2 使用
所有的安转使用相关的内容,都可以在LTT的官方站点:http://www.opersys.com/ltt/ 找到。仔细阅读里面的文档即可。
(不过,其稳定版本在我这编译起来居然有Error,修改过一些代码后,编译通过,有很多warning,或许是我的编译环境有问题,最终试用的时候图省事,没有去过多研究,使用了Montavista的Package中现成编译好的版本 8 )
3 体会
LTT的确是一个很有用的工具,灵活的配合其他工具的使用,如strace,time等等,可以作为分析优化系统的performance的一个可行的途径。
值得一提的是,LTT可以通过设置参数,在特定的时间段,筛选所需要记录的事件类型,还可以按进程ID等选择所跟踪的特定对象,通过合理的配置参数,可以使得其对系统所造成的额外负担减少到一个合理的程度,对系统性能的分析基本不会造成明显的干扰因素。
另外LTT提供的自定义和记录需要跟踪的事件类型的函数接口,也使它有了一些拓展能力,可以用来Debug自己编写的内核模块代码。
LTT跟踪用户空间事件的实现,是通过其内核模块中几个特定的IOCTL接口,由用户空间的一个LIB库将其包装成函数,使得其使用方法与其在内核模块中自定义和记录事件类型的函数接口相同。应该说这是一个很巧妙的实现办法,不过对其性能个人还是有些怀疑,因为这样一来,对用户空间事件的纪录就需要经由 用户空间-〉内核空间-〉用户空间 走一趟来实现。
inux trace toolkit 并不像strace那样,stace一般都只是针对一个程序的跟踪,不过,linux trace toolkit是用来对整个系统的性能进行trace的工具,这个需要kernel的支持,因此,一般都要对kernel打ltt的补丁。LTT支持的kernel相关的一些event的trace,所谓的trace point即能够被trace的地方:
Event Type | Event Subtype | Event Details |
---|---|---|
System call entry | N/A | System call ID, instruction counter |
System call exit | N/A | None |
Trap entry | N/A | Trap ID, instruction counter |
Trap exit | N/A | None |
Interrupt entry | N/A | Interrupt ID, kernel-space occurrence |
Interrupt exit | N/A | None |
Scheduling change | N/A | Incoming process ID, outgoing process ID, outgoing process state |
Kernel timer | N/A | None |
Soft IRQ | Bottom half | Bottom half ID |
Soft IRQ | Bottom half ID | |
Tasklet action | Address of function | |
Tasklet hi-action | Address of function | |
Process | Creation of kernel thread | Thread start address, PID |
Fork or clone | PID of created process | |
Exit | None | |
Wait | PID waited on | |
Signal | Signal ID, destination PID | |
Wakeup | Process PID, state prior to wakeup | |
File system | Starting to wait for a data buffer | None |
File system | End to the wait for a data buffer | None |
An exec occurred | Filename | |
An open occurred | Filename, file descriptor | |
A close occurred | File descriptor | |
A read occurred | File descriptor, amount read | |
A write occurred | File descriptor, amount written | |
A seek occurred | File descriptor, offset | |
An ioctl occurred | File descriptor, command | |
A select occurred | File descriptor, timeout | |
A poll occurred | File descriptor, timeout | |
Timer | Timer expired | None |
Setting itimer occurred | Type, time | |
Setting schedule timeout occurred | Time | |
Memory | Page allocated | Size order |
Page freed | Size order | |
Swap in | Page address | |
Swap out | Page address | |
Page wait start | None | |
Page wait end | None | |
Socket | Socket call has occurred | Call ID, socket ID |
Socket has been created | Socket type, ID of created socket | |
Data has been sent to a socket | Socket type, amount sent | |
Data has been read for a socket | Socket type, amount received | |
Interprocess communication | System V IPC call | Call ID, object ID |
Message queue has been created | Message queue ID, creation flags | |
Semaphore has been created | Semaphore ID, creation flags | |
Shared memory segment has been created | Shared memory ID, creation flags | |
Network | Incoming packet | Protocol type |
Outgoing packet | Protocol type
|
LTT使用了relayFS技术,这个与proc fs 有点类似,即将kernel的一些信息供用户空间方便的使用,但是有个重要的区别,就是,relayFS旨在提供kernel与user space之间高效快速的大量数据传输的情况。关于relayFS的资料,如下,转载自:
http://www.yuanma.org/data/2006/0927/article_1607.htm
从Linux-2.6.14内核(2.6.12需要打补丁,2.6.13的内核手头没有,不知道)开始,relayfs开始作为内核中File System选项中伪文件系统(Pseudo File System)来出现,这是一个新特性。
File System--->
Pseudo filesystems---->
<>Relayfs File System Support
我们知道,Pseduo File System 另外一个很有名的东西是Proc File System,几乎每个学习Linux的都知道使用这个文件系统来查看cpu型号,内存容量等等其它很多的runtime information。Proc FS为users提供了一个方便的接口来查询很多只有内核才能查看的信息,比如:cpuinfo,meminfo,interrupts等等,这些都只是 kernel管理的对象,但是我们可以以一个普通users的身份也可以查看,proc FS将内核信息可以动态地传递出来,供普通的process随时查看,某些情况下,用户也可以将信息传递到内核空间,比如:echo 1>/proc/sys/net/ipv4/ip_forward。同样地,relayfs也是可以一种内核和用户空间交换数据的工具,不同的是,它支持大容量的数据交换。
relayfs中有一个很重要的概念叫做”channel“,具体来说,一个channel就是由很多个内核的buffer组成的一个集合,这些内核的buffer在relayfs中就体现为一个个的文件。 当kernel中的程序把数据写入某个channel时,这些数据实际上自动填入这些channel的buffer。 用户空间的应用程序mmap()将relayfs中的这些文件做个映射,然后在适当的时候把数据提取出来。
写入channel的数据格式完全取决于最终从channel中提取数据的程序,relayfs可以提取一些hook程序,这些hook程序允许relayfs的数据提取程序(relayfs的客户端)为buffer中的数据增加一些数据结构。这个过程,就像解码跟编码的关系一样,你使用的编码程序和解码程序只有对应就可以,与传输程序无关,当然,你在传输的同时也可以对它进行一些编码,但是这些取决于你最终的解码。 但是,relayfs不提供任何形式的数据过滤,这些任务留给relayfs客户端去完成。 relayfs的设计目标就是尽可能地简单。
每一个relayfs channel都有一个buffer(单CPU情况),每一个buffer又有一个或者多个二级buffer。 消息是从第一个二级buffer开始写入的,直到这个buffer满为止。然后如果第二个二级buffer可用,就写入第二个二级部分反而,一次类推。 所以,如果第一个二级buffer被填满,那么就会通知用户空间,同时,kernel就会去写第二个二级buffer。
如果kernel发出通知说一个二级buffer被填满了,那么kernel肯定知道填了多少字节。userspace根据这个数字就可以仅仅拷贝合法的数据。拷贝完毕,userpsace通知kernel说一个二级buffer已经被使用了。
relayfs采用这么一种模式,它会直接去覆盖数据即使这些数据还没有被userspace所收集。(一个问题,如何保持传输的完整性,目前我也不知道)
下面说说relayfs的user space API:
relayfs为了使得空间程序可以访问channel里面的buffer数据,实现了基本的文件操作。文件操作函数如下:
open 打开一个存在的buffer
mmap 可以使得channel的buffer被映射到调用函数的内存空间,注意,你不能部分映射,而是要映射整个文件。
reald 读取channel buffer的内容
poll 通知用户空间程序二级buffer空间已满
close 关闭
为了使得用户空间的程序可以使用relayfs文件,relayfs必须被mount,格式跟proc差不多,like this:
mount -t relayfs relayfs /mnt/relay/
下面是kernel空间的一些API:
relay_open(base_filename, parent, subbuf_size, n_subbufs, callbacks)
relay_close(chan)
relay_flush(chan)
relay_reset(chan)
relayfs_create_dir(name, parent)
relayfs_remove_dir(dentry)
relayfs_create_file(name, parent, mode, fops, data)
relayfs_remove_file(dentry)
relay_subbufs_consumed(chan, cpu, subbufs_consumed)
relay_write(chan, data, length)
__relay_write(chan, data, length)
relay_reserve(chan, length)
subbuf_start(buf, subbuf, prev_subbuf, prev_padding)
buf_mapped(buf, filp)
buf_unmapped(buf, filp)
create_buf_file(filename, parent, mode, buf, is_global)
remove_buf_file(dentry)