查看源代码 LTTng 和 Erlang/OTP
简介
Linux Trace Toolkit:下一代是一个开源系统软件包,用于关联跟踪 Linux 内核、用户应用程序和库。
更多信息,请访问 http://lttng.org
构建支持 LTTng 的 Erlang/OTP
配置并构建支持 LTTng 的 Erlang
为了使 LTTng 与 Erlang/OTP 正常工作,您需要安装以下软件包
- LTTng-tools:用于控制跟踪会话的命令行接口。
- LTTng-UST:用户空间跟踪库。
在 Ubuntu 上,可以通过 aptitude
安装
$ sudo aptitude install lttng-tools liblttng-ust-dev
有关如何在您的系统上安装 LTTng 的更多信息,请参阅 安装 LTTng。
在系统上正确安装 LTTng 后,可以构建支持 LTTng 的 Erlang/OTP。
$ ./configure --with-dynamic-trace=lttng
$ make
Dyntrace 跟踪点
所有跟踪点都在 org_erlang_dyntrace
域中
所有 Erlang 类型在 LTTng 中都是字符串等效项。
process_spawn
pid : string
:: 进程 ID。例如"<0.131.0>"
parent : string
:: 进程 ID。例如"<0.131.0>"
entry : string
:: 代码位置。例如"lists:sort/1"
可以通过 erlang:trace/3
使用跟踪标志 procs
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
process_spawn: { cpu_id = 3 }, { pid = "<0.131.0>", parent = "<0.130.0>", entry = "erlang:apply/2" }
process_link
to : string
:: 进程 ID 或端口 ID。例如"<0.131.0>"
from : string
:: 进程 ID 或端口 ID。例如"<0.131.0>"
type : string
::"link" | "unlink"
可以通过 erlang:trace/3
使用跟踪标志 procs
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
process_link: { cpu_id = 3 }, { from = "<0.130.0>", to = "<0.131.0>", type = "link" }
process_exit
pid : string
:: 进程 ID。例如"<0.131.0>"
reason : string
:: 退出原因。例如"normal"
可以通过 erlang:trace/3
使用跟踪标志 procs
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
process_exit: { cpu_id = 3 }, { pid = "<0.130.0>", reason = "normal" }
process_register
pid : string
:: 进程 ID。例如"<0.131.0>"
name : string
:: 注册名称。例如"logger"
type : string
::"register" | "unregister"
示例
process_register: { cpu_id = 0 }, { pid = "<0.128.0>", name = "dyntrace_lttng_SUITE" type = "register" }
process_scheduled
pid : string
:: 进程 ID。例如"<0.131.0>"
entry : string
:: 代码位置。例如"lists:sort/1"
type : string
::"in" | "out" | "in_exiting" | "out_exiting" | "out_exited"
可以通过 erlang:trace/3
使用跟踪标志 running
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
process_scheduled: { cpu_id = 0 }, { pid = "<0.136.0>", entry = "erlang:apply/2", type = "in" }
port_open
pid : string
:: 进程 ID。例如"<0.131.0>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
port : string
:: 端口 ID。例如"#Port<0.1031>"
可以通过 erlang:trace/3
使用跟踪标志 ports
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
port_open: { cpu_id = 5 }, { pid = "<0.131.0>", driver = "'/bin/sh -s unix:cmd'", port = "#Port<0.1887>" }
port_exit
port : string
:: 端口 ID。例如"#Port<0.1031>"
reason : string
:: 退出原因。例如"normal"
可以通过 erlang:trace/3
使用跟踪标志 ports
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
port_exit: { cpu_id = 5 }, { port = "#Port<0.1887>", reason = "normal" }
port_link
to : string
:: 进程 ID。例如"<0.131.0>"
from : string
:: 进程 ID。例如"<0.131.0>"
type : string
::"link" | "unlink"
可以通过 erlang:trace/3
使用跟踪标志 ports
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
port_link: { cpu_id = 5 }, { from = "#Port<0.1887>", to = "<0.131.0>", type = "unlink" }
port_scheduled
可以通过 erlang:trace/3
使用跟踪标志 running
和 {tracer,dyntrace,[]}
作为跟踪器模块。
port : string
:: 端口 ID。例如"#Port<0.1031>"
entry : string
:: 回调。例如"open"
type : string
::"in" | "out" | "in_exiting" | "out_exiting" | "out_exited"
示例
port_scheduled: { cpu_id = 5 }, { pid = "#Port<0.1905>", entry = "close", type = "out" }
可以通过 erlang:trace/3
使用跟踪标志 running
和 {tracer,dyntrace,[]}
作为跟踪器模块。
function_call
pid : string
:: 进程 ID。例如"<0.131.0>"
entry : string
:: 代码位置。例如"lists:sort/1"
depth : integer
:: 堆栈深度。例如0
可以通过 erlang:trace/3
使用跟踪标志 call
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
function_call: { cpu_id = 5 }, { pid = "<0.145.0>", entry = "dyntrace_lttng_SUITE:'-t_call/1-fun-1-'/0", depth = 0 }
function_return
pid : string
:: 进程 ID。例如"<0.131.0>"
entry : string
:: 代码位置。例如"lists:sort/1"
depth : integer
:: 堆栈深度。例如0
可以通过 erlang:trace/3
使用跟踪标志 call
或 return_to
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
function_return: { cpu_id = 5 }, { pid = "<0.145.0>", entry = "dyntrace_lttng_SUITE:waiter/0", depth = 0 }
function_exception
pid : string
:: 进程 ID。例如"<0.131.0>"
entry : string
:: 代码位置。例如"lists:sort/1"
class : string
:: 错误原因。例如"error"
可以通过 erlang:trace/3
使用跟踪标志 call
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
function_exception: { cpu_id = 5 }, { pid = "<0.144.0>", entry = "t:call_exc/1", class = "error" }
message_send
from : string
:: 进程 ID 或端口 ID。例如"<0.131.0>"
to : string
:: 进程 ID 或端口 ID。例如"<0.131.0>"
message : string
:: 发送的消息。例如"{<0.162.0>,ok}"
可以通过 erlang:trace/3
使用跟踪标志 send
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
message_send: { cpu_id = 3 }, { from = "#Port<0.1938>", to = "<0.160.0>", message = "{#Port<0.1938>,eof}" }
message_receive
to : string
:: 进程 ID 或端口 ID。例如"<0.131.0>"
message : string
:: 收到的消息。例如"{<0.162.0>,ok}"
可以通过 erlang:trace/3
使用跟踪标志 'receive'
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
message_receive: { cpu_id = 7 }, { to = "<0.167.0>", message = "{<0.165.0>,ok}" }
gc_minor_start
pid : string
:: 进程 ID。例如"<0.131.0>"
need : integer
:: 堆需要量。例如2
heap : integer
:: 年轻代堆字大小。例如233
old_heap : integer
:: 老年代堆字大小。例如233
可以通过 erlang:trace/3
使用跟踪标志 garbage_collection
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
gc_minor_start: { cpu_id = 0 }, { pid = "<0.172.0>", need = 0, heap = 610, old_heap = 0 }
gc_minor_end
pid : string
:: 进程 ID。例如"<0.131.0>"
reclaimed : integer
:: 回收的堆空间。例如2
heap : integer
:: 年轻代堆字大小。例如233
old_heap : integer
:: 老年代堆字大小。例如233
可以通过 erlang:trace/3
使用跟踪标志 garbage_collection
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
gc_minor_end: { cpu_id = 0 }, { pid = "<0.172.0>", reclaimed = 120, heap = 1598, old_heap = 1598 }
gc_major_start
pid : string
:: 进程 ID。例如"<0.131.0>"
need : integer
:: 堆需要量。例如2
heap : integer
:: 年轻代堆字大小。例如233
old_heap : integer
:: 老年代堆字大小。例如233
可以通过 erlang:trace/3
使用跟踪标志 garbage_collection
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
gc_major_start: { cpu_id = 0 }, { pid = "<0.172.0>", need = 8, heap = 2586, old_heap = 1598 }
gc_major_end
pid : string
:: 进程 ID。例如"<0.131.0>"
reclaimed : integer
:: 回收的堆空间。例如2
heap : integer
:: 年轻代堆字大小。例如233
old_heap : integer
:: 老年代堆字大小。例如233
可以通过 erlang:trace/3
使用跟踪标志 garbage_collection
和 {tracer,dyntrace,[]}
作为跟踪器模块。
示例
gc_major_end: { cpu_id = 0 }, { pid = "<0.172.0>", reclaimed = 240, heap = 4185, old_heap = 0 }
BEAM 跟踪点
所有跟踪点都在 org_erlang_otp
域中
所有 Erlang 类型在 LTTng 中都是字符串等效项。
driver_init
driver : string
:: 驱动程序名称。例如"tcp_inet"
major : integer
:: 主版本号。例如3
minor : integer
:: 次版本号。例如1
flags : integer
:: 标志。例如1
示例
driver_init: { cpu_id = 2 }, { driver = "caller_drv", major = 3, minor = 3, flags = 1 }
driver_start
pid : string
:: 进程 ID。例如"<0.131.0>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
port : string
:: 端口 ID。例如"#Port<0.1031>"
示例
driver_start: { cpu_id = 2 }, { pid = "<0.198.0>", driver = "caller_drv", port = "#Port<0.3676>" }
driver_output
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
bytes : integer
:: 返回的数据大小。例如82
示例
driver_output: { cpu_id = 2 }, { pid = "<0.198.0>", port = "#Port<0.3677>", driver = "/bin/sh -s unix:cmd", bytes = 36 }
driver_outputv
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
bytes : integer
:: 返回的数据大小。例如82
示例
driver_outputv: { cpu_id = 5 }, { pid = "<0.194.0>", port = "#Port<0.3663>", driver = "tcp_inet", bytes = 3 }
driver_ready_input
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
示例
driver_ready_input: { cpu_id = 5 }, { pid = "<0.189.0>", port = "#Port<0.3637>", driver = "inet_gethost 4 " }
driver_ready_output
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
示例
driver_ready_output: { cpu_id = 5 }, { pid = "<0.194.0>", port = "#Port<0.3663>", driver = "tcp_inet" }
driver_timeout
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
示例
driver_timeout: { cpu_id = 5 }, { pid = "<0.196.0>", port = "#Port<0.3664>", driver = "tcp_inet" }
driver_stop_select
driver : string
:: 驱动程序名称。例如"tcp_inet"
示例
driver_stop_select: { cpu_id = 5 }, { driver = "unknown" }
driver_flush
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
示例
driver_flush: { cpu_id = 7 }, { pid = "<0.204.0>", port = "#Port<0.3686>", driver = "tcp_inet" }
driver_stop
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
示例
driver_stop: { cpu_id = 5 }, { pid = "[]", port = "#Port<0.3673>", driver = "tcp_inet" }
driver_process_exit
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
driver_ready_async
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
示例
driver_ready_async: { cpu_id = 3 }, { pid = "<0.181.0>", port = "#Port<0.3622>", driver = "tcp_inet" }
driver_call
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
command : integer
:: 命令整数值。例如1
bytes : integer
:: 返回的数据大小。例如82
示例
driver_call: { cpu_id = 2 }, { pid = "<0.202.0>", port = "#Port<0.3676>", driver = "caller_drv", command = 0, bytes = 2 }
driver_control
pid : string
:: 进程 ID。例如"<0.131.0>"
port : string
:: 端口 ID。例如"#Port<0.1031>"
driver : string
:: 驱动程序名称。例如"tcp_inet"
command : integer
:: 命令整数值。例如1
bytes : integer
:: 返回的数据大小。例如82
示例
driver_control: { cpu_id = 3 }, { pid = "<0.32767.8191>", port = "#Port<0.0>", driver = "forker", command = 83, bytes = 32 }
carrier_create
type : string
:: 载体类型。例如"ets_alloc"
instance : integer
:: 分配器实例。例如1
size : integer
:: 载体大小。例如262144
mbc_carriers : integer
:: 实例中多块载体的数量。例如3
mbc_carriers_size : integer
:: 实例中多块载体块的总大小。例如1343488
mbc_blocks : integer
:: 实例中多块块的数量。例如122
mbc_blocks_size : integer
:: 实例中所有多块块的总大小。例如285296
sbc_carriers : integer
:: 实例中单块载体的数量。例如1
sbc_carriers_size : integer
:: 实例中单块载体块的总大小。例如1343488
sbc_blocks : integer
:: 实例中单块的数量。例如1
sbc_blocks_size : integer
:: 实例中所有单块的总大小。例如285296
示例
carrier_create: { cpu_id = 2 }, { type = "ets_alloc", instance = 7, size = 2097152, mbc_carriers = 4, mbc_carriers_size = 3440640, mbc_blocks = 526, mbc_blocks_size = 1278576, sbc_carriers = 0, sbc_carriers_size = 0, sbc_blocks = 0, sbc_blocks_size = 0 }
carrier_destroy
type : string
:: 载体类型。例如"ets_alloc"
instance : integer
:: 分配器实例。例如1
size : integer
:: 载体大小。例如262144
mbc_carriers : integer
:: 实例中多块载体的数量。例如3
mbc_carriers_size : integer
:: 实例中多块载体块的总大小。例如1343488
mbc_blocks : integer
:: 实例中多块块的数量。例如122
mbc_blocks_size : integer
:: 实例中所有多块块的总大小。例如285296
sbc_carriers : integer
:: 实例中单块载体的数量。例如1
sbc_carriers_size : integer
:: 实例中单块载体块的总大小。例如1343488
sbc_blocks : integer
:: 实例中单块的数量。例如1
sbc_blocks_size : integer
:: 实例中所有单块的总大小。例如285296
示例
carrier_destroy: { cpu_id = 6 }, { type = "ets_alloc", instance = 7, size = 262144, mbc_carriers = 3, mbc_carriers_size = 3178496, mbc_blocks = 925, mbc_blocks_size = 2305336, sbc_carriers = 0, sbc_carriers_size = 0, sbc_blocks = 0, sbc_blocks_size = 0 }
carrier_pool_put
type : string
:: 载体类型。例如"ets_alloc"
instance : integer
:: 分配器实例。例如1
size : integer
:: 载体大小。例如262144
示例
carrier_pool_put: { cpu_id = 3 }, { type = "ets_alloc", instance = 5, size = 1048576 }
carrier_pool_get
type : string
:: 载体类型。例如"ets_alloc"
instance : integer
:: 分配器实例。例如1
size : integer
:: 载体大小。例如262144
示例
carrier_pool_get: { cpu_id = 7 }, { type = "ets_alloc", instance = 4, size = 3208 }
进程跟踪示例
os_mon
及其相关程序的进程跟踪示例。
在 bash shell 中干净启动 lttng。
$ lttng create erlang-demo
Spawning a session daemon
Session erlang-demo created.
Traces will be written in /home/egil/lttng-traces/erlang-demo-20160526-165920
启动启用 lttng 的 Erlang 节点。
$ erl
Erlang/OTP 19 [erts-8.0] [source-4d7b24d] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [lttng]
Eshell V8.0 (abort with ^G)
1>
加载 dyntrace
模块。
1> l(dyntrace).
{module,dyntrace}
现在可以通过 dyntrace 查看所有跟踪点,并且可以通过 lttng list -u
列出。
启用 Erlang 的 process_register LTTng 跟踪点。
$ lttng enable-event -u org_erlang_dyntrace:process_register
UST event org_erlang_dyntrace:process_register created in channel channel0
为新进程启用进程跟踪,并使用 dyntrace
作为跟踪器后端。
2> erlang:trace(new,true,[procs,{tracer,dyntrace,[]}]).
0
启动 LTTng 跟踪。
$ lttng start
Tracing started for session erlang-demo
在 Erlang 中启动 os_mon
应用程序。
3> application:ensure_all_started(os_mon).
{ok,[sasl,os_mon]}
停止 LTTng 跟踪并查看结果。
$ lttng stop
Tracing stopped for session erlang-demo
$ lttng view
[17:20:42.561168759] (+?.?????????) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "<0.66.0>", name = "sasl_sup", type = "register" }
[17:20:42.561215519] (+0.000046760) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "<0.67.0>", name = "sasl_safe_sup", type = "register" }
[17:20:42.562149024] (+0.000933505) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "<0.68.0>", name = "alarm_handler", type = "register" }
[17:20:42.571035803] (+0.008886779) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "<0.69.0>", name = "release_handler", type = "register" }
[17:20:42.574939868] (+0.003904065) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "<0.74.0>", name = "os_mon_sup", type = "register" }
[17:20:42.576818712] (+0.001878844) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "<0.75.0>", name = "disksup", type = "register" }
[17:20:42.580032013] (+0.003213301) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "<0.76.0>", name = "memsup", type = "register" }
[17:20:42.583046339] (+0.003014326) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "<0.78.0>", name = "cpu_sup", type = "register" }
[17:20:42.586206242] (+0.003159903) elxd1168lx9 org_erlang_dyntrace:process_register: \
{ cpu_id = 5 }, { pid = "<0.82.0>", name = "timer_server", type = "register" }