代码运行到观测点的时候,产生事件、事件匹配规则。
如果事件满足事件规则,则LTTng emit this event.
目前有两类event:
什么叫满足规则:
LTTng Tracepoint: 利用LTTng-modules的宏在内核源码或者模块中静态定义的点。
内核系统调用,监控进出口
kprobe: 通过地址或者符号名 来挂在已经编译好的内核上。
Linux user space probe: 通过内核 动态的把探针放在编译好的用户程序或者库的函数入口,现在支持USDT
kretprobe: 通过地址或者符号名,监控 内核函数进出口
满足条件执行动作
条件:
动作:
每一个用户可以有一个session daemon,在这之下有很多recording session。
用户通过操作recording session来操作trace。
各种属性封装在recording session中,相互隔离。
每个用户可以有自己的一系列 recording session。也相互隔离。
实际上是根据不同的Tracer来划分,在设置event rule的时候应该指定,以避免可能的观测点重名造成的歧义。
Linux kernel和User space可以自己建立channel,其他的都只有默认单独一个channel。
每个channel有一系列 ring buffer.
在“create channel”的时候可以指定的属性:
每个channel对于每个cpu都有至少一个ring buffer。哪个CPU释放的event,就记录在哪个对应的ring buffer里。
user space channel有两种scheme:
per-user buffering
每个用户在每个channel里有一组自己的ring buffer
per-process buffering
每个用户在每个channel里,对应于每个被监控进程,有一组ring buffer。就是说,用户在某个channel里有几个被监控进程,就有几组ring buffer。每个ring buffer只记录对应CPU上对应被监控进程的情况。
第二种scheme显然比第一种更占内存,但是第一种可能会存在某些被监控进程将ring buffer占满让别人没法记录的情况。第二种所有的进程都是自己用自己的buffer.不会互相影响。
对于内核空间来讲,整个系统只有一套ring buffer
当 LTTng 发出事件时,LTTng 可以将其记录到特定通道的环形缓冲区内的特定可用子缓冲区中。当子缓冲区中没有剩余空间时,跟踪程序将其标记为可消耗,另一个可用的子缓冲区开始接收以下事件记录。
consumer daemon 吃掉被标记的sub-buffer数据后,该sub-buffer状态回归可用。
上图,环形的每一段是一个sub-buffer。整个是一个ring buffer。红色的满了,标记后等待被消耗。
默认的,对内核和用户空间的tracer是不会阻塞的,他们认为丢失数据可接受,否则可能会导致影响被监测对象本身的执行。性能的重要性远高于数据完整性。
从LTTng 2.10 开始,LTTng-UST加入了对blocking mode的支持。可以设置阻塞超时。
对于丢失数据,也有两种丢失的模式:
Discard mode
新到的数据直接丢弃,并记录丢失event数量以供分析。在设置block timeout的情况下只能用这种方式。
Overwrite mode
将最老的sub-buffer整个清空然后写入数据。
从LTTng-2.8开始,LTTng在每个sub-buffer种写序号,这样reader在发现序号不连续了,就可以分析丢了多少数据。
这种模式不记录丢失的event数量。
应选择哪种机制取决于您的上下文:优先处理环形缓冲区中最新或最旧的事件记录?
并且,sub-buffer 数量 大小之类的都可调节,来优化数据丢失和内存使用。
在标记当前sub buffer为满并切换sub buffer的时候会带来较大的cpu开销。据此,下面有一些具体的配置范式:
High event throughput
较大的sub buffer有助于降低event丢失风险。也可以降低sub buffer切换频率。
sub buffer数量只在overwrite模式下有意义。这样,在覆盖某个buffer的时候其他的可以保持不变。
low event throughput
在lttng发出event的频率本身不高的情况下,因为丢失记录的风险不高,可以使用较小的sub buffer.buffer switch也少,buffer小了也不会造成性能消耗。
low memory system
如果系统的内存较少,有限制,还是建议先选择较少的sub buffer。而尽量保留较大的sub buffer。这种配置。也就是说优先削减数量,而不是单个buffer的大小。这样避免频繁的buffer切换。
平均内核event记录的大小只有32bytes. sub-buffer有1MB就可以认为是大的了。
在overwrite 模式下,sub buffer数量多,体积小,被覆盖的话数据丢失少,但是切换多CPU小号多,可以权衡一下,
但是在discard模式下,设计sub buffer的数量毫无意义,你就使用两个sub buffer,只用根据需求考虑buffer的大小就行了
默认 trace数据文件可以无限大。
可以在create channel的时候设计单个文件的最大值。
这样一个文件写满了,会新建一个文件继续写,文件名会包含文件计数。
如果设置了单个文件的大小,默认情况下,文件数量是无限的。你也可以设置最大文件数量。这样当所有文件写满之后,会发生trace file rotation,最老的文件会被覆盖。
每个channel有最多三个可选时钟。
switch timer
定时标记sub buffer可消耗和切换sub buffer。
如果event产出频率很低的话,保证周期地有数据产出。
create channel的时候添加–switch-timer选项。
read timer
默认的是,满了的sub buffer会异步通知consumer daemon 去消耗它。在一些实时性应用中,可以设置这个值,到时间了去检查并消耗所有的可消耗的sub buffer。
channel when you create it with --read-timer
Monitor timer
定时,consumer daemon采样一些channel的统计数据来判断一些触发条件:
如果关掉了这个计时器,触发条件1中的已消耗buffer size会不正确,触发条件2 3永远不会被分析。
Set the period of the monitor timer of a channel when you create it with the --monitor-timer option.
一个event如果被匹配了多个rule,也只记录一次。
As of LTTng 2.13, you cannot remove a recording event rule: it exists as long as its recording session exists.