Museum

Home

Lab Overview

Retrotechnology Articles

Online Manuals

⇒ ep(7) — Reliant UNIX 5.44c4

Media Vault

Software Library

Restoration Projects

Artifacts Sought

Related Articles

crash(1M)

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

Typewritten Software • bear@typewritten.org • Edmonds, WA 98026