NAME
evcnt,
evcnt_attach_dynamic,
evcnt_attach_static,
evcnt_detach —
generic event counter framework
SYNOPSIS
#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);
DESCRIPTION
The
NetBSD generic event counter framework is designed
to provide a flexible and hierarchical event counting facility, which is
useful for tracking system events (including device interrupts).
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_MISC
- Miscellaneous; doesn't fit into one of the other
types.
-
-
EVCNT_TYPE_INTR
- Interrupt counter, reported by vmstat
-i.
-
-
EVCNT_TYPE_TRAP
- Processor trap style events.
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 (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.
FUNCTIONS
The following is a brief description of each function in the framework:
-
-
- evcnt_attach_dynamic(ev,
type, parent,
group, name)
- Attach the event counter structure pointed to by
ev to the system event list. The event counter is
cleared and its fields initialized 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
list.
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)
- 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 appropriate (e.g., the string
lengths), and adds the counter to the system event list.
-
-
- evcnt_detach(ev)
- Detach the event counter structure pointed to by
ev from the system event list.
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.)
EXAMPLES
This section includes a description on basic use of the framework and example
usage of its functions.
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);
CODE REFERENCES
The event counter framework itself is implemented within the file
sys/kern/subr_evcnt.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(1) source file
usr.bin/vmstat/vmstat.c shows an example of how to access
event counters from user programs.
SEE ALSO
vmstat(1)
HISTORY
A set of interrupt counter interfaces with similar names to the interfaces 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.
AUTHORS
The
NetBSD generic event counter framework was designed
and implemented by
Chris Demetriou
⟨cgd@NetBSD.org⟩.