xref: /openbsd-src/share/man/man9/counters_alloc.9 (revision 6a13ef69787db04ae501a22e92fa10865b44fd7c)
1.\"	$OpenBSD: counters_alloc.9,v 1.9 2016/11/14 06:57:39 jmc Exp $
2.\"
3.\" Copyright (c) 2016 David Gwynne <dlg@openbsd.org>
4.\"
5.\" Permission to use, copy, modify, and distribute this software for any
6.\" purpose with or without fee is hereby granted, provided that the above
7.\" copyright notice and this permission notice appear in all copies.
8.\"
9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16.\"
17.Dd $Mdocdate: November 14 2016 $
18.Dt COUNTERS_ALLOC 9
19.Os
20.Sh NAME
21.Nm counters_alloc ,
22.Nm counters_free ,
23.Nm COUNTERS_BOOT_MEMORY ,
24.Nm COUNTERS_BOOT_INITIALIZER ,
25.Nm counters_alloc_ncpus ,
26.Nm counters_enter ,
27.Nm counters_leave ,
28.Nm counters_inc ,
29.Nm counters_add ,
30.Nm counters_pkt ,
31.Nm counters_read ,
32.Nm counters_zero
33.Nd per CPU counters
34.Sh SYNOPSIS
35.In sys/percpu.h
36.Ft struct cpumem *
37.Fn counters_alloc "unsigned int ncounters" "int type"
38.Ft void
39.Fn counters_free "struct cpumem *cm" "unsigned int ncounters" "int type"
40.Fn COUNTERS_BOOT_MEMORY "NAME" "unsigned int ncounters"
41.Fn COUNTERS_BOOT_INITIALIZER "NAME"
42.Ft struct cpumemt *
43.Fo counters_alloc_ncpus
44.Fa "struct cpumem *cm"
45.Fa "unsigned int ncounters"
46.Fa "int type"
47.Fc
48.Ft uint64_t *
49.Fn counters_enter "struct counters_ref *ref" "struct cpumem *cm"
50.Ft void
51.Fn counters_leave "struct counters_ref *ref" "struct cpumem *cm"
52.Ft void
53.Fn counters_inc "struct cpumem *cm" "unsigned int counter"
54.Ft void
55.Fn counters_add "struct cpumem *cm" "unsigned int counter" "uint64_t v"
56.Ft void
57.Fo counters_pkt
58.Fa "struct cpumem *cm"
59.Fa "unsigned int pcounter"
60.Fa "unsigned int bcounter"
61.Fa "uint64_t bytes"
62.Fc
63.Ft void
64.Fo counters_read
65.Fa "struct cpumem *cm"
66.Fa "uint64_t *counters"
67.Fa "unsigned int ncounters"
68.Fc
69.Ft void
70.Fn counters_zero "struct cpumem *cm" "unsigned int ncounters"
71.Sh DESCRIPTION
72The per CPU counter API builds on the per CPU memory API and provides
73access to a series of uint64_t counter values on each CPU.
74.Pp
75The API provides versioning of counter updates without using
76interlocked CPU instructions so they can all be read in a consistent
77state.
78Updates to counters should be limited to addition or subtraction
79of uint64_t values.
80.Pp
81An alternate implemention of the API is provided on uni-processor
82(i.e. when the kernel is not built with
83.Dv MULTIPROCESSOR
84defined)
85systems that provides no overhead compared to direct access to a
86data structure.
87This allows the API to be used without affecting the performance
88uni-processor systems.
89.Pp
90.Fn counters_alloc
91allocates memory for a series of uint64_t values on each CPU.
92.Fa ncounters
93specifies the number of counters to be allocated.
94The
95.Fa type
96argument specifies the type of memory that the counters will be
97allocated as via
98.Xr malloc 9 .
99The counters will be zeroed on allocation.
100.Pp
101.Fn counters_free
102deallocates each CPU's counters.
103The same
104.Fa ncounters
105and
106.Fa type
107arguments type originally provided to
108.Fn counters_alloc
109must be passed to
110.Fn counters_free .
111.Pp
112.Fn counters_alloc
113may only be used after all the CPUs in the system have been attached.
114If a set of CPU counters needs to be available during early boot,
115a cpumem pointer and counters for the boot CPU may be statically
116allocated.
117.Pp
118.Fn COUNTERS_BOOT_MEMORY
119statically allocates a set of counter for use on the boot CPU
120before the other CPUs in the system have been attached.
121The allocation is identified by
122.Fa NAME
123and provides memory for the number of counters specified by
124.Fa ncounters .
125The counters will be initialised to zero.
126.Pp
127.Fn COUNTERS_BOOT_INITIALIZER
128is used to initialise a cpumem pointer with the memory that was previously
129allocated using
130.Fn COUNTERS_BOOT_MEMORY
131and identified by
132.Fa NAME .
133.Pp
134.Fn counters_alloc_ncpus
135allocates additional sets of counters for the CPUs that were attached
136during boot.
137The cpumem structure
138.Fa cm
139must have been initialised with
140.Fn COUNTERS_BOOT_INITIALIZER .
141The same number of counters originally passed to
142.Fa COUNTERS_BOOT_MEMORY
143must be specified by
144.Fa ncounters .
145The
146.Fa type
147argument specifies the type of memory that the counters will be
148allocated as via
149.Xr malloc 9 .
150The counters on the boot CPU will be preserved, while the counters
151for the additional CPUs will be zeroed on allocation.
152.Pp
153Counters that have been allocated with
154.Fn COUNTERS_BOOT_MEMORY
155and
156.Fn counters_alloc_ncpus
157cannot be deallocated with
158.Fa counters_free .
159Any attempt to do so will lead to undefined behaviour.
160.Pp
161.Fn counters_enter
162provides access to the current CPU's set of counters referenced by
163.Fa cm .
164The caller's reference to the counters is held by
165.Fa ref .
166.Pp
167.Fn counters_leave
168indicates the end of access to the current CPU's set of counters referenced by
169.Fa cm .
170The reference held by
171.Fa ref
172is released by this call.
173.Pp
174.Fn counters_inc
175increments the counter at the index specified by
176.Fa counter
177in the array of counters referenced by
178.Fa cm .
179.Pp
180.Fn counters_add
181adds the value of
182.Fa v
183to the counter at the index specified by
184.Fa counter
185in the array of counters referenced by
186.Fa cm .
187.Pp
188.Fn counters_pkt
189increments the value at the index specified by
190.Fa pcounter
191and adds the value of
192.Fa bytes
193to the counter at the index specified by
194.Fa bcounter
195in the array of counters referenced by
196.Fa cm .
197.Pp
198.Fn counters_read
199iterates over each CPU's set of counters referenced by
200.Fa cm ,
201takes a consistent snapshot of the counters, and then sums them together.
202The sum of the counters is written to the
203.Fa counters
204array.
205The number of counters is specified with
206.Fa ncounters .
207.Pp
208.Fn counters_zero
209iterates over each CPU's set of counters referenced by
210.Fa cm
211and zeroes them.
212The number of counters is specified with
213.Fa ncounters .
214.Fn counters_zero
215itself does not prevent concurrent updates of the counters; it is
216up to the caller to serialise this call with other actions.
217.Sh CONTEXT
218.Fn counters_alloc ,
219.Fn counters_free ,
220.Fn counters_alloc_ncpus ,
221and
222.Fn counters_read
223may be called during autoconf, or from process context.
224.Pp
225.Fn counters_enter ,
226.Fn counters_leave ,
227.Fn counters_inc ,
228.Fn counters_add ,
229.Fn counters_pkt ,
230and
231.Fn counters_zero
232may be called during autoconf, from process context, or from interrupt
233context.
234The per CPU counters API does not provide any locking or serialisation
235of access to each CPU's set of counters beyond isolating each CPU's
236update.
237It is up to the caller to provide appropriate locking or serialisation
238around calls to these functions to prevent concurrent access to the
239relevant data structures.
240.Sh RETURN VALUES
241.Fn counters_alloc
242and
243.Fn counters_alloc_ncpus
244will return an opaque cpumem pointer that references each CPU's
245set of counters.
246.Pp
247.Fn counters_enter
248returns a reference to the current CPU's set of counters.
249.Sh EXAMPLES
250The following is an example of providing per CPU counters at boot
251time based on the
252.Xr mbuf 9
253statistics code in
254.Pa sys/kern/uipc_mbuf.c .
255.Bd -literal
256/* mbuf stats */
257COUNTERS_BOOT_MEMORY(mbstat_boot, MBSTAT_COUNT);
258struct cpumem *mbstat = COUNTERS_BOOT_INITIALIZER(mbstat_boot);
259
260/*
261 * this function is called from init_main.c after devices
262 * (including additional CPUs) have been attached
263 */
264void
265mbcpuinit()
266{
267	mbstat = counters_alloc_ncpus(mbstat, MBSTAT_COUNT,
268	    M_DEVBUF);
269}
270
271struct mbuf *
272m_get(int nowait, int type)
273{
274	...
275
276        struct counters_ref cr;
277        uint64_t *counters;
278        int s;
279
280	...
281
282        s = splnet();
283        counters = counters_enter(&cr, mbstat);
284        counters[type]++;
285        counters_leave(&cr, mbstat);
286        splx(s);
287
288	...
289}
290
291struct mbuf *
292m_free(struct mbuf *m)
293{
294	...
295
296        struct counters_ref cr;
297        uint64_t *counters;
298        int s;
299
300	...
301
302        s = splnet();
303        counters = counters_enter(&cr, mbstat);
304        counters[m->m_type]--;
305        counters_leave(&cr, mbstat);
306        splx(s);
307
308	...
309}
310.Ed
311.Sh SEE ALSO
312.Xr cpumem_get 9 ,
313.Xr malloc 9
314.Sh HISTORY
315The per CPU counter API first appeared in
316.Ox 6.1 .
317.Sh AUTHORS
318The per CPU counter API was written by
319.An David Gwynne Aq Mt dlg@openbsd.org .
320