Control the tracing of kernel events
#include <sys/neutrino.h> #include <sys/trace.h> int TraceEvent( int cmd, ... );
Some commands require additional arguments, as described below. In general, the arguments are grouped logically as follows:
TraceEvent(cmd [,class [,event]] [,p1 [,p2 [,p3 ... [,pn]]]])
Aside from the cmd, these arguments are:
There are also “pseudo-classes” defined as a convenience:
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
The TraceEvent() function lets you control all stages of the instrumentation process, including initializing, starting, stopping, controlling filters, and inserting events. These stages are broadly grouped into the following categories:
Filter and mode settings are made regardless of the previous settings. Use care to not accidentally override or delete previous configurations. |
These commands control the buffer setup, and start and stop logging:
TraceEvent(_NTO_TRACE_ALLOCBUFFER, uint bufnum, void** paddr) TraceEvent(_NTO_TRACE_DEALLOCBUFFER)
If your application calls TraceEvent() with these commands, it must run as root. |
The allocation option creates and initializes the instrumented kernel's ring of trace buffers. These buffers hold the emitted trace events. The extra arguments for the _NTO_TRACE_ALLOCBUFFER command are:
Allocated trace buffers can store 1024 simple trace events.
The deallocation option deallocates all of the previously allocated trace buffers. All events stored in the trace buffers are lost.
TraceEvent(_NTO_TRACE_FLUSHBUFFER)
Forces flushing of the buffer regardless of the number of trace events it contains.
TraceEvent(_NTO_TRACE_OVERWRITEBUFFER)
Overwrite the first buffer when the ring overflows.
TraceEvent(_NTO_TRACE_QUERYEVENTS)
Returns the number of simple trace events that are currently stored in the trace buffer.
TraceEvent(_NTO_TRACE_QUERYSUPPORT)
Returns _NTO_TRACE_SUPPINSTR if instrumentation is enabled, or _NTO_TRACE_NOINSTRSUPP if it isn't.
TraceEvent(_NTO_TRACE_QUERYVERSION)
Returns the version of the OS multiplied by 100.
TraceEvent(_NTO_TRACE_SETLINEARMODE) TraceEvent(_NTO_TRACE_SETRINGMODE)
Set the mode for using the trace buffers:
The kernel treats its trace buffers as a ring in either mode.
_NTO_TRACE_SETLINEARMODE and _NTO_TRACE_SETRINGMODE cause the trace buffers to be cleared, so you should use these commands before you start tracing. |
TraceEvent(_NTO_TRACE_SKIPBUFFER)
Skip the first buffer when the ring overflows.
TraceEvent(_NTO_TRACE_START) TraceEvent(_NTO_TRACE_STARTNOSTATE) TraceEvent(_NTO_TRACE_STOP)
These commands start and stop the instrumentation process. The event stream containing the trace events is opened or closed as appropriate.
The _NTO_TRACE_START and _NTO_TRACE_STARTNOSTATE options are similar, except that the latter suppresses the initial system state information (thread IDs and names of processes). This information is overwritten when the kernel reuses the buffer; if you're logging events in ring mode, you can make sure you capture the process names by issuing an _NTO_TRACE_START command followed by _NTO_TRACE_STOP after you've finished tracing.
If an application has called TraceEvent(_NTO_TRACE_START), and you then try to
start tracelogger, tracelogger might fail with a “resource busy” message.
To help avoid this:
|
These commands control whether fast or wide events are emitted:
For more information about fast and wide modes, see the System Analysis Toolkit User's Guide:
TraceEvent(_NTO_TRACE_SETALLCLASSESFAST) TraceEvent(_NTO_TRACE_SETALLCLASSESWIDE)
Sets the fast/wide emitting mode for all classes and events.
TraceEvent(_NTO_TRACE_SETCLASSFAST, int class) TraceEvent(_NTO_TRACE_SETCLASSWIDE, int class)
Sets the fast/wide emitting mode for all events within the specified class.
TraceEvent(_NTO_TRACE_SETEVENTFAST, int class, int event) TraceEvent(_NTO_TRACE_SETEVENTWIDE, int class, int event)
Sets the fast/wide emitting mode for the specified event for the specified class.
These commands control the operation of the static rules filter:
For more information about this filter, see the Filtering chapter in the System Analysis Toolkit User's Guide.
TraceEvent(_NTO_TRACE_ADDALLCLASSES) TraceEvent(_NTO_TRACE_DELALLCLASSES)
Emit/suppress trace events for all classes and events.
TraceEvent(_NTO_TRACE_ADDCLASS, int class) TraceEvent(_NTO_TRACE_DELCLASS, int class)
Emit/suppress all trace events from a specific class.
TraceEvent(_NTO_TRACE_ADDEVENT, int class, int event) TraceEvent(_NTO_TRACE_DELEVENT, int class, int event)
Emit/suppress a trace event from a specific class.
TraceEvent(_NTO_TRACE_SETCLASSPID, int class, pid_t pid) TraceEvent(_NTO_TRACE_CLRCLASSPID, int class) TraceEvent(_NTO_TRACE_SETCLASSTID, int class, pid_t pid, tid_t tid) TraceEvent(_NTO_TRACE_CLRCLASSTID, int class)
Emit/suppress all events from a specified process ID (and thread ID).
The class must be one of the following:
|
TraceEvent(_NTO_TRACE_SETEVENTPID, int class, int event, pid_t pid) TraceEvent(_NTO_TRACE_CLREVENTPID, int class, int event) TraceEvent(_NTO_TRACE_SETEVENTTID, int class, int event, pid_t pid, tid_t tid) TraceEvent(_NTO_TRACE_CLREVENTTID, int class, int event)
Emit/suppress a specific event for a specified process ID (and thread ID).
The class must be one of the following:
|
These commands control the operation of the dynamic rules filter, in which you set up handlers for the events you're interested in:
In order to set up the dynamic rules filter, your application must call ThreadCtl() with the _NTO_TCTL_IO flag to get I/O privileges. |
For more information about this filter, see the Filtering chapter in the System Analysis Toolkit User's Guide.
The only library functions that you can call in your event handler are those that are safe to call from an interrupt handler. For a list of these functions, see the Summary of Safety Information appendix. If you call an unsafe function—such as printf()—in your event handler, you'll crash your entire system. Your event handler must also be reentrant. |
You can access the trace event information from within the event handler by using members of the event_data_t structure.
The layout of the event_data_t structure (declared in <sys/trace.h>) is as follows:
/* event data filled by an event handler */ typedef struct { __traceentry header; /* same as traceevent header */ uint32_t* data_array; /* initialized by the user */ uint32_t el_num; /* number of elements returned */ void* area; /* user data */ uint32_t feature_mask;/* bits indicate valid features */ uint32_t feature[_NTO_TRACE_FI_NUM]; /* feature array - additional data */ } event_data_t;
The event_data_t structure includes a pointer to an
array for the data arguments of the event.
You must provide an array, and it must be large enough to hold the
data for the event or events that you're handling (see the
Current Trace Events and Data
appendix of the System Analysis Toolkit User's Guide).
For example:
event_data_t e_d_1; uint32_t data_array_1[20]; /* 20 elements for potential args. */ e_d_1.data_array = data_array_1; If you don't provide the data array, or it isn't big enough, your data segment could become corrupted. |
You can use the _NTO_TRACE_GET*() macros to extract the class, event, and CPU from the header member. Note that the class and event numbers are internal representations of the _NTO_TRACE_* numbers.
The bits of the member feature_mask are related to any additional features (arguments) that could be accessed inside the event handler. All standard data arguments—the ones that correspond to the data arguments of the trace event—are delivered without changes within the data_array.
There are two constants associated with each additional feature:
The currently defined features are:
Feature | Parameter mask | Index |
---|---|---|
Process ID | _NTO_TRACE_FMPID | _NTO_TRACE_FIPID |
Thread ID | _NTO_TRACE_FMTID | _NTO_TRACE_FITID |
If any particular bit of the feature_mask is set to 1, then you can access the feature corresponding to this bit within the feature array. Otherwise, you must not access the feature.
TraceEvent(_NTO_TRACE_ADDEVENTHANDLER, int class, int event, int (*event_hdlr)(event_data_t*), event_data_t* data_struct) TraceEvent(_NTO_TRACE_DELEVENTHANDLER, int class, int event)
Attaches/deletes the event handler for a specified class and event, where:
In order to emit an event data, a dynamic filter (event handler) has to return a non-zero value. If both types of the dynamic filters (event handler and class event handler) are applicable to a particular event, the event is emitted if both event handlers return non-zero values.
TraceEvent(_NTO_TRACE_ADDCLASSEVHANDLER, int class, int (*event_hdlr)(event_data_t*), event_data_t* data_struct) TraceEvent(_NTO_TRACE_DELCLASSEVHANDLER, int class)
Attaches/deletes the event handler for a specified class, where:
In order to emit an event data, a dynamic filter (event handler) has to return a non-zero value. If both types of the dynamic filters (event handler and class event handler) are applicable to a particular event, the event is emitted if both event handlers return non-zero values.
These commands let you insert your own events into the event stream:
TraceEvent(_NTO_TRACE_INSERTCCLASSEVENT, int class, int event, unsigned *buf, unsigned len) TraceEvent(_NTO_TRACE_INSERTSCLASSEVENT, int class, int event, int data0, int data1)
These commands insert user-created events of a specified class into the event stream. The API handles details such as timestamping.
The len argument represents the number of 32-bit values (not bytes) in buf. |
The trace_logbc() is a convenient cover function for this command.
TraceEvent(_NTO_TRACE_INSERTEVENT, int head, int stamp, int data0, int data1)
Inserts an event of an arbitrary type and class into the event stream. It's powerful, but because the API doesn't do any of the interpretation for you, you should use this function (with care!) only if you're an advanced user. You'll have to modify the data-interpretation program to properly interpret the event.
The arguments are:
Instead of using the _NTO_TRACE_INSERTEVENT command directly, you can use the following convenience functions:
TraceEvent(_NTO_TRACE_INSERTSUSEREVENT, int event, int data0, int data1) TraceEvent(_NTO_TRACE_INSERTCUSEREVENT, int event, unsigned * buf, unsigned len) TraceEvent(_NTO_TRACE_INSERTUSRSTREVENT, int event, const char * str)
These commands insert user-created events into the event stream. Because the API handles details such as timestamping, they're reasonably easy to use. The class is _NTO_TRACE_USER.
The len argument represents the number of 32-bit values (not bytes) in buf. |
The event argument must be in the range from _NTO_TRACE_USERFIRST through _NTO_TRACE_USERLAST, but you can decide what each event means.
Instead of using these commands directly, you can use the following convenience functions:
The value that TraceEvent() returns depends on the value of the cmd argument:
See the Tutorials chapter of the System Analysis Toolkit User's Guide.
Safety: | |
---|---|
Cancellation point | No |
Interrupt handler | Read the Caveats |
Signal handler | Yes |
Thread | Yes |
You can call TraceEvent() from an interrupt/event handler. However, not all commands are valid in this case. The valid commands are:
If you use TraceEvent() to add a dynamic rules filter, the only library functions that you can call in your event handler are those that are safe to call from an interrupt handler.
InterruptAttach(), InterruptHookTrace(), _NTO_TRACE_GET*(), _NTO_TRACE_SET*(), trace_func_enter(), trace_func_exit(), _TRACE_GET_STRUCT(), trace_here(), trace_logb(), trace_logbc(), trace_logf(), trace_logi(), trace_nlogf(), trace_vnlogf()
tracelogger in the Utilities Reference
System Analysis Toolkit User's Guide
Analyzing Your System with Kernel Tracing chapter of the Integrated Development Environment User's Guide