tprof.c revision 1.20 1 1.20 chs /* $NetBSD: tprof.c,v 1.20 2022/12/11 01:36:49 chs Exp $ */
2 1.1 yamt
3 1.1 yamt /*-
4 1.8 yamt * Copyright (c)2008,2009,2010 YAMAMOTO Takashi,
5 1.1 yamt * All rights reserved.
6 1.1 yamt *
7 1.1 yamt * Redistribution and use in source and binary forms, with or without
8 1.1 yamt * modification, are permitted provided that the following conditions
9 1.1 yamt * are met:
10 1.1 yamt * 1. Redistributions of source code must retain the above copyright
11 1.1 yamt * notice, this list of conditions and the following disclaimer.
12 1.1 yamt * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 yamt * notice, this list of conditions and the following disclaimer in the
14 1.1 yamt * documentation and/or other materials provided with the distribution.
15 1.1 yamt *
16 1.1 yamt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 1.1 yamt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 yamt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 yamt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 1.1 yamt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 yamt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 yamt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 yamt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 yamt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 yamt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 yamt * SUCH DAMAGE.
27 1.1 yamt */
28 1.1 yamt
29 1.1 yamt #include <sys/cdefs.h>
30 1.20 chs __KERNEL_RCSID(0, "$NetBSD: tprof.c,v 1.20 2022/12/11 01:36:49 chs Exp $");
31 1.1 yamt
32 1.1 yamt #include <sys/param.h>
33 1.1 yamt #include <sys/systm.h>
34 1.1 yamt #include <sys/kernel.h>
35 1.1 yamt
36 1.15 riastrad #include <sys/callout.h>
37 1.15 riastrad #include <sys/conf.h>
38 1.1 yamt #include <sys/cpu.h>
39 1.1 yamt #include <sys/kmem.h>
40 1.4 yamt #include <sys/module.h>
41 1.15 riastrad #include <sys/percpu.h>
42 1.8 yamt #include <sys/proc.h>
43 1.15 riastrad #include <sys/queue.h>
44 1.1 yamt #include <sys/workqueue.h>
45 1.19 ryo #include <sys/xcall.h>
46 1.1 yamt
47 1.1 yamt #include <dev/tprof/tprof.h>
48 1.1 yamt #include <dev/tprof/tprof_ioctl.h>
49 1.1 yamt
50 1.13 christos #include "ioconf.h"
51 1.13 christos
52 1.19 ryo #ifndef TPROF_HZ
53 1.19 ryo #define TPROF_HZ 10000
54 1.19 ryo #endif
55 1.19 ryo
56 1.4 yamt /*
57 1.4 yamt * locking order:
58 1.4 yamt * tprof_reader_lock -> tprof_lock
59 1.4 yamt * tprof_startstop_lock -> tprof_lock
60 1.4 yamt */
61 1.4 yamt
62 1.4 yamt /*
63 1.4 yamt * protected by:
64 1.4 yamt * L: tprof_lock
65 1.4 yamt * R: tprof_reader_lock
66 1.4 yamt * S: tprof_startstop_lock
67 1.8 yamt * s: writer should hold tprof_startstop_lock and tprof_lock
68 1.8 yamt * reader should hold tprof_startstop_lock or tprof_lock
69 1.4 yamt */
70 1.4 yamt
71 1.1 yamt typedef struct tprof_buf {
72 1.1 yamt u_int b_used;
73 1.1 yamt u_int b_size;
74 1.1 yamt u_int b_overflow;
75 1.1 yamt u_int b_unused;
76 1.1 yamt STAILQ_ENTRY(tprof_buf) b_list;
77 1.1 yamt tprof_sample_t b_data[];
78 1.1 yamt } tprof_buf_t;
79 1.1 yamt #define TPROF_BUF_BYTESIZE(sz) \
80 1.1 yamt (sizeof(tprof_buf_t) + (sz) * sizeof(tprof_sample_t))
81 1.19 ryo #define TPROF_MAX_SAMPLES_PER_BUF (TPROF_HZ * 2)
82 1.1 yamt
83 1.1 yamt #define TPROF_MAX_BUF 100
84 1.1 yamt
85 1.1 yamt typedef struct {
86 1.1 yamt tprof_buf_t *c_buf;
87 1.10 yamt uint32_t c_cpuid;
88 1.1 yamt struct work c_work;
89 1.1 yamt callout_t c_callout;
90 1.1 yamt } __aligned(CACHE_LINE_SIZE) tprof_cpu_t;
91 1.1 yamt
92 1.4 yamt typedef struct tprof_backend {
93 1.19 ryo /*
94 1.19 ryo * tprof_backend_softc_t must be passed as an argument to the interrupt
95 1.19 ryo * handler, but since this is difficult to implement in armv7/v8. Then,
96 1.19 ryo * tprof_backend is exposed. Additionally, softc must be placed at the
97 1.19 ryo * beginning of struct tprof_backend.
98 1.19 ryo */
99 1.19 ryo tprof_backend_softc_t tb_softc;
100 1.19 ryo
101 1.4 yamt const char *tb_name;
102 1.4 yamt const tprof_backend_ops_t *tb_ops;
103 1.4 yamt LIST_ENTRY(tprof_backend) tb_list;
104 1.4 yamt } tprof_backend_t;
105 1.3 yamt
106 1.1 yamt static kmutex_t tprof_lock;
107 1.4 yamt static u_int tprof_nworker; /* L: # of running worker LWPs */
108 1.1 yamt static lwp_t *tprof_owner;
109 1.4 yamt static STAILQ_HEAD(, tprof_buf) tprof_list; /* L: global buffer list */
110 1.4 yamt static u_int tprof_nbuf_on_list; /* L: # of buffers on tprof_list */
111 1.1 yamt static struct workqueue *tprof_wq;
112 1.15 riastrad static struct percpu *tprof_cpus __read_mostly; /* tprof_cpu_t * */
113 1.1 yamt static u_int tprof_samples_per_buf;
114 1.1 yamt
115 1.19 ryo tprof_backend_t *tprof_backend; /* S: */
116 1.4 yamt static LIST_HEAD(, tprof_backend) tprof_backends =
117 1.4 yamt LIST_HEAD_INITIALIZER(tprof_backend); /* S: */
118 1.4 yamt
119 1.1 yamt static kmutex_t tprof_reader_lock;
120 1.4 yamt static kcondvar_t tprof_reader_cv; /* L: */
121 1.4 yamt static off_t tprof_reader_offset; /* R: */
122 1.1 yamt
123 1.1 yamt static kmutex_t tprof_startstop_lock;
124 1.4 yamt static kcondvar_t tprof_cv; /* L: */
125 1.1 yamt
126 1.4 yamt static struct tprof_stat tprof_stat; /* L: */
127 1.1 yamt
128 1.1 yamt static tprof_cpu_t *
129 1.18 ryo tprof_cpu_direct(struct cpu_info *ci)
130 1.18 ryo {
131 1.18 ryo tprof_cpu_t **cp;
132 1.18 ryo
133 1.18 ryo cp = percpu_getptr_remote(tprof_cpus, ci);
134 1.18 ryo return *cp;
135 1.18 ryo }
136 1.18 ryo
137 1.18 ryo static tprof_cpu_t *
138 1.1 yamt tprof_cpu(struct cpu_info *ci)
139 1.1 yamt {
140 1.18 ryo tprof_cpu_t *c;
141 1.1 yamt
142 1.15 riastrad /*
143 1.15 riastrad * As long as xcalls are blocked -- e.g., by kpreempt_disable
144 1.15 riastrad * -- the percpu object will not be swapped and destroyed. We
145 1.15 riastrad * can't write to it, because the data may have already been
146 1.15 riastrad * moved to a new buffer, but we can safely read from it.
147 1.15 riastrad */
148 1.15 riastrad kpreempt_disable();
149 1.18 ryo c = tprof_cpu_direct(ci);
150 1.15 riastrad kpreempt_enable();
151 1.15 riastrad
152 1.15 riastrad return c;
153 1.1 yamt }
154 1.1 yamt
155 1.1 yamt static tprof_cpu_t *
156 1.1 yamt tprof_curcpu(void)
157 1.1 yamt {
158 1.1 yamt
159 1.1 yamt return tprof_cpu(curcpu());
160 1.1 yamt }
161 1.1 yamt
162 1.1 yamt static tprof_buf_t *
163 1.1 yamt tprof_buf_alloc(void)
164 1.1 yamt {
165 1.1 yamt tprof_buf_t *new;
166 1.1 yamt u_int size = tprof_samples_per_buf;
167 1.15 riastrad
168 1.1 yamt new = kmem_alloc(TPROF_BUF_BYTESIZE(size), KM_SLEEP);
169 1.1 yamt new->b_used = 0;
170 1.1 yamt new->b_size = size;
171 1.1 yamt new->b_overflow = 0;
172 1.1 yamt return new;
173 1.1 yamt }
174 1.1 yamt
175 1.1 yamt static void
176 1.1 yamt tprof_buf_free(tprof_buf_t *buf)
177 1.1 yamt {
178 1.1 yamt
179 1.1 yamt kmem_free(buf, TPROF_BUF_BYTESIZE(buf->b_size));
180 1.1 yamt }
181 1.1 yamt
182 1.1 yamt static tprof_buf_t *
183 1.1 yamt tprof_buf_switch(tprof_cpu_t *c, tprof_buf_t *new)
184 1.1 yamt {
185 1.1 yamt tprof_buf_t *old;
186 1.1 yamt
187 1.1 yamt old = c->c_buf;
188 1.1 yamt c->c_buf = new;
189 1.1 yamt return old;
190 1.1 yamt }
191 1.1 yamt
192 1.1 yamt static tprof_buf_t *
193 1.1 yamt tprof_buf_refresh(void)
194 1.1 yamt {
195 1.1 yamt tprof_cpu_t * const c = tprof_curcpu();
196 1.1 yamt tprof_buf_t *new;
197 1.1 yamt
198 1.1 yamt new = tprof_buf_alloc();
199 1.1 yamt return tprof_buf_switch(c, new);
200 1.1 yamt }
201 1.1 yamt
202 1.1 yamt static void
203 1.1 yamt tprof_worker(struct work *wk, void *dummy)
204 1.1 yamt {
205 1.1 yamt tprof_cpu_t * const c = tprof_curcpu();
206 1.1 yamt tprof_buf_t *buf;
207 1.19 ryo tprof_backend_t *tb;
208 1.1 yamt bool shouldstop;
209 1.1 yamt
210 1.1 yamt KASSERT(wk == &c->c_work);
211 1.1 yamt KASSERT(dummy == NULL);
212 1.1 yamt
213 1.1 yamt /*
214 1.1 yamt * get a per cpu buffer.
215 1.1 yamt */
216 1.1 yamt buf = tprof_buf_refresh();
217 1.1 yamt
218 1.1 yamt /*
219 1.1 yamt * and put it on the global list for read(2).
220 1.1 yamt */
221 1.1 yamt mutex_enter(&tprof_lock);
222 1.19 ryo tb = tprof_backend;
223 1.19 ryo shouldstop = (tb == NULL || tb->tb_softc.sc_ctr_running_mask == 0);
224 1.1 yamt if (shouldstop) {
225 1.1 yamt KASSERT(tprof_nworker > 0);
226 1.1 yamt tprof_nworker--;
227 1.1 yamt cv_broadcast(&tprof_cv);
228 1.1 yamt cv_broadcast(&tprof_reader_cv);
229 1.1 yamt }
230 1.1 yamt if (buf->b_used == 0) {
231 1.1 yamt tprof_stat.ts_emptybuf++;
232 1.1 yamt } else if (tprof_nbuf_on_list < TPROF_MAX_BUF) {
233 1.1 yamt tprof_stat.ts_sample += buf->b_used;
234 1.1 yamt tprof_stat.ts_overflow += buf->b_overflow;
235 1.1 yamt tprof_stat.ts_buf++;
236 1.1 yamt STAILQ_INSERT_TAIL(&tprof_list, buf, b_list);
237 1.1 yamt tprof_nbuf_on_list++;
238 1.1 yamt buf = NULL;
239 1.1 yamt cv_broadcast(&tprof_reader_cv);
240 1.1 yamt } else {
241 1.1 yamt tprof_stat.ts_dropbuf_sample += buf->b_used;
242 1.1 yamt tprof_stat.ts_dropbuf++;
243 1.1 yamt }
244 1.1 yamt mutex_exit(&tprof_lock);
245 1.1 yamt if (buf) {
246 1.1 yamt tprof_buf_free(buf);
247 1.1 yamt }
248 1.1 yamt if (!shouldstop) {
249 1.1 yamt callout_schedule(&c->c_callout, hz);
250 1.1 yamt }
251 1.1 yamt }
252 1.1 yamt
253 1.1 yamt static void
254 1.1 yamt tprof_kick(void *vp)
255 1.1 yamt {
256 1.1 yamt struct cpu_info * const ci = vp;
257 1.1 yamt tprof_cpu_t * const c = tprof_cpu(ci);
258 1.1 yamt
259 1.1 yamt workqueue_enqueue(tprof_wq, &c->c_work, ci);
260 1.1 yamt }
261 1.1 yamt
262 1.1 yamt static void
263 1.1 yamt tprof_stop1(void)
264 1.1 yamt {
265 1.1 yamt CPU_INFO_ITERATOR cii;
266 1.1 yamt struct cpu_info *ci;
267 1.1 yamt
268 1.1 yamt KASSERT(mutex_owned(&tprof_startstop_lock));
269 1.6 yamt KASSERT(tprof_nworker == 0);
270 1.1 yamt
271 1.1 yamt for (CPU_INFO_FOREACH(cii, ci)) {
272 1.1 yamt tprof_cpu_t * const c = tprof_cpu(ci);
273 1.1 yamt tprof_buf_t *old;
274 1.1 yamt
275 1.1 yamt old = tprof_buf_switch(c, NULL);
276 1.1 yamt if (old != NULL) {
277 1.1 yamt tprof_buf_free(old);
278 1.1 yamt }
279 1.1 yamt callout_destroy(&c->c_callout);
280 1.1 yamt }
281 1.1 yamt workqueue_destroy(tprof_wq);
282 1.1 yamt }
283 1.1 yamt
284 1.14 maxv static void
285 1.14 maxv tprof_getinfo(struct tprof_info *info)
286 1.14 maxv {
287 1.14 maxv tprof_backend_t *tb;
288 1.14 maxv
289 1.14 maxv KASSERT(mutex_owned(&tprof_startstop_lock));
290 1.14 maxv
291 1.14 maxv memset(info, 0, sizeof(*info));
292 1.14 maxv info->ti_version = TPROF_VERSION;
293 1.14 maxv if ((tb = tprof_backend) != NULL) {
294 1.14 maxv info->ti_ident = tb->tb_ops->tbo_ident();
295 1.14 maxv }
296 1.14 maxv }
297 1.14 maxv
298 1.1 yamt static int
299 1.19 ryo tprof_getncounters(u_int *ncounters)
300 1.19 ryo {
301 1.19 ryo tprof_backend_t *tb;
302 1.19 ryo
303 1.19 ryo tb = tprof_backend;
304 1.19 ryo if (tb == NULL)
305 1.19 ryo return ENOENT;
306 1.19 ryo
307 1.19 ryo *ncounters = tb->tb_ops->tbo_ncounters();
308 1.19 ryo return 0;
309 1.19 ryo }
310 1.19 ryo
311 1.19 ryo static void
312 1.19 ryo tprof_start_cpu(void *arg1, void *arg2)
313 1.19 ryo {
314 1.19 ryo tprof_backend_t *tb = arg1;
315 1.19 ryo tprof_countermask_t runmask = (uintptr_t)arg2;
316 1.19 ryo
317 1.19 ryo tb->tb_ops->tbo_start(runmask);
318 1.19 ryo }
319 1.19 ryo
320 1.19 ryo static void
321 1.19 ryo tprof_stop_cpu(void *arg1, void *arg2)
322 1.19 ryo {
323 1.19 ryo tprof_backend_t *tb = arg1;
324 1.19 ryo tprof_countermask_t stopmask = (uintptr_t)arg2;
325 1.19 ryo
326 1.19 ryo tb->tb_ops->tbo_stop(stopmask);
327 1.19 ryo }
328 1.19 ryo
329 1.19 ryo static int
330 1.19 ryo tprof_start(tprof_countermask_t runmask)
331 1.1 yamt {
332 1.1 yamt CPU_INFO_ITERATOR cii;
333 1.1 yamt struct cpu_info *ci;
334 1.19 ryo tprof_backend_t *tb;
335 1.19 ryo uint64_t xc;
336 1.1 yamt int error;
337 1.19 ryo bool firstrun;
338 1.1 yamt
339 1.1 yamt KASSERT(mutex_owned(&tprof_startstop_lock));
340 1.1 yamt
341 1.4 yamt tb = tprof_backend;
342 1.4 yamt if (tb == NULL) {
343 1.4 yamt error = ENOENT;
344 1.4 yamt goto done;
345 1.4 yamt }
346 1.19 ryo
347 1.19 ryo runmask &= ~tb->tb_softc.sc_ctr_running_mask;
348 1.19 ryo runmask &= tb->tb_softc.sc_ctr_configured_mask;
349 1.19 ryo if (runmask == 0) {
350 1.19 ryo /*
351 1.19 ryo * targets are already running.
352 1.19 ryo * unconfigured counters are ignored.
353 1.19 ryo */
354 1.19 ryo error = 0;
355 1.4 yamt goto done;
356 1.4 yamt }
357 1.4 yamt
358 1.19 ryo firstrun = (tb->tb_softc.sc_ctr_running_mask == 0);
359 1.19 ryo if (firstrun) {
360 1.19 ryo if (tb->tb_ops->tbo_establish != NULL) {
361 1.19 ryo error = tb->tb_ops->tbo_establish(&tb->tb_softc);
362 1.19 ryo if (error != 0)
363 1.19 ryo goto done;
364 1.19 ryo }
365 1.19 ryo
366 1.19 ryo tprof_samples_per_buf = TPROF_MAX_SAMPLES_PER_BUF;
367 1.19 ryo error = workqueue_create(&tprof_wq, "tprofmv", tprof_worker,
368 1.19 ryo NULL, PRI_NONE, IPL_SOFTCLOCK, WQ_MPSAFE | WQ_PERCPU);
369 1.19 ryo if (error != 0) {
370 1.19 ryo if (tb->tb_ops->tbo_disestablish != NULL)
371 1.19 ryo tb->tb_ops->tbo_disestablish(&tb->tb_softc);
372 1.19 ryo goto done;
373 1.19 ryo }
374 1.19 ryo
375 1.19 ryo for (CPU_INFO_FOREACH(cii, ci)) {
376 1.19 ryo tprof_cpu_t * const c = tprof_cpu(ci);
377 1.19 ryo tprof_buf_t *new;
378 1.19 ryo tprof_buf_t *old;
379 1.19 ryo
380 1.19 ryo new = tprof_buf_alloc();
381 1.19 ryo old = tprof_buf_switch(c, new);
382 1.19 ryo if (old != NULL) {
383 1.19 ryo tprof_buf_free(old);
384 1.19 ryo }
385 1.19 ryo callout_init(&c->c_callout, CALLOUT_MPSAFE);
386 1.19 ryo callout_setfunc(&c->c_callout, tprof_kick, ci);
387 1.19 ryo }
388 1.1 yamt }
389 1.1 yamt
390 1.19 ryo runmask &= tb->tb_softc.sc_ctr_configured_mask;
391 1.19 ryo xc = xc_broadcast(0, tprof_start_cpu, tb, (void *)(uintptr_t)runmask);
392 1.19 ryo xc_wait(xc);
393 1.19 ryo mutex_enter(&tprof_lock);
394 1.19 ryo tb->tb_softc.sc_ctr_running_mask |= runmask;
395 1.19 ryo mutex_exit(&tprof_lock);
396 1.19 ryo
397 1.19 ryo if (firstrun) {
398 1.19 ryo for (CPU_INFO_FOREACH(cii, ci)) {
399 1.19 ryo tprof_cpu_t * const c = tprof_cpu(ci);
400 1.1 yamt
401 1.19 ryo mutex_enter(&tprof_lock);
402 1.19 ryo tprof_nworker++;
403 1.19 ryo mutex_exit(&tprof_lock);
404 1.19 ryo workqueue_enqueue(tprof_wq, &c->c_work, ci);
405 1.1 yamt }
406 1.1 yamt }
407 1.20 chs error = 0;
408 1.20 chs
409 1.19 ryo done:
410 1.19 ryo return error;
411 1.19 ryo }
412 1.1 yamt
413 1.19 ryo static void
414 1.19 ryo tprof_stop(tprof_countermask_t stopmask)
415 1.19 ryo {
416 1.19 ryo tprof_backend_t *tb;
417 1.19 ryo uint64_t xc;
418 1.19 ryo
419 1.19 ryo tb = tprof_backend;
420 1.19 ryo if (tb == NULL)
421 1.19 ryo return;
422 1.19 ryo
423 1.19 ryo KASSERT(mutex_owned(&tprof_startstop_lock));
424 1.19 ryo stopmask &= tb->tb_softc.sc_ctr_running_mask;
425 1.19 ryo if (stopmask == 0) {
426 1.19 ryo /* targets are not running */
427 1.1 yamt goto done;
428 1.1 yamt }
429 1.1 yamt
430 1.19 ryo xc = xc_broadcast(0, tprof_stop_cpu, tb, (void *)(uintptr_t)stopmask);
431 1.19 ryo xc_wait(xc);
432 1.1 yamt mutex_enter(&tprof_lock);
433 1.19 ryo tb->tb_softc.sc_ctr_running_mask &= ~stopmask;
434 1.1 yamt mutex_exit(&tprof_lock);
435 1.1 yamt
436 1.19 ryo /* all counters have stopped? */
437 1.19 ryo if (tb->tb_softc.sc_ctr_running_mask == 0) {
438 1.1 yamt mutex_enter(&tprof_lock);
439 1.19 ryo cv_broadcast(&tprof_reader_cv);
440 1.19 ryo while (tprof_nworker > 0) {
441 1.19 ryo cv_wait(&tprof_cv, &tprof_lock);
442 1.19 ryo }
443 1.1 yamt mutex_exit(&tprof_lock);
444 1.19 ryo
445 1.19 ryo tprof_stop1();
446 1.19 ryo if (tb->tb_ops->tbo_disestablish != NULL)
447 1.19 ryo tb->tb_ops->tbo_disestablish(&tb->tb_softc);
448 1.1 yamt }
449 1.1 yamt done:
450 1.19 ryo ;
451 1.19 ryo }
452 1.19 ryo
453 1.19 ryo static void
454 1.19 ryo tprof_init_percpu_counters_offset(void *vp, void *vp2, struct cpu_info *ci)
455 1.19 ryo {
456 1.19 ryo uint64_t *counters_offset = vp;
457 1.19 ryo u_int counter = (uintptr_t)vp2;
458 1.19 ryo
459 1.19 ryo tprof_backend_t *tb = tprof_backend;
460 1.19 ryo tprof_param_t *param = &tb->tb_softc.sc_count[counter].ctr_param;
461 1.19 ryo counters_offset[counter] = param->p_value;
462 1.1 yamt }
463 1.1 yamt
464 1.1 yamt static void
465 1.19 ryo tprof_configure_event_cpu(void *arg1, void *arg2)
466 1.19 ryo {
467 1.19 ryo tprof_backend_t *tb = arg1;
468 1.19 ryo u_int counter = (uintptr_t)arg2;
469 1.19 ryo tprof_param_t *param = &tb->tb_softc.sc_count[counter].ctr_param;
470 1.19 ryo
471 1.19 ryo tb->tb_ops->tbo_configure_event(counter, param);
472 1.19 ryo }
473 1.19 ryo
474 1.19 ryo static int
475 1.19 ryo tprof_configure_event(const tprof_param_t *param)
476 1.1 yamt {
477 1.4 yamt tprof_backend_t *tb;
478 1.19 ryo tprof_backend_softc_t *sc;
479 1.19 ryo tprof_param_t *sc_param;
480 1.19 ryo uint64_t xc;
481 1.19 ryo int c, error;
482 1.1 yamt
483 1.19 ryo if ((param->p_flags & (TPROF_PARAM_USER | TPROF_PARAM_KERN)) == 0) {
484 1.19 ryo error = EINVAL;
485 1.1 yamt goto done;
486 1.1 yamt }
487 1.1 yamt
488 1.4 yamt tb = tprof_backend;
489 1.19 ryo if (tb == NULL) {
490 1.19 ryo error = ENOENT;
491 1.19 ryo goto done;
492 1.19 ryo }
493 1.19 ryo sc = &tb->tb_softc;
494 1.19 ryo
495 1.19 ryo c = param->p_counter;
496 1.19 ryo if (c >= tb->tb_softc.sc_ncounters) {
497 1.19 ryo error = EINVAL;
498 1.19 ryo goto done;
499 1.19 ryo }
500 1.19 ryo
501 1.19 ryo if (tb->tb_ops->tbo_valid_event != NULL) {
502 1.19 ryo error = tb->tb_ops->tbo_valid_event(param->p_counter, param);
503 1.19 ryo if (error != 0)
504 1.19 ryo goto done;
505 1.19 ryo }
506 1.19 ryo
507 1.19 ryo /* if already running, stop the counter */
508 1.19 ryo if (ISSET(c, tb->tb_softc.sc_ctr_running_mask))
509 1.19 ryo tprof_stop(__BIT(c));
510 1.19 ryo
511 1.19 ryo sc->sc_count[c].ctr_bitwidth =
512 1.19 ryo tb->tb_ops->tbo_counter_bitwidth(param->p_counter);
513 1.19 ryo
514 1.19 ryo sc_param = &sc->sc_count[c].ctr_param;
515 1.19 ryo memcpy(sc_param, param, sizeof(*sc_param)); /* save copy of param */
516 1.19 ryo
517 1.19 ryo if (ISSET(param->p_flags, TPROF_PARAM_PROFILE)) {
518 1.19 ryo uint64_t freq, inum, dnum;
519 1.19 ryo
520 1.19 ryo freq = tb->tb_ops->tbo_counter_estimate_freq(c);
521 1.19 ryo sc->sc_count[c].ctr_counter_val = freq / TPROF_HZ;
522 1.19 ryo if (sc->sc_count[c].ctr_counter_val == 0) {
523 1.19 ryo printf("%s: counter#%d frequency (%"PRIu64") is"
524 1.19 ryo " very low relative to TPROF_HZ (%u)\n", __func__,
525 1.19 ryo c, freq, TPROF_HZ);
526 1.19 ryo sc->sc_count[c].ctr_counter_val =
527 1.19 ryo 4000000000ULL / TPROF_HZ;
528 1.19 ryo }
529 1.19 ryo
530 1.19 ryo switch (param->p_flags & TPROF_PARAM_VALUE2_MASK) {
531 1.19 ryo case TPROF_PARAM_VALUE2_SCALE:
532 1.19 ryo if (sc_param->p_value2 == 0)
533 1.19 ryo break;
534 1.19 ryo /*
535 1.19 ryo * p_value2 is 64-bit fixed-point
536 1.19 ryo * upper 32 bits are the integer part
537 1.19 ryo * lower 32 bits are the decimal part
538 1.19 ryo */
539 1.19 ryo inum = sc_param->p_value2 >> 32;
540 1.19 ryo dnum = sc_param->p_value2 & __BITS(31, 0);
541 1.19 ryo sc->sc_count[c].ctr_counter_val =
542 1.19 ryo sc->sc_count[c].ctr_counter_val * inum +
543 1.19 ryo (sc->sc_count[c].ctr_counter_val * dnum >> 32);
544 1.19 ryo if (sc->sc_count[c].ctr_counter_val == 0)
545 1.19 ryo sc->sc_count[c].ctr_counter_val = 1;
546 1.19 ryo break;
547 1.19 ryo case TPROF_PARAM_VALUE2_TRIGGERCOUNT:
548 1.19 ryo if (sc_param->p_value2 == 0)
549 1.19 ryo sc_param->p_value2 = 1;
550 1.19 ryo if (sc_param->p_value2 >
551 1.19 ryo __BITS(sc->sc_count[c].ctr_bitwidth - 1, 0)) {
552 1.19 ryo sc_param->p_value2 =
553 1.19 ryo __BITS(sc->sc_count[c].ctr_bitwidth - 1, 0);
554 1.19 ryo }
555 1.19 ryo sc->sc_count[c].ctr_counter_val = sc_param->p_value2;
556 1.19 ryo break;
557 1.19 ryo default:
558 1.19 ryo break;
559 1.19 ryo }
560 1.19 ryo sc->sc_count[c].ctr_counter_reset_val =
561 1.19 ryo -sc->sc_count[c].ctr_counter_val;
562 1.19 ryo sc->sc_count[c].ctr_counter_reset_val &=
563 1.19 ryo __BITS(sc->sc_count[c].ctr_bitwidth - 1, 0);
564 1.19 ryo } else {
565 1.19 ryo sc->sc_count[c].ctr_counter_val = 0;
566 1.19 ryo sc->sc_count[c].ctr_counter_reset_val = 0;
567 1.19 ryo }
568 1.19 ryo
569 1.19 ryo /* At this point, p_value is used as an initial value */
570 1.19 ryo percpu_foreach(tb->tb_softc.sc_ctr_offset_percpu,
571 1.19 ryo tprof_init_percpu_counters_offset, (void *)(uintptr_t)c);
572 1.19 ryo /* On the backend side, p_value is used as the reset value */
573 1.19 ryo sc_param->p_value = tb->tb_softc.sc_count[c].ctr_counter_reset_val;
574 1.19 ryo
575 1.19 ryo xc = xc_broadcast(0, tprof_configure_event_cpu,
576 1.19 ryo tb, (void *)(uintptr_t)c);
577 1.19 ryo xc_wait(xc);
578 1.1 yamt
579 1.1 yamt mutex_enter(&tprof_lock);
580 1.19 ryo /* update counters bitmasks */
581 1.19 ryo SET(tb->tb_softc.sc_ctr_configured_mask, __BIT(c));
582 1.19 ryo CLR(tb->tb_softc.sc_ctr_prof_mask, __BIT(c));
583 1.19 ryo CLR(tb->tb_softc.sc_ctr_ovf_mask, __BIT(c));
584 1.19 ryo /* profiled counter requires overflow handling */
585 1.19 ryo if (ISSET(param->p_flags, TPROF_PARAM_PROFILE)) {
586 1.19 ryo SET(tb->tb_softc.sc_ctr_prof_mask, __BIT(c));
587 1.19 ryo SET(tb->tb_softc.sc_ctr_ovf_mask, __BIT(c));
588 1.19 ryo }
589 1.19 ryo /* counters with less than 64bits also require overflow handling */
590 1.19 ryo if (sc->sc_count[c].ctr_bitwidth != 64)
591 1.19 ryo SET(tb->tb_softc.sc_ctr_ovf_mask, __BIT(c));
592 1.19 ryo mutex_exit(&tprof_lock);
593 1.19 ryo
594 1.19 ryo error = 0;
595 1.19 ryo
596 1.19 ryo done:
597 1.19 ryo return error;
598 1.19 ryo }
599 1.19 ryo
600 1.19 ryo static void
601 1.19 ryo tprof_getcounts_cpu(void *arg1, void *arg2)
602 1.19 ryo {
603 1.19 ryo tprof_backend_t *tb = arg1;
604 1.19 ryo tprof_backend_softc_t *sc = &tb->tb_softc;
605 1.19 ryo uint64_t *counters = arg2;
606 1.19 ryo uint64_t *counters_offset;
607 1.19 ryo unsigned int c;
608 1.19 ryo
609 1.19 ryo tprof_countermask_t configmask = sc->sc_ctr_configured_mask;
610 1.19 ryo counters_offset = percpu_getref(sc->sc_ctr_offset_percpu);
611 1.19 ryo for (c = 0; c < sc->sc_ncounters; c++) {
612 1.19 ryo if (ISSET(configmask, __BIT(c))) {
613 1.19 ryo uint64_t ctr = tb->tb_ops->tbo_counter_read(c);
614 1.19 ryo counters[c] = counters_offset[c] +
615 1.19 ryo ((ctr - sc->sc_count[c].ctr_counter_reset_val) &
616 1.19 ryo __BITS(sc->sc_count[c].ctr_bitwidth - 1, 0));
617 1.19 ryo } else {
618 1.19 ryo counters[c] = 0;
619 1.19 ryo }
620 1.8 yamt }
621 1.19 ryo percpu_putref(sc->sc_ctr_offset_percpu);
622 1.19 ryo }
623 1.19 ryo
624 1.19 ryo static int
625 1.19 ryo tprof_getcounts(tprof_counts_t *counts)
626 1.19 ryo {
627 1.19 ryo struct cpu_info *ci;
628 1.19 ryo tprof_backend_t *tb;
629 1.19 ryo uint64_t xc;
630 1.19 ryo
631 1.19 ryo tb = tprof_backend;
632 1.19 ryo if (tb == NULL)
633 1.19 ryo return ENOENT;
634 1.19 ryo
635 1.19 ryo if (counts->c_cpu >= ncpu)
636 1.19 ryo return ESRCH;
637 1.19 ryo ci = cpu_lookup(counts->c_cpu);
638 1.19 ryo if (ci == NULL)
639 1.19 ryo return ESRCH;
640 1.19 ryo
641 1.19 ryo xc = xc_unicast(0, tprof_getcounts_cpu, tb, counts->c_count, ci);
642 1.19 ryo xc_wait(xc);
643 1.1 yamt
644 1.19 ryo counts->c_ncounters = tb->tb_softc.sc_ncounters;
645 1.19 ryo counts->c_runningmask = tb->tb_softc.sc_ctr_running_mask;
646 1.19 ryo return 0;
647 1.1 yamt }
648 1.1 yamt
649 1.4 yamt /*
650 1.4 yamt * tprof_clear: drain unread samples.
651 1.4 yamt */
652 1.4 yamt
653 1.1 yamt static void
654 1.1 yamt tprof_clear(void)
655 1.1 yamt {
656 1.1 yamt tprof_buf_t *buf;
657 1.1 yamt
658 1.1 yamt mutex_enter(&tprof_reader_lock);
659 1.1 yamt mutex_enter(&tprof_lock);
660 1.1 yamt while ((buf = STAILQ_FIRST(&tprof_list)) != NULL) {
661 1.1 yamt if (buf != NULL) {
662 1.1 yamt STAILQ_REMOVE_HEAD(&tprof_list, b_list);
663 1.1 yamt KASSERT(tprof_nbuf_on_list > 0);
664 1.1 yamt tprof_nbuf_on_list--;
665 1.1 yamt mutex_exit(&tprof_lock);
666 1.1 yamt tprof_buf_free(buf);
667 1.1 yamt mutex_enter(&tprof_lock);
668 1.1 yamt }
669 1.1 yamt }
670 1.1 yamt KASSERT(tprof_nbuf_on_list == 0);
671 1.1 yamt mutex_exit(&tprof_lock);
672 1.1 yamt tprof_reader_offset = 0;
673 1.1 yamt mutex_exit(&tprof_reader_lock);
674 1.1 yamt
675 1.1 yamt memset(&tprof_stat, 0, sizeof(tprof_stat));
676 1.1 yamt }
677 1.1 yamt
678 1.4 yamt static tprof_backend_t *
679 1.4 yamt tprof_backend_lookup(const char *name)
680 1.4 yamt {
681 1.4 yamt tprof_backend_t *tb;
682 1.4 yamt
683 1.4 yamt KASSERT(mutex_owned(&tprof_startstop_lock));
684 1.4 yamt
685 1.4 yamt LIST_FOREACH(tb, &tprof_backends, tb_list) {
686 1.4 yamt if (!strcmp(tb->tb_name, name)) {
687 1.4 yamt return tb;
688 1.4 yamt }
689 1.4 yamt }
690 1.4 yamt return NULL;
691 1.4 yamt }
692 1.4 yamt
693 1.1 yamt /* -------------------- backend interfaces */
694 1.1 yamt
695 1.1 yamt /*
696 1.1 yamt * tprof_sample: record a sample on the per-cpu buffer.
697 1.1 yamt *
698 1.1 yamt * be careful; can be called in NMI context.
699 1.10 yamt * we are bluntly assuming the followings are safe.
700 1.10 yamt * curcpu()
701 1.10 yamt * curlwp->l_lid
702 1.10 yamt * curlwp->l_proc->p_pid
703 1.1 yamt */
704 1.1 yamt
705 1.1 yamt void
706 1.14 maxv tprof_sample(void *unused, const tprof_frame_info_t *tfi)
707 1.1 yamt {
708 1.18 ryo tprof_cpu_t * const c = tprof_cpu_direct(curcpu());
709 1.1 yamt tprof_buf_t * const buf = c->c_buf;
710 1.8 yamt tprof_sample_t *sp;
711 1.5 yamt const uintptr_t pc = tfi->tfi_pc;
712 1.10 yamt const lwp_t * const l = curlwp;
713 1.1 yamt u_int idx;
714 1.1 yamt
715 1.1 yamt idx = buf->b_used;
716 1.1 yamt if (__predict_false(idx >= buf->b_size)) {
717 1.1 yamt buf->b_overflow++;
718 1.1 yamt return;
719 1.1 yamt }
720 1.8 yamt sp = &buf->b_data[idx];
721 1.10 yamt sp->s_pid = l->l_proc->p_pid;
722 1.10 yamt sp->s_lwpid = l->l_lid;
723 1.10 yamt sp->s_cpuid = c->c_cpuid;
724 1.19 ryo sp->s_flags = ((tfi->tfi_inkernel) ? TPROF_SAMPLE_INKERNEL : 0) |
725 1.19 ryo __SHIFTIN(tfi->tfi_counter, TPROF_SAMPLE_COUNTER_MASK);
726 1.8 yamt sp->s_pc = pc;
727 1.1 yamt buf->b_used = idx + 1;
728 1.1 yamt }
729 1.1 yamt
730 1.4 yamt /*
731 1.16 skrll * tprof_backend_register:
732 1.4 yamt */
733 1.4 yamt
734 1.4 yamt int
735 1.4 yamt tprof_backend_register(const char *name, const tprof_backend_ops_t *ops,
736 1.4 yamt int vers)
737 1.4 yamt {
738 1.4 yamt tprof_backend_t *tb;
739 1.4 yamt
740 1.4 yamt if (vers != TPROF_BACKEND_VERSION) {
741 1.4 yamt return EINVAL;
742 1.4 yamt }
743 1.4 yamt
744 1.4 yamt mutex_enter(&tprof_startstop_lock);
745 1.4 yamt tb = tprof_backend_lookup(name);
746 1.4 yamt if (tb != NULL) {
747 1.4 yamt mutex_exit(&tprof_startstop_lock);
748 1.4 yamt return EEXIST;
749 1.4 yamt }
750 1.4 yamt #if 1 /* XXX for now */
751 1.4 yamt if (!LIST_EMPTY(&tprof_backends)) {
752 1.4 yamt mutex_exit(&tprof_startstop_lock);
753 1.4 yamt return ENOTSUP;
754 1.4 yamt }
755 1.4 yamt #endif
756 1.19 ryo tb = kmem_zalloc(sizeof(*tb), KM_SLEEP);
757 1.4 yamt tb->tb_name = name;
758 1.4 yamt tb->tb_ops = ops;
759 1.4 yamt LIST_INSERT_HEAD(&tprof_backends, tb, tb_list);
760 1.4 yamt #if 1 /* XXX for now */
761 1.4 yamt if (tprof_backend == NULL) {
762 1.4 yamt tprof_backend = tb;
763 1.4 yamt }
764 1.4 yamt #endif
765 1.4 yamt mutex_exit(&tprof_startstop_lock);
766 1.4 yamt
767 1.19 ryo /* init backend softc */
768 1.19 ryo tb->tb_softc.sc_ncounters = tb->tb_ops->tbo_ncounters();
769 1.19 ryo tb->tb_softc.sc_ctr_offset_percpu_size =
770 1.19 ryo sizeof(uint64_t) * tb->tb_softc.sc_ncounters;
771 1.19 ryo tb->tb_softc.sc_ctr_offset_percpu =
772 1.19 ryo percpu_alloc(tb->tb_softc.sc_ctr_offset_percpu_size);
773 1.19 ryo
774 1.4 yamt return 0;
775 1.4 yamt }
776 1.4 yamt
777 1.4 yamt /*
778 1.16 skrll * tprof_backend_unregister:
779 1.4 yamt */
780 1.4 yamt
781 1.4 yamt int
782 1.4 yamt tprof_backend_unregister(const char *name)
783 1.4 yamt {
784 1.4 yamt tprof_backend_t *tb;
785 1.4 yamt
786 1.4 yamt mutex_enter(&tprof_startstop_lock);
787 1.4 yamt tb = tprof_backend_lookup(name);
788 1.4 yamt #if defined(DIAGNOSTIC)
789 1.4 yamt if (tb == NULL) {
790 1.4 yamt mutex_exit(&tprof_startstop_lock);
791 1.4 yamt panic("%s: not found '%s'", __func__, name);
792 1.4 yamt }
793 1.4 yamt #endif /* defined(DIAGNOSTIC) */
794 1.19 ryo if (tb->tb_softc.sc_ctr_running_mask != 0) {
795 1.4 yamt mutex_exit(&tprof_startstop_lock);
796 1.4 yamt return EBUSY;
797 1.4 yamt }
798 1.4 yamt #if 1 /* XXX for now */
799 1.4 yamt if (tprof_backend == tb) {
800 1.4 yamt tprof_backend = NULL;
801 1.4 yamt }
802 1.4 yamt #endif
803 1.4 yamt LIST_REMOVE(tb, tb_list);
804 1.4 yamt mutex_exit(&tprof_startstop_lock);
805 1.4 yamt
806 1.19 ryo /* fini backend softc */
807 1.19 ryo percpu_free(tb->tb_softc.sc_ctr_offset_percpu,
808 1.19 ryo tb->tb_softc.sc_ctr_offset_percpu_size);
809 1.19 ryo
810 1.19 ryo /* free backend */
811 1.4 yamt kmem_free(tb, sizeof(*tb));
812 1.4 yamt
813 1.4 yamt return 0;
814 1.4 yamt }
815 1.4 yamt
816 1.1 yamt /* -------------------- cdevsw interfaces */
817 1.1 yamt
818 1.1 yamt static int
819 1.1 yamt tprof_open(dev_t dev, int flags, int type, struct lwp *l)
820 1.1 yamt {
821 1.1 yamt
822 1.1 yamt if (minor(dev) != 0) {
823 1.1 yamt return EXDEV;
824 1.1 yamt }
825 1.1 yamt mutex_enter(&tprof_lock);
826 1.1 yamt if (tprof_owner != NULL) {
827 1.1 yamt mutex_exit(&tprof_lock);
828 1.1 yamt return EBUSY;
829 1.1 yamt }
830 1.1 yamt tprof_owner = curlwp;
831 1.1 yamt mutex_exit(&tprof_lock);
832 1.1 yamt
833 1.1 yamt return 0;
834 1.1 yamt }
835 1.1 yamt
836 1.1 yamt static int
837 1.1 yamt tprof_close(dev_t dev, int flags, int type, struct lwp *l)
838 1.1 yamt {
839 1.1 yamt
840 1.1 yamt KASSERT(minor(dev) == 0);
841 1.1 yamt
842 1.1 yamt mutex_enter(&tprof_startstop_lock);
843 1.1 yamt mutex_enter(&tprof_lock);
844 1.1 yamt tprof_owner = NULL;
845 1.1 yamt mutex_exit(&tprof_lock);
846 1.19 ryo tprof_stop(TPROF_COUNTERMASK_ALL);
847 1.1 yamt tprof_clear();
848 1.19 ryo
849 1.19 ryo tprof_backend_t *tb = tprof_backend;
850 1.19 ryo if (tb != NULL) {
851 1.19 ryo KASSERT(tb->tb_softc.sc_ctr_running_mask == 0);
852 1.19 ryo tb->tb_softc.sc_ctr_configured_mask = 0;
853 1.19 ryo tb->tb_softc.sc_ctr_prof_mask = 0;
854 1.19 ryo tb->tb_softc.sc_ctr_ovf_mask = 0;
855 1.19 ryo }
856 1.19 ryo
857 1.1 yamt mutex_exit(&tprof_startstop_lock);
858 1.1 yamt
859 1.1 yamt return 0;
860 1.1 yamt }
861 1.1 yamt
862 1.1 yamt static int
863 1.1 yamt tprof_read(dev_t dev, struct uio *uio, int flags)
864 1.1 yamt {
865 1.1 yamt tprof_buf_t *buf;
866 1.1 yamt size_t bytes;
867 1.1 yamt size_t resid;
868 1.1 yamt size_t done;
869 1.1 yamt int error = 0;
870 1.1 yamt
871 1.1 yamt KASSERT(minor(dev) == 0);
872 1.1 yamt mutex_enter(&tprof_reader_lock);
873 1.1 yamt while (uio->uio_resid > 0 && error == 0) {
874 1.1 yamt /*
875 1.1 yamt * take the first buffer from the list.
876 1.1 yamt */
877 1.1 yamt mutex_enter(&tprof_lock);
878 1.1 yamt buf = STAILQ_FIRST(&tprof_list);
879 1.1 yamt if (buf == NULL) {
880 1.1 yamt if (tprof_nworker == 0) {
881 1.1 yamt mutex_exit(&tprof_lock);
882 1.1 yamt error = 0;
883 1.1 yamt break;
884 1.1 yamt }
885 1.1 yamt mutex_exit(&tprof_reader_lock);
886 1.1 yamt error = cv_wait_sig(&tprof_reader_cv, &tprof_lock);
887 1.1 yamt mutex_exit(&tprof_lock);
888 1.1 yamt mutex_enter(&tprof_reader_lock);
889 1.1 yamt continue;
890 1.1 yamt }
891 1.1 yamt STAILQ_REMOVE_HEAD(&tprof_list, b_list);
892 1.1 yamt KASSERT(tprof_nbuf_on_list > 0);
893 1.1 yamt tprof_nbuf_on_list--;
894 1.1 yamt mutex_exit(&tprof_lock);
895 1.1 yamt
896 1.1 yamt /*
897 1.1 yamt * copy it out.
898 1.1 yamt */
899 1.1 yamt bytes = MIN(buf->b_used * sizeof(tprof_sample_t) -
900 1.1 yamt tprof_reader_offset, uio->uio_resid);
901 1.1 yamt resid = uio->uio_resid;
902 1.1 yamt error = uiomove((char *)buf->b_data + tprof_reader_offset,
903 1.1 yamt bytes, uio);
904 1.1 yamt done = resid - uio->uio_resid;
905 1.1 yamt tprof_reader_offset += done;
906 1.1 yamt
907 1.1 yamt /*
908 1.1 yamt * if we didn't consume the whole buffer,
909 1.1 yamt * put it back to the list.
910 1.1 yamt */
911 1.1 yamt if (tprof_reader_offset <
912 1.1 yamt buf->b_used * sizeof(tprof_sample_t)) {
913 1.1 yamt mutex_enter(&tprof_lock);
914 1.1 yamt STAILQ_INSERT_HEAD(&tprof_list, buf, b_list);
915 1.1 yamt tprof_nbuf_on_list++;
916 1.1 yamt cv_broadcast(&tprof_reader_cv);
917 1.1 yamt mutex_exit(&tprof_lock);
918 1.1 yamt } else {
919 1.1 yamt tprof_buf_free(buf);
920 1.1 yamt tprof_reader_offset = 0;
921 1.1 yamt }
922 1.1 yamt }
923 1.1 yamt mutex_exit(&tprof_reader_lock);
924 1.1 yamt
925 1.1 yamt return error;
926 1.1 yamt }
927 1.1 yamt
928 1.1 yamt static int
929 1.1 yamt tprof_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
930 1.1 yamt {
931 1.14 maxv const tprof_param_t *param;
932 1.19 ryo tprof_counts_t *counts;
933 1.1 yamt int error = 0;
934 1.1 yamt
935 1.1 yamt KASSERT(minor(dev) == 0);
936 1.1 yamt
937 1.1 yamt switch (cmd) {
938 1.14 maxv case TPROF_IOC_GETINFO:
939 1.14 maxv mutex_enter(&tprof_startstop_lock);
940 1.14 maxv tprof_getinfo(data);
941 1.14 maxv mutex_exit(&tprof_startstop_lock);
942 1.1 yamt break;
943 1.19 ryo case TPROF_IOC_GETNCOUNTERS:
944 1.19 ryo mutex_enter(&tprof_lock);
945 1.19 ryo error = tprof_getncounters((u_int *)data);
946 1.19 ryo mutex_exit(&tprof_lock);
947 1.19 ryo break;
948 1.1 yamt case TPROF_IOC_START:
949 1.1 yamt mutex_enter(&tprof_startstop_lock);
950 1.19 ryo error = tprof_start(*(tprof_countermask_t *)data);
951 1.1 yamt mutex_exit(&tprof_startstop_lock);
952 1.1 yamt break;
953 1.1 yamt case TPROF_IOC_STOP:
954 1.1 yamt mutex_enter(&tprof_startstop_lock);
955 1.19 ryo tprof_stop(*(tprof_countermask_t *)data);
956 1.1 yamt mutex_exit(&tprof_startstop_lock);
957 1.1 yamt break;
958 1.1 yamt case TPROF_IOC_GETSTAT:
959 1.1 yamt mutex_enter(&tprof_lock);
960 1.1 yamt memcpy(data, &tprof_stat, sizeof(tprof_stat));
961 1.1 yamt mutex_exit(&tprof_lock);
962 1.1 yamt break;
963 1.19 ryo case TPROF_IOC_CONFIGURE_EVENT:
964 1.19 ryo param = data;
965 1.19 ryo mutex_enter(&tprof_startstop_lock);
966 1.19 ryo error = tprof_configure_event(param);
967 1.19 ryo mutex_exit(&tprof_startstop_lock);
968 1.19 ryo break;
969 1.19 ryo case TPROF_IOC_GETCOUNTS:
970 1.19 ryo counts = data;
971 1.19 ryo mutex_enter(&tprof_startstop_lock);
972 1.19 ryo error = tprof_getcounts(counts);
973 1.19 ryo mutex_exit(&tprof_startstop_lock);
974 1.19 ryo break;
975 1.1 yamt default:
976 1.1 yamt error = EINVAL;
977 1.1 yamt break;
978 1.1 yamt }
979 1.1 yamt
980 1.1 yamt return error;
981 1.1 yamt }
982 1.1 yamt
983 1.1 yamt const struct cdevsw tprof_cdevsw = {
984 1.1 yamt .d_open = tprof_open,
985 1.1 yamt .d_close = tprof_close,
986 1.1 yamt .d_read = tprof_read,
987 1.1 yamt .d_write = nowrite,
988 1.1 yamt .d_ioctl = tprof_ioctl,
989 1.1 yamt .d_stop = nostop,
990 1.1 yamt .d_tty = notty,
991 1.1 yamt .d_poll = nopoll,
992 1.1 yamt .d_mmap = nommap,
993 1.1 yamt .d_kqfilter = nokqfilter,
994 1.12 dholland .d_discard = nodiscard,
995 1.11 dholland .d_flag = D_OTHER | D_MPSAFE
996 1.1 yamt };
997 1.1 yamt
998 1.1 yamt void
999 1.1 yamt tprofattach(int nunits)
1000 1.1 yamt {
1001 1.1 yamt
1002 1.4 yamt /* nothing */
1003 1.4 yamt }
1004 1.4 yamt
1005 1.4 yamt MODULE(MODULE_CLASS_DRIVER, tprof, NULL);
1006 1.4 yamt
1007 1.4 yamt static void
1008 1.15 riastrad tprof_cpu_init(void *vcp, void *vcookie, struct cpu_info *ci)
1009 1.15 riastrad {
1010 1.15 riastrad tprof_cpu_t **cp = vcp, *c;
1011 1.15 riastrad
1012 1.15 riastrad c = kmem_zalloc(sizeof(*c), KM_SLEEP);
1013 1.15 riastrad c->c_buf = NULL;
1014 1.15 riastrad c->c_cpuid = cpu_index(ci);
1015 1.15 riastrad *cp = c;
1016 1.15 riastrad }
1017 1.15 riastrad
1018 1.15 riastrad static void
1019 1.15 riastrad tprof_cpu_fini(void *vcp, void *vcookie, struct cpu_info *ci)
1020 1.15 riastrad {
1021 1.15 riastrad tprof_cpu_t **cp = vcp, *c;
1022 1.15 riastrad
1023 1.15 riastrad c = *cp;
1024 1.15 riastrad KASSERT(c->c_cpuid == cpu_index(ci));
1025 1.15 riastrad KASSERT(c->c_buf == NULL);
1026 1.15 riastrad kmem_free(c, sizeof(*c));
1027 1.15 riastrad *cp = NULL;
1028 1.15 riastrad }
1029 1.15 riastrad
1030 1.15 riastrad static void
1031 1.4 yamt tprof_driver_init(void)
1032 1.4 yamt {
1033 1.4 yamt
1034 1.1 yamt mutex_init(&tprof_lock, MUTEX_DEFAULT, IPL_NONE);
1035 1.1 yamt mutex_init(&tprof_reader_lock, MUTEX_DEFAULT, IPL_NONE);
1036 1.1 yamt mutex_init(&tprof_startstop_lock, MUTEX_DEFAULT, IPL_NONE);
1037 1.1 yamt cv_init(&tprof_cv, "tprof");
1038 1.7 pgoyette cv_init(&tprof_reader_cv, "tprof_rd");
1039 1.1 yamt STAILQ_INIT(&tprof_list);
1040 1.15 riastrad tprof_cpus = percpu_create(sizeof(tprof_cpu_t *),
1041 1.15 riastrad tprof_cpu_init, tprof_cpu_fini, NULL);
1042 1.1 yamt }
1043 1.4 yamt
1044 1.4 yamt static void
1045 1.4 yamt tprof_driver_fini(void)
1046 1.4 yamt {
1047 1.4 yamt
1048 1.15 riastrad percpu_free(tprof_cpus, sizeof(tprof_cpu_t *));
1049 1.4 yamt mutex_destroy(&tprof_lock);
1050 1.4 yamt mutex_destroy(&tprof_reader_lock);
1051 1.4 yamt mutex_destroy(&tprof_startstop_lock);
1052 1.4 yamt cv_destroy(&tprof_cv);
1053 1.4 yamt cv_destroy(&tprof_reader_cv);
1054 1.4 yamt }
1055 1.4 yamt
1056 1.4 yamt static int
1057 1.4 yamt tprof_modcmd(modcmd_t cmd, void *arg)
1058 1.4 yamt {
1059 1.4 yamt
1060 1.4 yamt switch (cmd) {
1061 1.4 yamt case MODULE_CMD_INIT:
1062 1.4 yamt tprof_driver_init();
1063 1.4 yamt #if defined(_MODULE)
1064 1.4 yamt {
1065 1.4 yamt devmajor_t bmajor = NODEVMAJOR;
1066 1.4 yamt devmajor_t cmajor = NODEVMAJOR;
1067 1.4 yamt int error;
1068 1.4 yamt
1069 1.4 yamt error = devsw_attach("tprof", NULL, &bmajor,
1070 1.4 yamt &tprof_cdevsw, &cmajor);
1071 1.4 yamt if (error) {
1072 1.4 yamt tprof_driver_fini();
1073 1.4 yamt return error;
1074 1.4 yamt }
1075 1.4 yamt }
1076 1.4 yamt #endif /* defined(_MODULE) */
1077 1.4 yamt return 0;
1078 1.4 yamt
1079 1.4 yamt case MODULE_CMD_FINI:
1080 1.4 yamt #if defined(_MODULE)
1081 1.17 riastrad devsw_detach(NULL, &tprof_cdevsw);
1082 1.4 yamt #endif /* defined(_MODULE) */
1083 1.4 yamt tprof_driver_fini();
1084 1.4 yamt return 0;
1085 1.4 yamt
1086 1.4 yamt default:
1087 1.4 yamt return ENOTTY;
1088 1.4 yamt }
1089 1.4 yamt }
1090