.\" $NetBSD: evcnt.9,v 1.22 2017/07/03 21:28:48 wiz Exp $
.\"
.\" Copyright (c) 2000 Christopher G. Demetriou
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed for the
.\" NetBSD Project. See http://www.NetBSD.org/ for
.\" information about NetBSD.
.\" 4. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )--
.\"
.Dd January 14, 2011
.Dt EVCNT 9
.Os
.Sh NAME
.Nm evcnt ,
.Nm evcnt_attach_dynamic ,
.Nm evcnt_attach_static ,
.Nm evcnt_detach
.Nd generic event counter framework
.Sh SYNOPSIS
.In sys/evcnt.h
.Ft void
.Fn evcnt_attach_dynamic "struct evcnt *ev" \
"int type" "const struct evcnt *parent" "const char *group" "const char *name"
.Ft void
.Fn evcnt_attach_static "struct evcnt *ev"
.Ft void
.Fn evcnt_detach "struct evcnt *ev"
.Sh DESCRIPTION
The
.Nx
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).
.Pp
The fundamental component of this framework is the
.Em evcnt
structure.
Its user-accessible fields are:
.Bd -literal
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 */
};
.Ed
.Pp
The system maintains a global linked list of all active event counters.
This list, called
.Nm allevents ,
may grow or shrink over time as event counters are dynamically
added to and removed from the system.
.Pp
Each event counter is marked (in the
.Fa ev_type
field) with the type of event being counted.
The following types are currently defined:
.Bl -tag -offset indent -width EVCNT_TYPE_MISC
.It Ev EVCNT_TYPE_MISC
Miscellaneous; doesn't fit into one of the other types.
.It Ev EVCNT_TYPE_INTR
Interrupt counter, reported by
.Ic vmstat -i .
.It Ev EVCNT_TYPE_TRAP
Processor trap style events.
.El
.Pp
Each event counter also has a group name
.Pq Fa ev_group
and
an event name
.Pq Fa 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
.Xr vmstat 1 .
The constant
.Dv EVCNT_STRING_MAX
is defined to be the maximum group or event name length in
bytes (including the trailing
.Dv NUL ) .
In the current implementation it is 256.
.Pp
To support hierarchical tracking of events, each event counter can
name a
.Dq 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
.Dv 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.
.Pp
The
.Fn EVCNT_INITIALIZER
macro can be used to provide a static initializer for an event
counter structure.
It is invoked as
.Fn 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
.Fa group
and
.Fa name
arguments must be constant strings.
.Sh FUNCTIONS
The following is a brief description of each function in the framework:
.Bl -tag -width indent
.It Fn evcnt_attach_dynamic "ev" "type" "parent" "group" "name"
Attach the event counter structure pointed to by
.Fa 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.
.Pp
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.
.It Fn evcnt_attach_static "ev"
Attach the statically-initialized event counter structure
pointed to by
.Fa ev
to the system event list.
The event counter is assumed to be statically initialized using the
.Fn 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.
.It Fn evcnt_detach "ev"
Detach the event counter structure pointed to by
.Fa ev
from the system event list.
.El
.Pp
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
.Fa 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.)
.Sh EXAMPLES
This section includes a description on basic use of the framework
and example usage of its functions.
.Pp
Device drivers can use the
.Fn evcnt_attach_dynamic
and
.Fn evcnt_detach
functions to manage device-specific event counters.
Statically configured system modules can use
.Fn evcnt_attach_static
to configure global event counters.
Similarly, loadable modules can use
.Fn evcnt_attach_static
to configure their global event counters,
.Fn evcnt_attach_dynamic
to attach device-specific event
counters, and
.Fn evcnt_detach
to detach all counters when being unloaded.
.Pp
Device drivers that wish to use the generic event counter
framework should place event counter structures in their
.Dq softc
structures.
For example, to keep track of the number of interrupts for a given
device (broken down further into
.Dq device readable
and
.Dq device writable
interrupts) a device driver might use:
.Bd -literal
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 */
[ . . . ]
};
.Ed
.Pp
In the device attach function, those counters would be registered with
the system using the
.Fn evcnt_attach_dynamic
function, using code like:
.Bd -literal
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");
[ . . . ]
}
.Ed
.Pp
If the device can be detached from the system, its detach
function should invoke
.Fn evcnt_detach
on each attached counter (making sure to detach any
.Dq parent
counters only after detaching all children).
.Pp
Code like the following might be used to initialize a static
event counter (in this example, one used to track CPU alignment traps):
.Bd -literal
struct evcnt aligntrap_ev = EVCNT_INITIALIZER(EVCNT_TYPE_MISC,
NULL, "cpu", "aligntrap")
.Ed
.Pp
To attach this event counter, code like the following could be used:
.Bd -literal
evcnt_attach_static(&aligntrap_ev);
.Ed
.Sh CODE REFERENCES
The event counter framework itself is implemented within the file
.Pa sys/kern/subr_evcnt.c .
Data structures and function prototypes for the framework are located in
.Pa sys/sys/device.h .
.Pp
Event counters are used throughout the system.
.Pp
The
.Xr vmstat 1
source file
.Pa usr.bin/vmstat/vmstat.c
shows an example of how to access event counters from user programs.
.Sh SEE ALSO
.Xr vmstat 1
.Sh HISTORY
A set of interrupt counter interfaces with similar names to the interfaces
in the
.Nx
generic event counter framework appeared as part
of the new autoconfiguration system in
.Bx 4.4 .
Those interfaces were never widely adopted in
.Nx
because of limitations in their applicability.
(Their use was limited to non-hierarchical, dynamically
attached device interrupt counters.)
The
.Nx
generic event counter framework first appeared in
.Nx 1.5 .
.Sh AUTHORS
The
.Nx
generic event counter framework was designed and implemented by
.An Chris Demetriou
.Aq cgd@NetBSD.org .