1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
|
.\" $OpenBSD: evcount.9,v 1.8 2022/11/10 07:05:41 jmatthew Exp $
.\" Written by Jared Yanovich
.\" This file belongs to the public domain, 11/02/2004.
.Dd $Mdocdate: November 10 2022 $
.Dt EVCOUNT 9
.Os
.Sh NAME
.Nm evcount ,
.Nm evcount_attach ,
.Nm evcount_detach ,
.Nm evcount_percpu ,
.Nm evcount_inc
.Nd generic interrupt and event counter kernel API
.Sh SYNOPSIS
.In sys/evcount.h
.Ft void
.Fn evcount_attach "struct evcount *ec" "const char *name" "void *data"
.Ft void
.Fn evcount_percpu "struct evcount *ec"
.Ft void
.Fn evcount_inc "struct evcount *ec"
.Ft void
.Fn evcount_detach "struct evcount *ec"
.Sh DESCRIPTION
The
.Nm
API provides an interface for generic event and interrupt counting,
whose statistics are made available to machine-independent
.Xr sysctl 2
nodes.
.Ss Overview
With
.Nm ,
an architecture can collect interrupt counting for any device.
All registered counters will be made available under the
.Va kern.evcount
.Xr sysctl 2
node as a flat list.
The following is a sample list of counters provided by some
common architectures:
.Pp
.Bl -tag -width 8n -offset indent -compact
.It clock
Interrupt counter for the system clock
.It stat
Second-level interrupt decrementer counter
.It rtc
Real-time clock counter
.It prof
System profiler counter
.It pciide0
PCI IDE controller counter (see
.Xr pciide 4 )
.It uhci0
USB 1.0 controller counter (see
.Xr usb 4 )
.El
.Pp
See
.Xr intro 4
for a list of devices for any of which
.Nm
may track interrupt counting.
.Pp
The
.Xr systat 1
and
.Xr vmstat 8
utilities can be used to view interrupts collected by
.Nm .
.Ss The API
The
.Vt evcount
structure has the following definition:
.Bd -literal -offset indent
struct evcount {
u_int64_t ec_count; /* main counter */
int ec_id; /* counter ID */
const char *ec_name; /* counter name */
void *ec_data; /* user data */
struct cpumem *ec_cpumem; /* per-cpu counter */
TAILQ_ENTRY(evcount) next;
};
.Ed
.Pp
The
.Fn evcount_attach ec name data
function adds the given event counter to the system's counter list.
.Fa name
provides the counter name, which is modeled after a
device, such as
.Dq clock
or
.Dq pciide0 .
.Fa data
provides a chunk of data that will be made available through the
.Xr sysctl 2
call.
.Pp
The
.Fn evcount_percpu ec
function configures
.Fa ec
with one counter for each CPU in the system.
It should be used when
.Fa ec Ns 's
corresponding interrupt can occur simultaneously on multiple CPUs.
It must be called immediately after
.Fn evcount_attach
is called for a given counter.
.Pp
The
.Fn evcount_inc ec
function increments the given counter.
.Pp
The
.Fn evcount_detach ec
function removes the given event counter
.Fa ec
from the counter list.
.Sh EXAMPLES
The following is an outline of code that provides routines to register
and de-register interrupt handlers for devices, plugging the counting of
interrupts generated by them during system operation into the
.Nm
framework.
.Bd -literal
#include <sys/evcount.h>
#include <machine/intr.h>
/*
* machine/intr.h provides a structure, intrhand, which is
* machine-dependent but is usually similar to this:
*
* struct intrhand {
* int (*ih_fun)(void *);
* void *ih_arg;
* int ih_level;
* struct intrhand *ih_next;
* int ih_irq;
* struct evcount ih_count;
* }
*/
/*
* Register an interrupt handler.
*/
void *
intr_establish(void *lcv, int irq, int type, int level,
int (*ih_fun)(void *), void *ih_arg, char *name)
{
struct intrhand *ih, **p;
/*
* Allocate memory for the handler, sanity-check incoming
* values (IRQ#, etc.), and link the handler into
* machine-dependent data structures.
*/
/*
* Fill out the handler.
*/
ih->ih_fun = ih_fun;
ih->ih_arg = ih_arg;
ih->ih_next = NULL;
ih->ih_level = level;
ih->ih_irq = irq;
/*
* Attach it.
*/
evcount_attach(&ih->ih_count, name, &ih->ih_irq);
return (ih);
}
/*
* Deregister an interrupt handler.
*/
void
intr_disestablish(void *lcp, void *arg)
{
struct intrhand *ih = arg;
/*
* Sanity-check incoming values (IRQ, etc.) and remove
* the interrupt handler from machine-dependent data
* structures.
*/
evcount_detach(&ih->ih_count);
/*
* Free up memory and install a null interrupt handler.
*/
}
.Ed
.Pp
An interrupt handler for a device will be registered during
.Xr autoconf 9
with a call to the above
.Fn intr_establish .
.Pp
The main external interrupt handler, which handles all system
interrupts, will select the appropriate handler for the device
that created the interrupt when an interrupt is generated.
In this case, the handler is the routine assigned to
.Va ih_fun ,
and
.Nm
will be made aware of interrupt occurrence.
.Sh SEE ALSO
.Xr systat 1 ,
.Xr sysctl 2 ,
.Xr queue 3 ,
.Xr intro 4 ,
.Xr vmstat 8 ,
.Xr autoconf 9 ,
.Xr counters_alloc 9
.Sh AUTHORS
.An -nosplit
The
.Nm
API was written by
.An Artur Grabowski
and
.An Aaron Campbell
for
.Ox 3.6 .
|