1.\" $NetBSD: evcnt.9,v 1.6 2002/02/13 08:18:40 ross 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 June 1, 2000 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.Fd #include \*[Lt]sys/device.h\*[Gt] 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. Its user-accessible fields are: 62.Bd -literal 63struct evcnt { 64 u_int64_t ev_count; /* how many have occurred */ 65 TAILQ_ENTRY(evcnt) ev_list; /* entry on list of all counters */ 66 unsigned char ev_type; /* counter type; see below */ 67 unsigned char ev_grouplen; /* 'group' len, excluding NUL */ 68 unsigned char ev_namelen; /* 'name' len, excluding NUL */ 69 const struct evcnt *ev_parent; /* parent, for hierarchical ctrs */ 70 const char *ev_group; /* name of group */ 71 const char *ev_name; /* name of specific event */ 72}; 73.Ed 74.Pp 75The system maintains a global linked list of all active event counters. 76This list, called 77.Nm allevents , 78may grow or shrink over time as event counters are dynamically 79added to and removed from the system. 80.Pp 81Each event counter is marked (in the 82.Fa ev_type 83field) with the type of event being counted. 84The following types are currently defined: 85.Bl -tag -offset indent -width EVCNT_TYPE_MISC -compact 86.It Ev EVCNT_TYPE_MISC 87Miscellaneous; doesn't fit into one of the other types. 88.It Ev EVCNT_TYPE_INTR 89Interrupt counter, reported by 90.Ic vmstat -i . 91.El 92.Pp 93Each event counter also has a group name 94.Pq Fa ev_group 95and 96an event name 97.Pq Fa ev_name 98which are used to identify the counter. The group name 99may be shared by a set of counters. For example, device 100interrupt counters would use the name of the device whose 101interrupts are being counted as the group name. 102The counter 103name is meant to distinguish the counter from others in its group 104(and need not be unique across groups). 105Both names should be understandable by users, since they are printed 106by commands like 107.Xr vmstat 1 . 108The constant 109.Dv EVCNT_STRING_MAX 110is defined to be the maximum group or event name length in 111bytes (including the trailing 112.Dv NUL ) . 113In the current implementation it is 256. 114.Pp 115To support hierarchical tracking of events, each event counter can 116name a 117.Dq parent 118event counter. For instance, interrupt dispatch code could have an 119event counter per interrupt line, and devices could each have 120counters for the number of interrupts that they were responsible for 121causing. In that case, the counter for a device on a given interrupt line 122would have the line's counter as its parent. 123The value 124.Dv NULL 125is be used to indicate that a counter has no parent. 126A counter's parent must be attached before the counter is attached, 127and detached after the counter is detached. 128.Pp 129The 130.Fn EVCNT_INITIALIZER 131macro can be used to provide a static initializer for an event 132counter structure. It is be invoked as 133.Fn EVCNT_INITIALIZER "type" "parent" "group" "name" , 134and its arguments will be placed into the corresponding fields of 135the event counter structure it is initializing. The 136.Fa group 137and 138.Fa name 139arguments must be constant strings. 140.Pp 141The following is a brief description of each function in the framework: 142.Bl -tag -width indent 143.It Fn "void evcnt_attach_dynamic" "struct evcnt *ev" "int type" "const struct evcnt *parent" "const char *group" "const char *name" 144.Pp 145Attach the event counter structure pointed to by 146.Fa ev 147to the system event list. The event counter is cleared and its fields 148initialized using the arguments to the function call. 149The contents of the remaining elements in the structure (e.g., the 150name lengths) are calculated, and the counter is added to the 151system event list. 152.Pp 153The strings specified as the group and 154counter names must persist (with the same value) 155throughout the life of the event counter; they are referenced by, 156not copied into, the counter. 157.It Fn "void evcnt_attach_static" "struct evcnt *ev" 158.Pp 159Attach the statically-initialized event counter structure 160pointed to by 161.Fa ev 162to the system event list. The event counter is assumed to be 163statically initialized using the 164.Fn EVCNT_INITIALIZER 165macro. This function simply calculates structure elements' 166values as appropriate (e.g., the string lengths), and adds 167the counter to the system event list. 168.It Fn "void evcnt_detach" "struct evcnt *ev" 169.Pp 170Detach the event counter structure pointed to by 171.Fa ev 172from the system event list. 173.El 174.Pp 175Note that no method is provided to increment the value of an 176event counter. Code incrementing an event counter should 177do so by directly accessing its 178.Fa ev_count 179field in a manner that is known to be safe. For instance, 180additions to a device's event counters in the interrupt handler 181for that device will often be safe without additional protection 182(because interrupt handler entries for a given device have to be 183serialized). 184However, for other uses of event counters, additional locking 185or use of machine-dependent atomic operation may be appropriate. 186(The overhead of using a mechanism that is guaranteed to 187be safe to increment every counter, regardless of actual need 188for such a mechanism where the counter is being incremented, 189would be too great. On some systems, it might involve a global 190lock and several function calls.) 191.Sh USING THE FRAMEWORK 192This section includes a description on basic use of the framework 193and example usage of its functions. 194.Pp 195Device drivers can use the 196.Fn evcnt_attach_dynamic 197and 198.Fn evcnt_detach 199functions to manage device-specific event counters. 200Statically configured system modules can use 201.Fn evcnt_attach_static 202to configure global event counters. Similarly, loadable 203modules can use 204.Fn evcnt_attach_static 205to configure their global event counters, 206.Fn evcnt_attach_dynamic 207to attach device-specific event 208counters, and 209.Fn evcnt_detach 210to detach all counters when being unloaded. 211.Pp 212Device drivers that wish to use the generic event counter 213framework should place event counter structures in their 214.Dq softc 215structures. For example, to keep track of the number of interrupts 216for a given device (broken down further into 217.Dq device readable 218and 219.Dq device writable 220interrupts) a device driver might use: 221.Bd -literal 222struct foo_softc { 223 struct device sc_dev; /* generic device information */ 224 [ . . . ] 225 struct evcnt sc_ev_intr; /* interrupt count */ 226 struct evcnt sc_ev_intr_rd; /* 'readable' interrupt count */ 227 struct evcnt sc_ev_intr_wr; /* 'writable' interrupt count */ 228 [ . . . ] 229}; 230.Ed 231.Pp 232In the device attach function, those counters would be registered with 233the system using the 234.Fn evcnt_attach_dynamic 235function, using code like: 236.Bd -literal 237void 238fooattach(parent, self, aux) 239 struct device *parent, *self; 240 void *aux; 241{ 242 struct foo_softc *sc = (struct foo_softc *)self; 243 244 [ . . . ] 245 246 /* Initialize and attach event counters. */ 247 evcnt_attach_dynamic(\*[Am]sc-\*[Gt]sc_ev, EVCNT_TYPE_INTR, 248 NULL, sc-\*[Gt]sc_dev.dv_xname, "intr"); 249 evcnt_attach_dynamic(\*[Am]sc-\*[Gt]sc_ev_rd, EVCNT_TYPE_INTR, 250 \*[Am]sc-\*[Gt]sc_ev, sc-\*[Gt]sc_dev.dv_xname, "intr rd"); 251 evcnt_attach_dynamic(\*[Am]sc-\*[Gt]sc_ev_wr, EVCNT_TYPE_INTR, 252 \*[Am]sc-\*[Gt]sc_ev, sc-\*[Gt]sc_dev.dv_xname, "intr wr"); 253 254 [ . . . ] 255} 256.Ed 257.Pp 258If the device can be detached from the system, its detach 259function should invoke 260.Fn evcnt_detach 261on each attached counter (making sure to detach any 262.Dq parent 263counters only after detaching all children). 264.Pp 265Code like the following might be used to initialize a static 266event counter (in this example, one used to track CPU alignment traps): 267.Bd -literal 268 struct evcnt aligntrap_ev = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, 269 NULL, "cpu", "aligntrap") 270.Ed 271.Pp 272To attach this event counter, code like the following could be used: 273.Bd -literal 274 evcnt_attach_static(\*[Am]aligntrap_ev); 275.Ed 276.Sh CODE REFERENCES 277This section describes places within the 278.Nx 279source tree where actual 280code implementing or utilizing the event counter framework can be found. 281All pathnames are relative to 282.Pa /usr/src . 283.Pp 284The event counter framework itself is implemented within the file 285.Pa sys/kern/subr_autoconf.c . 286Data structures and function prototypes for the framework are located in 287.Pa sys/sys/device.h . 288.Pp 289Event counters are used throughout the system. 290.Pp 291The 292.Xr vmstat 1 293source file 294.Pa usr.bin/vmstat/vmstat.c 295shows an example of how to access event counters from user programs. 296.Sh SEE ALSO 297.Xr vmstat 1 298.Sh HISTORY 299A set of interrupt counter interfaces with similar names to the interfaces 300in the 301.Nx 302generic event counter framework appeared as part 303of the new autoconfiguration system in 304.Bx 4.4 . 305Those interfaces were never widely adopted in 306.Nx 307because of limitations in their applicability. 308(Their use was limited to non-hierarchical, dynamically 309attached device interrupt counters.) 310The 311.Nx 312generic event counter framework first appeared in 313.Nx 1.5 . 314.Sh AUTHORS 315The 316.Nx 317generic event counter framework was designed and implemented by 318Chris Demetriou \*[Lt]cgd@NetBSD.ORG\*[Gt]. 319