ep(7) ep(7)
NAME
ep - event profiler
DESCRIPTION
A problem that often arises when writing a program is that a part of
the program allocates resources, such as memory areas, and then either
does not free these resources at all or frees them several times.
Within the system kernel, the event profiler is the component that
allows the developer to collect information on such resources. These
resources are termed OBJECTS below. Examples of OBJECTS include memory
areas, locks, file descriptors or other items that can be identified
by a unique key.
Various events can occur during the service life of an OBJECT. Stan-
dard events include, for example, creating and freeing an OBJECT.
An example of an OBJECT is a streams message block (msgb). This type
of OBJECT is
- created in the allocb() or dupb() functions,
- processed in the putq(), getq(), putbq() and putnext() functions
and
- freed again in the freeb() function.
The forwarding of a message to another streams module by means of a
putnext() can be very interesting in the case of the debugger and
should therefore also be logged.
The event profiler must be informed of the creation, use and freeing
of the OBJECTS. There are three different types of events here:
- Following creation of a new OBJECTS, the event profiler has to be
informed that information should now be collected for this OBJECT.
The creation event is stored automatically in the process by the
event profiler for the OBJECT. The event profiler stores the ID of
the trace point, or the trace ID, a time stamp and the stack back-
trace of the caller, if no trace-specific data was handed over when
the function was called. In this case, it is possible to store the
values of certain variables in addition to the stack backtrace of
the caller. Based on this information, it is very easy to determine
who created the OBJECT and when.
- Other events can also be stored in the profile of the event pro-
filer. These events are control points at which the system program-
mer can log when and where an OBJECT changed its status or its
position. As is the case when the OBJECT is created, trace-specific
information can also be stored for these events instead of the
stack backtrace of the caller.
Page 1 Reliant UNIX 5.44 Printed 11/98
ep(7) ep(7)
- The event profiler has to be informed if the OBJECT is freed again
(release event). The behavior of the event profiler in the case of
this event depends on its mode. This is described below.
The event profiler can be started in two different modes:
- The history of all OBJECTS created is logged in PROFILING mode.
When an OBJECT is freed, all information stored in the event pro-
filer for this OBJECT is also freed. The time stamps stored by the
event profiler for each event can be used by the system programmers
to find the memory leak. If an OBJECT was created an hour previ-
ously, for example, this is a possible candidate.
- Multiple release can be recognized in MFREE mode. If an OBJECT is
freed, not all information for this OBJECT is freed. Instead, a
release event is stored with the stack backtrace of the caller. If
the OBJECT is freed again, the event profiler can detect this using
this event. A PANIC is normally initiated in this case. The system
programmer can find the first freeing entity based on the stack
backtrace of the caller stored in the release event. The second
freeing entity can be established based on the stack backtrace of
the caller of the process which initiated the PANIC.
The position in the code at which the event profiler is notified of an
event, by one of the ep event functions (see below) being invoked, is
termed a trace point.
The trace points are all given unique numbers to help the developer to
determine which events are of interest in a particular situation;
these trace points are termed trace IDs. The numbers comprise bit
masks in which only a single bit is set. By setting the respective
bits, a global bit mask - the so-called trace mask - can then be used
to determine which trace points are active. The eptracemasks trace
mask [numberofCLIENT] is set using crash(1M) when the event profiler
is initialized in accordance with the mode.
In order to be able to examine several parts of the kernel at the same
time, the event profiler differentiates between so-called CLIENTS. A
CLIENT is a part of the kernel in which trace points have been
integrated for the event profiler. If, for example, an error were to
be found in the kernel space management, a new CLIENT would have to be
defined (see below). Trace points then have to be incorporated in this
part of the kernel. An example of a part of the kernel for which this
has already taken place is Streams.
CLIENTS are identified by means of unique numbers [0, numberofCLIENTS-1].
To create a new CLIENT, a #define statement has to be inserted in
sys/ep.h which assigns such a number to the name of the new CLIENT.
The EPCLIENTLAST #define statement has to be adapted so that it
still specifies the last number used. The start value for the trace
mask for this CLIENT (eptracemasks [newCLIENT number]) must be set
to ~0. This means that all trace points are active.
Page 2 Reliant UNIX 5.44 Printed 11/98
ep(7) ep(7)
The functions that can be used to inform the event profiler of the
events, all have the following parameters in common:
traceid The traceid is a unique number per CLIENT for a specific
trace point.
client client is a unique number for this CLIENT.
key key identifies the OBJECT. The address of a buffer can be
used here, for example struct msgb *bp.
skipcallers skipcallers specifies the number of callers that can be
skipped when storing the stack backtrace of the caller.
This can be very useful if the name of the last caller
contains no further useful information. The value 0 means
that the storage of the stack backtrace of the caller
begins with the caller of the ep function. However, since
this is usually identified on the basis of the trace
point number (trace ID), the value 1 is generally used.
The trace points should always remain integrated in the kernel. This
is the only way to guarantee that the event profiler can be used as
soon as an error occurs. However, to ensure that the trace points do
not take an unnecessary amount of time when the event profiler is dis-
abled, the ep function calls have been encapsulated in #define state-
ments. These only invoke the functions when necessary. Only these mac-
ros should therefore be used (see sys/ep.h). The only difference in
calling the macros and calling the functions is that the macros are
specified in uppercase.
The ep functions are described below:
void epcreate(ulongt traceid, int client, ulongt key,
ulongt maxsize, addrt buf, ulongt len, int skipcallers)
The event profiler is informed that a new OBJECT has been
created. The event profiler automatically stores the creation
event.
maxsize
Maximum number of bytes to be stored as trace-specific data
by any ep function calls within this CLIENT. This number
must be the same for all epcreate() calls within this
CLIENT.
buf Address of trace-specific data or NULL.
len Length of trace-specific data for this event or 0. This
length must of course always be less than maxsize.
Page 3 Reliant UNIX 5.44 Printed 11/98
ep(7) ep(7)
void epdestroy(ulongt traceid, int client, ulongt key, int skipcallers)
The event profiler is informed that the OBJECT has been freed
again.
void eppush(ulongt traceid, int client, ulongt key,
addrt buf, int len, int skipcallers)
A further event is stored in the event profiler.
buf Address of trace-specific data or NULL.
len Length of trace-specific data for this event or 0. This
length must of course always be less than the maxsize used
with epcreate().
A further function is also made available in addition to these event
functions:
int epgetcallers(int client, ulongt *buf, int skipcallers)
You can use this function to store the stack backtrace of the
caller in a trace-specific data buffer. The function specifies
the number of stored callers. If fewer callers could be stored
than configured for this CLIENT using crash, the remainder is
filled with NULL.
buf Address of a buffer in which the stack backtrace of the
caller is to be stored.
CLIENT: Streams
Streams is an initial CLIENT, for which trace points have been
integrated. The event profiler aims to detect when memory is being
leaked or when Streams message blocks are freed twice. The following
trace points have been integrated for this purpose:
Page 4 Reliant UNIX 5.44 Printed 11/98
ep(7) ep(7)
______________________________________
| Function Trace ID Event function|
|_____________________________________|
| allocb 0x1 epcreate() |
| dupb 0x2 epcreate() |
| getq 0x4 eppush() |
| getq 0x8 eppush() |
| putq 0x10 eppush() |
| putbq 0x20 eppush() |
| putnext 0x40 eppush() |
| freeb 0x80 epdestroy() |
| freeb 0x100 epdestroy() |
| freeb 0x200 epdestroy() |
| freeb 0x400 epdestroy() |
| freeb 0x800 epdestroy() |
| freeb 0x1000 epdestroy() |
|_____________________________________|
Since freeb() contains six different calls for freemsgblock() and
freemdbblock(), there are six different trace IDs for freeb() in the
above list.
EXAMPLES
To identify a Streams message block, you need the address of the data
header as well as the address of the message header. Consequently,
Streams uses special macros which store the address of the data header
in the trace-specific data buffers in addition to the stack backtrace
of the caller:
#define EPPROFILING
#ifdef EPPROFILING
#include "sys/ep.h"
#define ME EPCLIENTSTREAMS
#define EPSTRINITBUF(mp)\
epclntstreamst buf;\
int n = epgetcallers(ME, &buf.stk[0], 1);\
buf.datab = (ulongt)(((struct msgb *)(mp))->bdatap)
#define EPSTRNEW(mask, mp)\
if (epactive[ME]) {\
EPSTRINITBUF(mp);\
epcreate(mask, ME, (ulongt)(mp), (n+1) * sizeof(ulongt),\
(addrt)&buf, (n+1) * sizeof(ulongt), 0);\
}
#define EPSTRLOG(mask, mp)\
if (epclients[ME]) {\
EPSTRINITBUF(mp);\
eppush(mask, ME, (ulongt)(mp), (addrt)&buf,\
(n+1) * sizeof(ulongt), 0);\
}
Page 5 Reliant UNIX 5.44 Printed 11/98
ep(7) ep(7)
#define EPSTRDELETE(mask, mp)\
if (epclients[ME])\
epdestroy(mask, ME, (ulongt)mp, 1);
#endif
A trace point in freeb() would then look as follows, for example:
...
EPSTRDELETE(0x80, bp);
freemsgblock(bp);
SEE ALSO
crash(1M).
Page 6 Reliant UNIX 5.44 Printed 11/98