last modified:
08-09-2011
---------------
ref:http://lttng.org/files/ust/manual/ust.html
1.1 UST(Userspace Tracer)
UST是一个带有一系列跟踪用户空间代码的工具的库。
代码可以插入maker或者tracepoint。高性能的无锁tracer记录这些事件到
trace buffer。一个守护进程从这些buffer中获取数据并写到磁盘上。
通过使用无锁缓冲算法,RCU和per-cpu缓冲区,达到了很高的性能。
另外,也特殊注意减少对cache的影响。
1.3 支持的平台
当前UST可以运行在装有Llinux的 x86-32, x86-64和PowerPC 32位体系结构上。
2. 安装
需要安装如下的包:
- ust
包括跟踪库,ustd 守护进程,跟踪控制工具和其他的帮助工具。
仓库:git://git.lttng.org/ust.git
http://git.lttng.org//ust.git
- liburcu
用户空间的read-copy-update 库。
在debian上可用的包是 liburcu-dev
主页: http://lttng.org/urcu
- LTTV
LTTng traces的图形化观察器。
主页:http://lttng.org
liburcu需要首先安装。 UST才可以被编译和安装。LTTV是独立的。
下面,我们安装上面的包。
对于liburcu:
在debian上:#aptitude install liburcu-dev即可
下面看一下,从源码安装:
#wget -c http://lttng.org/files/urcu/userspace-rcu-0.6.4.tar.bz2 //下载包
#tar -jxf userspace-rcu-0.6.4.tar.bz2
#cd userspace-rcu-0.6.4
//#./bootstrap (我们使用tar包安装,跳过这一步)
#./configure
#make
#make install
#ldconfig
OK.
下面开始装UST:
# git clone git://git.lttng.org/ust.git //下载仓库
#aptitude install dh-autoreconf //安装必要的工具
# cd ust
#./bootstrap
#./configure
#make
#make install
#ldconfig
OK
==================
3. Qs
首先,为一个程序装上一个marker。
//foo.c
#include <ust/marker.h>
int main(int argc, char **argv)
{
int v;
char *st;
/* ... set values of v and st ... */
v = 110;
st = "hello, UST";
/* a marker: */
trace_mark(ust, myevent, "firstarg %d secondarg %s", v, st);
/* a marker without arguments: */
trace_mark(ust, myotherevent, MARK_NOARGS);
return 0;
}
生成可执行程序:
#gcc -o foo -lust foo.c
使用usttrace运行程序。
#mkdir /tmp/mytrace
#usttrace -o /tmp/mytrace ./foo
Waiting for ust-consumerd to shutdown...
Trace was output in: /tmp/mytrace
#tree /tmp/mytrace
/tmp/mytrace
├── 21402_147523
│ ├── metadata_0
│ └── ust_0
├── app.log
└── ust-consumerd.log
最后,使用LTTV打开trace。
#lttv-gui -t /tmp/mytrace/21060_900246
或者以字符形式显示在终端:
# lttv -m textDump -t /tmp/mytrace/21402_147523
...
ust.myevent: 102427.849378367 (/tmp/mytrace/21402_147523/ust_0), 0, 0, , , 0, 0x0, MODE_UNKNOWN { firstarg = 110, secondarg = "hello, UST" }
...
待续。。。
09_08_2011
==========
4 检测一个应用程序
为了记录发生在应用程序的事件,这个程序必须被检测(instrumented)。检测点类似于系统调用。
当程序达到检测点,一个事件就会触发。对于能够被检测的代码类型没有什么限制。
多线程程序,信号处理程序等都可以被检测(instrumented)。
有两种API来检测程序:maker 和 tracepoint。marker可以快速添加,通常被用来做临时检测。
tracepoint提供了一种更简洁的适合永久检测(instrumentation)的方法。
4.1 markers
添加一个marker只需要在程序中添加一行。
#include <ust/marker.h>
int main(int argc, char **argv)
{
int v;
char *st;
/* ... set values of v and st ... */
/* a marker: */
trace_mark(main, myevent, "firstarg %d secondarg %s", v, st);
/* another marker without arguments: */
trace_mark(main, myotherevent, MARK_NOARGS);
return 0;
}
调用trace_mark()宏需要至少3个参数。第一个参数,在这里是“main”,是事件目录(event category)的名字。也是事件运行的通道(channel)。第二个参数,"myevent"是事件名字。第三个参数,
是格式化的字符串,声明了事件参数(event argument)的名字和类型。它的格式类似于printf()的格式字符串。
一个marker可以在同一个程序中重复出现。其他Marker可以有相同的名字但是不同的格式化字符串。但是,这会在分析时带来一些混淆。
4.2 tracepoint
tracepoint API使用了Marker,但是它提供更高层的抽象。鉴于Marker体统了有限的类型检查,
tracepoint API提供了更彻底的类型检查和从直接插入格式化字符串到当marker重用时使格式化字符串重复出现。
注意:虽然本例使用mychannel作为通道名字,但是对于当前支持的early tracing 的通道名是ust。
usttrace工具通常使用 early tracing mode. 当使用没有 early tracing的手动模式时,任何通道名字都可以使用。
一个添加了tracepoint的函数:
////ust_test.c
#include "tp.h"
void myfunc()
{
int v = 123;
char *st = "I am in myfunc.";
/* ... set values of v and st ... */
/* a tracepoint: */
trace_mychannel_myevent(v, st);
}
int main(void)
{
myfunc();
return 0;
}
另一个文件 tp.h包含了tracepoint的声明。
#include <ust/tracepoint.h>
DECLARE_TRACE(mychannel_myevent, TP_PROTO(int v, char *st),
TP_ARGS(v, st));
另一个文件,tp.c,包含了tracepoint的定义。
#include <ust/marker.h>
#include "tp.h"
DEFINE_TRACE(mychannel_myevent);
void mychannel_myevent_probe(int v, char *st)
{
trace_mark(mychannel, myevent, "v %d st %s", v, st);
}
static void __attribute__((constructor)) init()
{
register_trace_mychannel_myevent(mychannel_myevent_probe);
// printf("%s called \n", __func__);// 这个函数会被自动调用
}
tp.h和tp.c可以包含其他tracepoint的定义和声明。构造器可以包含其他register_* 调用。
#gcc -o foo -lust tp.h tp.c ust_test.c
#usttrace -o /tmp/newtrace/ ./foo
Waiting for ust-consumerd to shutdown...
Trace was output in: /tmp/newtrace/
#tree newtrace/
newtrace/
├── 24508_519505
│ ├── metadata_0
│ └── ust_0
├── app.log
└── ust-consumerd.log
# lttv -m textDump -t /tmp/newtrace/24508_519505
...
metadata.core_marker_id: 163473.951192646 (/tmp/newtrace/24508_519505/metadata_0), 0, 0, , , 0, 0x0, MODE_UNKNOWN { channel = "ust", name = "myevent", event_id = 1, int = 4, long = 4, pointer = 4, size_t = 4, alignment = 0 }
metadata.core_marker_format: 163473.951202982 (/tmp/newtrace/24508_519505/metadata_0), 0, 0, , , 0, 0x0, MODE_UNKNOWN { channel = "ust", name = "myevent", format = "v %d st %s" }
ust.myevent: 163473.951217604 (/tmp/newtrace/24508_519505/ust_0), 0, 0, , , 0, 0x0, MODE_UNKNOWN { v = 123, st = "I am in myfunc." }
...
5. 记录一个trace
记录一个trace最简单的方法就是使用 /usr/local/bin/usttrace 脚本(你可以打开看看它进行了那些操作)。
usttrace:
- 创建一个守护进程
- 使能所有的marker
- 运行命令行上指定的命令
- 执行完毕,打印出trace保存的位置
#tree newtrace/
newtrace/
├── 24508_519505 // PID_创建的时间戳
│ ├── metadata_0
│ └── ust_0
├── app.log // tracing logs
└── ust-consumerd.log
几个 usttrace可以同时没有冲突地执行。每一个usttrace的实例运行他们自己的守护进程
来收集它创建的进程的事件。
5.2 手动跟踪//???? 这里有些问题没有搞清楚
- 确保通信socket文件夹存在
#mkdir /tmp/ustsocks
- 确保trace要写入文件夹存在
#mkdir /tmp/trace
- 开始运行守护进程
#ustd (./usr/local/bin/ust-consumerd)?????
- 假设我们要trace的程序已经开始运行并且它的pid是24974
- 列出所有可用的marker
#ustctl --list-markers 24974
- 0 表示非活动的marker,1表示活动的marker
{PID: 24974, channel/marker: metadata/core_marker_format, state: 1, fmt: "channel %s name %s format %s" (nil)}
{PID: 24974, channel/marker: metadata/core_marker_id, state: 1, fmt: "channel %s name %s event_id %hu int #1u%zu long #1u%zu pointer #1u%zu size_t #1u%zu alignment #1u%u" (nil)}
{PID: 24974, channel/marker: metadata/core_marker_format, state: 1, fmt: "channel %s name %s format %s" (nil)}
{PID: 24974, channel/marker: metadata/core_marker_id, state: 1, fmt: "channel %s name %s event_id %hu int #1u%zu long #1u%zu pointer #1u%zu size_t #1u%zu alignment #1u%u" (nil)}
{PID: 24974, channel/marker: metadata/core_marker_format, state: 1, fmt: "channel %s name %s format %s" (nil)}
{PID: 24974, channel/marker: ust/potential_exec, state: 0, fmt: " " (nil)}
{PID: 24974, channel/marker: ust/myevent, state: 0, fmt: "v %d st %s" (nil)}
- 使能 一个 marker
#ustctl --enable-marker ust/myevent 24974 // 可以再次运行 --list-markers 来检查是否已经使能
- 创建一个trace
#ustctl --create-trace 24974
-- 做些其他事情
-停止 trace
#ustctl --stop-trace 24974 //这里有些问题????
//ustctl[25317/25317]: Error: Failed to stop trace auto for PID 24974
// (in stop_trace() at trace_cmds.c:73)
-销毁trace
#ustctl --destroy-trace 24974
========= 使用 early tracing
early tracing 包括尽早的开始跟踪。这样在程序开始运行到运行跟踪命令之间没有事件丢失。
它可以确保在程序进入main()之前,跟踪就开始了。
使用 early tracing 只要把 环境变量 UST_TRACE 设置为1就可以了。
把UST_AUTOPROBE设置为1就自动使能所有marker。
其他信息,参看 http://lttng.org/files/ust/manual/ust.html