| EVCNT(9) | Kernel Developer's Manual | EVCNT(9) | 
evcnt, evcnt_attach_dynamic,
  evcnt_attach_static,
  evcnt_detach —
#include <sys/evcnt.h>
void
  
  evcnt_attach_dynamic(struct
    evcnt *ev, int
    type, const struct evcnt
    *parent, const char
    *group, const char
    *name);
void
  
  evcnt_attach_static(struct
    evcnt *ev);
void
  
  evcnt_detach(struct
    evcnt *ev);
The fundamental component of this framework is the evcnt structure. Its user-accessible fields are:
struct evcnt {
	uint64_t	ev_count;	/* how many have occurred */
	TAILQ_ENTRY(evcnt) ev_list;	/* entry on list of all counters */
	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 counters 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_MISCEVCNT_TYPE_INTRvmstat -i.EVCNT_TYPE_TRAPEach 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 (and need not be unique across groups). Both names
    should be understandable by users, since they are printed by commands like
    vmstat(1). The constant
    EVCNT_STRING_MAX is defined to be the maximum group
    or event name length in bytes (including the trailing
    NUL). In the current implementation it is 256.
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 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
    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.
evcnt_attach_dynamic(ev,
    type, parent,
    group, name)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.
evcnt_attach_static(ev)EVCNT_INITIALIZER() macro. This function simply
      calculates structure elements' values as appropriate (e.g., the string
      lengths), and adds the counter to the system event list.evcnt_detach(ev)Note that no method is provided to increment the value of an event counter. Code incrementing an event counter should do so by directly accessing its ev_count field in a manner that is known to be safe. For instance, additions to a device's event counters in the interrupt handler for that device will often be safe without additional protection (because interrupt handler entries for a given device have to be serialized). However, for other uses of event counters, additional locking or use of machine-dependent atomic operation may be appropriate. (The overhead of using a mechanism that is guaranteed to be safe to increment every counter, regardless of actual need for such a mechanism where the counter is being incremented, would be too great. On some systems, it might involve a global lock and several function calls.)
Device drivers can use the
    evcnt_attach_dynamic() and
    evcnt_detach() functions to manage device-specific
    event counters. Statically configured 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” interrupts) a device driver might use:
struct foo_softc {
	[ . . . ]
	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:
void
fooattach(device_t parent, device_t self, void *aux)
{
	struct foo_softc *sc = device_private(self);
	[ . . . ]
	/* Initialize and attach event counters. */
	evcnt_attach_dynamic(&sc->sc_ev, EVCNT_TYPE_INTR,
	    NULL, device_xname(self), "intr");
	evcnt_attach_dynamic(&sc->sc_ev_rd, EVCNT_TYPE_INTR,
	    &sc->sc_ev, device_xname(self), "intr rd");
	evcnt_attach_dynamic(&sc->sc_ev_wr, EVCNT_TYPE_INTR,
	    &sc->sc_ev, device_xname(self), "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:
evcnt_attach_static(&aligntrap_ev);
Event counters are used throughout the system.
The vmstat(1) source file usr.bin/vmstat/vmstat.c shows an example of how to access event counters from user programs.
| January 14, 2011 | NetBSD 9.3 |