1.\" $NetBSD: evcnt.9,v 1.12 2004/06/05 15:05:02 rumble Exp $ 2.\" 3.\" Copyright (c) 2000 Christopher G. Demetriou 4.\" All rights reserved. 5.\" 6.\" Redistribution and use in source and binary forms, with or without 7.\" modification, are permitted provided that the following conditions 8.\" are met: 9.\" 1. Redistributions of source code must retain the above copyright 10.\" notice, this list of conditions and the following disclaimer. 11.\" 2. Redistributions in binary form must reproduce the above copyright 12.\" notice, this list of conditions and the following disclaimer in the 13.\" documentation and/or other materials provided with the distribution. 14.\" 3. All advertising materials mentioning features or use of this software 15.\" must display the following acknowledgement: 16.\" This product includes software developed for the 17.\" NetBSD Project. See http://www.NetBSD.org/ for 18.\" information about NetBSD. 19.\" 4. The name of the author may not be used to endorse or promote products 20.\" derived from this software without specific prior written permission. 21.\" 22.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32.\" 33.\" --(license Id: LICENSE.proto,v 1.1 2000/06/13 21:40:26 cgd Exp )-- 34.\" 35.Dd February 18, 2004 36.Dt EVCNT 9 37.Os 38.Sh NAME 39.Nm evcnt , 40.Nm evcnt_attach_dynamic , 41.Nm evcnt_attach_static , 42.Nm evcnt_detach 43.Nd generic event counter framework 44.Sh SYNOPSIS 45.In sys/device.h 46.Ft void 47.Fn evcnt_attach_dynamic "struct evcnt *ev" "int type" "const struct evcnt *parent" "const char *group" "const char *name" 48.Ft void 49.Fn evcnt_attach_static "struct evcnt *ev" 50.Ft void 51.Fn evcnt_detach "struct evcnt *ev" 52.Sh DESCRIPTION 53The 54.Nx 55generic event counter framework is designed to provide a flexible and 56hierarchical event counting facility, which is useful for tracking 57system events (including device interrupts). 58.Pp 59The fundamental component of this framework is the 60.Nm evcnt 61structure. 62Its user-accessible fields are: 63.Bd -literal 64struct evcnt { 65 u_int64_t ev_count; /* how many have occurred */ 66 TAILQ_ENTRY(evcnt) ev_list; /* entry on list of all counters */ 67 unsigned char ev_type; /* counter type; see below */ 68 unsigned char ev_grouplen; /* 'group' len, excluding NUL */ 69 unsigned char ev_namelen; /* 'name' len, excluding NUL */ 70 const struct evcnt *ev_parent; /* parent, for hierarchical ctrs */ 71 const char *ev_group; /* name of group */ 72 const char *ev_name; /* name of specific event */ 73}; 74.Ed 75.Pp 76The system maintains a global linked list of all active event counters. 77This list, called 78.Nm allevents , 79may grow or shrink over time as event counters are dynamically 80added to and removed from the system. 81.Pp 82Each event counter is marked (in the 83.Fa ev_type 84field) with the type of event being counted. 85The following types are currently defined: 86.Bl -tag -offset indent -width EVCNT_TYPE_MISC -compact 87.It Ev EVCNT_TYPE_MISC 88Miscellaneous; doesn't fit into one of the other types. 89.It Ev EVCNT_TYPE_INTR 90Interrupt counter, reported by 91.Ic vmstat -i . 92.El 93.Pp 94Each event counter also has a group name 95.Pq Fa ev_group 96and 97an event name 98.Pq Fa ev_name 99which are used to identify the counter. 100The group name may be shared by a set of counters. 101For example, device interrupt counters would use the name of the 102device whose interrupts are being counted as the group name. 103The counter 104name is meant to distinguish the counter from others in its group 105(and need not be unique across groups). 106Both names should be understandable by users, since they are printed 107by commands like 108.Xr vmstat 1 . 109The constant 110.Dv EVCNT_STRING_MAX 111is defined to be the maximum group or event name length in 112bytes (including the trailing 113.Dv NUL ) . 114In the current implementation it is 256. 115.Pp 116To support hierarchical tracking of events, each event counter can 117name a 118.Dq parent 119event counter. 120For instance, interrupt dispatch code could have an event counter per 121interrupt line, and devices could each have counters for the number 122of interrupts that they were responsible for causing. 123In that case, the counter for a device on a given interrupt line 124would have the line's counter as its parent. 125The value 126.Dv NULL 127is used to indicate that a counter has no parent. 128A counter's parent must be attached before the counter is attached, 129and detached after the counter is detached. 130.Pp 131The 132.Fn EVCNT_INITIALIZER 133macro can be used to provide a static initializer for an event 134counter structure. 135It is be invoked as 136.Fn EVCNT_INITIALIZER "type" "parent" "group" "name" , 137and its arguments will be placed into the corresponding fields of 138the event counter structure it is initializing. 139The 140.Fa group 141and 142.Fa name 143arguments must be constant strings. 144.Pp 145The following is a brief description of each function in the framework: 146.Bl -tag -width indent 147.It Fn "void evcnt_attach_dynamic" "struct evcnt *ev" "int type" "const struct evcnt *parent" "const char *group" "const char *name" 148.Pp 149Attach the event counter structure pointed to by 150.Fa ev 151to the system event list. 152The event counter is cleared and its fields initialized using the 153arguments to the function call. 154The contents of the remaining elements in the structure (e.g., the 155name lengths) are calculated, and the counter is added to the 156system event list. 157.Pp 158The strings specified as the group and 159counter names must persist (with the same value) 160throughout the life of the event counter; they are referenced by, 161not copied into, the counter. 162.It Fn "void evcnt_attach_static" "struct evcnt *ev" 163.Pp 164Attach the statically-initialized event counter structure 165pointed to by 166.Fa ev 167to the system event list. 168The event counter is assumed to be statically initialized using the 169.Fn EVCNT_INITIALIZER 170macro. 171This function simply calculates structure elements' values as appropriate 172(e.g., the string lengths), and adds the counter to the system event list. 173.It Fn "void evcnt_detach" "struct evcnt *ev" 174.Pp 175Detach the event counter structure pointed to by 176.Fa ev 177from the system event list. 178.El 179.Pp 180Note that no method is provided to increment the value of an 181event counter. 182Code incrementing an event counter should do so by directly accessing its 183.Fa ev_count 184field in a manner that is known to be safe. 185For instance, additions to a device's event counters in the interrupt 186handler for that device will often be safe without additional protection 187(because interrupt handler entries for a given device have to be 188serialized). 189However, for other uses of event counters, additional locking 190or use of machine-dependent atomic operation may be appropriate. 191(The overhead of using a mechanism that is guaranteed to 192be safe to increment every counter, regardless of actual need 193for such a mechanism where the counter is being incremented, 194would be too great. 195On some systems, it might involve a global lock and several function calls.) 196.Sh USING THE FRAMEWORK 197This section includes a description on basic use of the framework 198and example usage of its functions. 199.Pp 200Device drivers can use the 201.Fn evcnt_attach_dynamic 202and 203.Fn evcnt_detach 204functions to manage device-specific event counters. 205Statically configured system modules can use 206.Fn evcnt_attach_static 207to configure global event counters. 208Similarly, loadable modules can use 209.Fn evcnt_attach_static 210to configure their global event counters, 211.Fn evcnt_attach_dynamic 212to attach device-specific event 213counters, and 214.Fn evcnt_detach 215to detach all counters when being unloaded. 216.Pp 217Device drivers that wish to use the generic event counter 218framework should place event counter structures in their 219.Dq softc 220structures. 221For example, to keep track of the number of interrupts for a given 222device (broken down further into 223.Dq device readable 224and 225.Dq device writable 226interrupts) a device driver might use: 227.Bd -literal 228struct foo_softc { 229 struct device sc_dev; /* generic device information */ 230 [ . . . ] 231 struct evcnt sc_ev_intr; /* interrupt count */ 232 struct evcnt sc_ev_intr_rd; /* 'readable' interrupt count */ 233 struct evcnt sc_ev_intr_wr; /* 'writable' interrupt count */ 234 [ . . . ] 235}; 236.Ed 237.Pp 238In the device attach function, those counters would be registered with 239the system using the 240.Fn evcnt_attach_dynamic 241function, using code like: 242.Bd -literal 243void 244fooattach(parent, self, aux) 245 struct device *parent, *self; 246 void *aux; 247{ 248 struct foo_softc *sc = (struct foo_softc *)self; 249 250 [ . . . ] 251 252 /* Initialize and attach event counters. */ 253 evcnt_attach_dynamic(\*[Am]sc-\*[Gt]sc_ev, EVCNT_TYPE_INTR, 254 NULL, sc-\*[Gt]sc_dev.dv_xname, "intr"); 255 evcnt_attach_dynamic(\*[Am]sc-\*[Gt]sc_ev_rd, EVCNT_TYPE_INTR, 256 \*[Am]sc-\*[Gt]sc_ev, sc-\*[Gt]sc_dev.dv_xname, "intr rd"); 257 evcnt_attach_dynamic(\*[Am]sc-\*[Gt]sc_ev_wr, EVCNT_TYPE_INTR, 258 \*[Am]sc-\*[Gt]sc_ev, sc-\*[Gt]sc_dev.dv_xname, "intr wr"); 259 260 [ . . . ] 261} 262.Ed 263.Pp 264If the device can be detached from the system, its detach 265function should invoke 266.Fn evcnt_detach 267on each attached counter (making sure to detach any 268.Dq parent 269counters only after detaching all children). 270.Pp 271Code like the following might be used to initialize a static 272event counter (in this example, one used to track CPU alignment traps): 273.Bd -literal 274 struct evcnt aligntrap_ev = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, 275 NULL, "cpu", "aligntrap") 276.Ed 277.Pp 278To attach this event counter, code like the following could be used: 279.Bd -literal 280 evcnt_attach_static(\*[Am]aligntrap_ev); 281.Ed 282.Sh CODE REFERENCES 283This section describes places within the 284.Nx 285source tree where actual 286code implementing or using the event counter framework can be found. 287All pathnames are relative to 288.Pa /usr/src . 289.Pp 290The event counter framework itself is implemented within the file 291.Pa sys/kern/subr_evcnt.c . 292Data structures and function prototypes for the framework are located in 293.Pa sys/sys/device.h . 294.Pp 295Event counters are used throughout the system. 296.Pp 297The 298.Xr vmstat 1 299source file 300.Pa usr.bin/vmstat/vmstat.c 301shows an example of how to access event counters from user programs. 302.Sh SEE ALSO 303.Xr vmstat 1 304.Sh HISTORY 305A set of interrupt counter interfaces with similar names to the interfaces 306in the 307.Nx 308generic event counter framework appeared as part 309of the new autoconfiguration system in 310.Bx 4.4 . 311Those interfaces were never widely adopted in 312.Nx 313because of limitations in their applicability. 314(Their use was limited to non-hierarchical, dynamically 315attached device interrupt counters.) 316The 317.Nx 318generic event counter framework first appeared in 319.Nx 1.5 . 320.Sh AUTHORS 321The 322.Nx 323generic event counter framework was designed and implemented by 324.An Chris Demetriou 325.Aq cgd@NetBSD.org . 326