微内核的仪表化版本(procnt -instr)配备了复杂的跟踪和分析机制,允许您实时监视系统的执行。procnt -instr模块可以在单cpu和SMP系统上工作。
procnt -instr模块使用的开销非常少,并且具有非常好的性能——它的速度通常是非仪表化内核(在不记录日志的情况下)速度的98%左右。与这个有用工具所增加的功能和灵活性相比,仪表化内核中额外的代码量(x86系统上大约30 KB)是一个相对较小的代价。根据最终系统的内存需求,您可以选择使用这个特殊的内核作为开发/原型工具,或者作为最终产品中的实际内核。
仪表化的模块是非侵入性的——您不必修改程序的源代码来监视程序如何与内核交互。您可以根据需要跟踪内核与系统中任何正在运行的线程或进程之间的交互(例如,内核调用、状态更改和其他系统活动)的数量或数量。您甚至可以监视中断。在这种情况下,所有这些活动都称为事件。
有关详细信息,请参阅系统分析工具包用户指南。(System Analysis Toolkit User’s Guide)
以下是内核仪表化中涉及的基本任务:
考虑到活动系统中发生的大量活动,内核发出的事件数量可能会非常多(就数据量、处理需求和存储所需的资源而言)。但是您可以轻松地控制发出的数据量。具体地说,您可以:
除了应用各种过滤器来控制事件流,你还可以指定内核可以用来发射事件的两种模式之一:
这里的权衡是速度与信息的权衡:快速模式提供的数据更少,而宽模式为每个事件打包的信息更多。不管采用哪种方式,您都可以轻松地调优系统,因为这些模式是基于每个事件的。
作为fast和wide发射模式区别的一个例子,让我们看看我们可能会看到的MsgSendv()调用条目的信息:
Fast mode data | Number of bytes for the event |
---|---|
Connection ID | 4 bytes |
Message data | 4 bytes (the first 4 bytes usually comprise the header) |
total data | Total emitted: 8 bytes |
Wide mode data | Number of bytes for event |
---|---|
Connection ID | 4 bytes |
# of parts to send | 4 bytes |
# of parts to receive | 4 bytes |
Message data | 4 bytes (the first 4 bytes usually comprise the header) |
Message data | 4 bytes |
Message data | 4 bytes |
tatal data | 24 bytes |
内核可以将所有跟踪事件保存在内部循环缓冲区中,而不是总是将事件发送到外部设备。当满足某个触发条件时,可以通过编程方式将该缓冲区转储到外部设备,这使得它成为一个非常强大的工具,可以用来识别在某些运行时条件下突然出现的难以捉摸的bug。
事件的数据包括一个高精度的时间戳,以及生成事件的CPU的ID号。这些信息有助于您轻松诊断困难的定时问题,这些问题更有可能发生在多处理器系统上。
事件格式还包括CPU平台(如x86、ARM等)和endian类型,便于远程分析(实时或离线)。使用数据解释器,您可以查看数据输出的各种方式,如:
TRACEPRINTER version 0.94
-- HEADER FILE INFORMATION --
TRACE_FILE_NAME:: /dev/shmem/tracebuffer
TRACE_DATE:: Fri Jun 8 13:14:40 2001
TRACE_VER_MAJOR:: 0
TRACE_VER_MINOR:: 96
TRACE_LITTLE_ENDIAN:: TRUE
TRACE_ENCODING:: 16 byte events
TRACE_BOOT_DATE:: Fri Jun 8 04:31:05 2001
TRACE_CYCLES_PER_SEC:: 400181900
TRACE_CPU_NUM:: 4
TRACE_SYSNAME:: QNX
TRACE_NODENAME:: x86quad.gp.qa
TRACE_SYS_RELEASE:: 6.1.0
TRACE_SYS_VERSION:: 2001/06/04-14:07:56
TRACE_MACHINE:: x86pc
TRACE_SYSPAGE_LEN:: 2440
-- KERNEL EVENTS --
t:0x1310da15 CPU:01 CONTROL :TIME msb:0x0000000f, lsb(offset):0x1310d81c
t:0x1310e89d CPU:01 PROCESS :PROCCREATE_NAME
ppid:0
pid:1
name:./procnto-smp-instr
t:0x1310eee4 CPU:00 THREAD :THCREATE pid:1 tid:1
t:0x1310f052 CPU:00 THREAD :THRUNNING pid:1 tid:1
t:0x1310f144 CPU:01 THREAD :THCREATE pid:1 tid:2
t:0x1310f201 CPU:01 THREAD :THREADY pid:1 tid:2
t:0x1310f32f CPU:02 THREAD :THCREATE pid:1 tid:3
t:0x1310f3ec CPU:02 THREAD :THREADY pid:1 tid:3
t:0x1310f52d CPU:03 THREAD :THCREATE pid:1 tid:4
t:0x1310f5ea CPU:03 THREAD :THRUNNING pid:1 tid:4
t:0x1310f731 CPU:02 THREAD :THCREATE pid:1 tid:5
.
.
为了帮助您调整对事件数据流的解释,我们提供了一个库(traceparser),这样您就可以编写自己的自定义事件解释器。
系统分析工具包(SAT)的IDE模块可以作为一个综合的仪表控制和后处理可视化工具。在IDE中,开发人员可以配置所有跟踪事件和模式,然后将日志文件自动传输到远程系统进行分析。作为一种可视化工具,IDE提供了一组丰富的事件和流程筛选器,旨在帮助开发人员快速删除大量事件集,以便只查看感兴趣的事件。
虽然仪表化的内核为仪表化和监视进程、线程和系统状态提供了一种优秀的不引人注目的方法,但是您也可以让您的应用程序主动地影响事件收集过程。通过使用TraceEvent()库调用,应用程序本身可以将定制事件注入跟踪流。这个功能在构建大型、紧密耦合的多组件系统时特别有用。
例如,下面的简单调用将把eventcode,first和second的整数值注入到事件流中:
TraceEvent(_NTO_TRACE_INSERTSUSEREVENT, eventcode, first, second);
你也可以在事件流中注入一个字符串(例如“我的事件”),如下面的代码所示:
#include
#include
/* Code to associate with emitted events */
#define MYEVENTCODE 12
int main(int argc, char **argv) {
printf("My pid is %d \n", getpid());
/* Inject two integer events (26, 1975) */
TraceEvent(_NTO_TRACE_INSERTSUSEREVENT, MYEVENTCODE,
26, 1975);
/* Inject a string event (My Event) */
TraceEvent(_NTO_TRACE_INSERTUSRSTREVENT, MYEVENTCODE,
"My Event");
return 0;
}
由traceprinter数据解释器收集的输出会是这样的:
‘’’
.
.
t:0x38ea737e CPU:00 USREVENT:EVENT:12, d0:26 d1:1975
.
.
.
t:0x38ea7cb0 CPU:00 USREVENT:EVENT:12 STR:“My Event”
‘’’