Subject: major revision of kernel 'evcnt' interfaces.
To: None <>
From: Chris G. Demetriou <>
List: tech-kern
Date: 06/01/2000 15:06:10
new manual page below.  Comments?  I've already done the
implementation, and I'd like to commit it no later than next monday or

the number of places the existing 'evcnt' interfaces are used in the
tree is ... small.  (29 places, iirc 7 of which were #if'd out, and
they're all trivial to convert. 8-)

EVCNT(9)                     NetBSD Kernel Manual                     EVCNT(9)

     evcnt, evcnt_attach_dynamic, evcnt_attach_static, evcnt_detach,
     evcnt_incr - generic event counter framework

     #include <sys/device.h>

     evcnt_attach_dynamic(struct evcnt *ev, int type,
             const struct evcnt *parent, const char *group, const char *name);

     evcnt_attach_static(struct evcnt *ev);

     evcnt_detach(struct evcnt *ev);

     evcnt_incr(struct evcnt *ev);

     The NetBSD generic event counter framework is designed to provide a flex-
     ible and hierarchical event counting facility, which is useful for track-
     ing system events (including device interrupts).

     The fundamental component of this framework is the evcnt structure, which
     is defined as follows:

     struct evcnt {
             u_int64_t       ev_count;      /* how many have occurred */
             TAILQ_ENTRY(evcnt) ev_list;    /* entry on list of all counters */
             unsigned char   ev_version;    /* version of structure */
             unsigned char   ev_type;       /* counter type; see below */
             unsigned char   ev_grouplen;   /* 'group' len, excluding NUL */
             unsigned char   ev_namelen;    /* 'name' len, excluding NUL */
             const struct evcnt *ev_parent; /* parent, for hierarchical ctrs */
             const char      *ev_group;     /* name of group */
             const char      *ev_name;      /* name of specific event */

     The system maintains a global linked list of all active event counters.
     This list, called allevents, may grow or shrink over time as event coun-
     ters are dynamically added to and removed from the system.

     Each event counter is marked (in the ev_type field) with the type of
     event being counted.  The following types are currently defined:
           EVCNT_TYPE_MISC  Miscellaneous; doesn't fit into one of the other
           EVCNT_TYPE_INTR  Interrupt counter, reported by vmstat -i.

     Each event counter also has a group name (ev_group) and an event name
     (ev_name) which are used to identify the counter.  The group name may be
     shared by a set of counters.  For example, device interrupt counters
     would use the name of the device whose interrupts are being counted as
     the group name.  The counter name is meant to distinguish the counter
     from others in its group.  Both names should be understandable by users,
     since they are printed by commands like vmstat(8).  These strings are
     limited in length to 256 characters (including trailing NUL) by the size
     of the fields used to store their lengths.

     To support hierarchical tracking of events, each event counter can name a
     ``parent'' event counter.  For instance, interrupt dispatch code could
     have an event counter per interrupt line, and devices could each have
     counters for the number of interrupts that they were responsible for
     causing.  In that case, the counter for a device on a given interrupt
     line would have the line's counter as its parent.  The value NULL is be
     used to indicate that a counter has no parent.  A counter's parent must
     be attached before the counter is attached, and detached after the
     counter is detached.

     The EVCNT_INITIALIZER() macro can be used to provide a static initializer
     for an event counter structure.  It is be invoked as
     EVCNT_INITIALIZER(type, parent, group, name), and its arguments will be
     placed into the corresponding fields of the event counter structure it is
     initializing.  The group and name arguments must be constant strings.

     The following is a brief description of each function in the framework:

     void evcnt_attach_dynamic(struct evcnt *ev, int type, const struct evcnt
             *parent, const char *group, const char *name)

             Attach the event counter structure pointed to by ev to the system
             event list.  The event counter is cleared and its fields initial-
             ized using the arguments to the function call.  The contents of
             the remaining elements in the structure (e.g., the name lengths)
             are calculated, and the counter is added to the system event

             The strings specified as the group and counter names must persist
             (with the same value) throughout the life of the event counter;
             they are referenced by, not copied into, the counter.

     void evcnt_attach_static(struct evcnt *ev)

             Attach the statically-initialized event counter structure pointed
             to by ev to the system event list.  The event counter is assumed
             to be statically initialized using the EVCNT_INITIALIZER() macro.
             This function simply calculates structure elements' values as ap-
             propriate (e.g., the string lengths), and adds the counter to the
             system event list.

     void evcnt_detach(struct evcnt *ev)

             Detach the event counter structure pointed to by ev from the sys-
             tem event list.

     void evcnt_incr(struct evcnt *ev)
             Increment the value of the event counter pointer to by ev.  (This
             is actually implemented as a macro.)

             Note that evcnt_incr() does not attempt to provide any locking,
             or otherwise guarantee that the increment will happen atomically.
             The caller must take care to insure that the increment is will be
             done safely with respect to other possible sections of code which
             may also increment the counter.  (The overhead of providing a
             guaranteed-safe, machine-independent mechanism to increment them
             would be too great.  In the extreme, it might involve a per-
             counter lock on some system types, and several function calls per

     This section includes a description on basic use of the framework and ex-
     ample usage of its functions.

     Device drivers can use the evcnt_attach_dynamic() and evcnt_detach()
     functions to manage device-specific event counters.  Statically config-
     ured system modules can use evcnt_attach_static() to configure global
     event counters.  Similarly, loadable modules can use
     evcnt_attach_static() to configure their global event counters,
     evcnt_attach_dynamic() to attach device-specific event counters, and
     evcnt_detach() to detach all counters when being unloaded.

     Device drivers that wish to use the generic event counter framework
     should place event counter structures in their ``softc'' structures.  For
     example, to keep track of the number of interrupts for a given device
     (broken down further into ``device readable'' and ``device writable'' in-
     terrupts) a device driver might use:

     struct foo_softc {
             struct device sc_dev;          /* generic device information */
             [ . . . ]
             struct evcnt sc_ev_intr;       /* interrupt count */
             struct evcnt sc_ev_intr_rd;    /* 'readable' interrupt count */
             struct evcnt sc_ev_intr_wr;    /* 'writable' interrupt count */
             [ . . . ]

     In the device attach function, those counters would be registered with
     the system using the evcnt_attach_dynamic() function, using code like:

     fooattach(parent, self, aux)
             struct device *parent, *self;
             void *aux;
             struct foo_softc *sc = (struct foo_softc *)self;

             [ . . . ]

             /* Initialize and attach event counters. */
             evcnt_attach_dynamic(&sc->sc_ev, EVCNT_TYPE_INTR,
                 NULL, sc->sc_dev.dv_xname, "intr");
             evcnt_attach_dynamic(&sc->sc_ev_rd, EVCNT_TYPE_INTR,
                 &sc->sc_ev, sc->sc_dev.dv_xname, "intr rd");
             evcnt_attach_dynamic(&sc->sc_ev_wr, EVCNT_TYPE_INTR,
                 &sc->sc_ev, sc->sc_dev.dv_xname, "intr wr");

             [ . . . ]

     If the device can be detached from the system, its detach function should
     invoke evcnt_detach() on each attached counter (making sure to detach any
     ``parent'' counters only after detaching all children).

     Code like the following might be used to initialize a static event
     counter (in this example, one used to track CPU alignment traps):

             struct evcnt aligntrap_ev = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
                 NULL, "cpu", "aligntrap")

     To attach this event counter, code like the following could be used:


     This section describes places within the NetBSD source tree where actual
     code implementing or utilizing the event counter framework can be found.
     All pathnames are relative to /usr/src.

     The event counter framework itself is implemented within the file
     sys/kern/subr_autoconf.c.  Data structures and function prototypes for
     the framework are located in sys/sys/device.h.

     Event counters are used throughout the system.

     The vmstat(8) source file usr.bin/vmstat/vmstat.c shows an example of how
     to access event counters from user programs.

     The NetBSD generic event counter framework was designed and implemented
     by Chris Demetriou <cgd@NetBSD.ORG>.


     A set of interrupt counter interfaces with similar names to the inter-
     faces in the NetBSD generic event counter framework appeared as part of
     the new autoconfiguration system in 4.4BSD.  Those interfaces were never
     widely adopted in NetBSD because of limitations in their applicability.
     (Their use was limited to non-hierarchical, dynamically attached device
     interrupt counters.)  The NetBSD generic event counter framework first
     appeared in NetBSD 1.5.

NetBSD 1.4                       May 31, 2000                                4

Chris Demetriou - -
Disclaimer: Not speaking for NetBSD, just expressing my own opinion.