tprof.c revision 1.23 1 1.23 msaitoh /* $NetBSD: tprof.c,v 1.23 2023/04/11 10:07:12 msaitoh 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.23 msaitoh __KERNEL_RCSID(0, "$NetBSD: tprof.c,v 1.23 2023/04/11 10:07:12 msaitoh 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.21 ryo #include <sys/poll.h>
43 1.8 yamt #include <sys/proc.h>
44 1.15 riastrad #include <sys/queue.h>
45 1.21 ryo #include <sys/select.h>
46 1.1 yamt #include <sys/workqueue.h>
47 1.19 ryo #include <sys/xcall.h>
48 1.1 yamt
49 1.1 yamt #include <dev/tprof/tprof.h>
50 1.1 yamt #include <dev/tprof/tprof_ioctl.h>
51 1.1 yamt
52 1.13 christos #include "ioconf.h"
53 1.13 christos
54 1.19 ryo #ifndef TPROF_HZ
55 1.19 ryo #define TPROF_HZ 10000
56 1.19 ryo #endif
57 1.19 ryo
58 1.4 yamt /*
59 1.4 yamt * locking order:
60 1.4 yamt * tprof_reader_lock -> tprof_lock
61 1.4 yamt * tprof_startstop_lock -> tprof_lock
62 1.4 yamt */
63 1.4 yamt
64 1.4 yamt /*
65 1.4 yamt * protected by:
66 1.4 yamt * L: tprof_lock
67 1.4 yamt * R: tprof_reader_lock
68 1.4 yamt * S: tprof_startstop_lock
69 1.8 yamt * s: writer should hold tprof_startstop_lock and tprof_lock
70 1.8 yamt * reader should hold tprof_startstop_lock or tprof_lock
71 1.4 yamt */
72 1.4 yamt
73 1.1 yamt typedef struct tprof_buf {
74 1.1 yamt u_int b_used;
75 1.1 yamt u_int b_size;
76 1.1 yamt u_int b_overflow;
77 1.1 yamt u_int b_unused;
78 1.1 yamt STAILQ_ENTRY(tprof_buf) b_list;
79 1.1 yamt tprof_sample_t b_data[];
80 1.1 yamt } tprof_buf_t;
81 1.1 yamt #define TPROF_BUF_BYTESIZE(sz) \
82 1.1 yamt (sizeof(tprof_buf_t) + (sz) * sizeof(tprof_sample_t))
83 1.21 ryo #define TPROF_MAX_SAMPLES_PER_BUF TPROF_HZ
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.21 ryo static u_int tprof_max_buf;
115 1.1 yamt
116 1.19 ryo tprof_backend_t *tprof_backend; /* S: */
117 1.4 yamt static LIST_HEAD(, tprof_backend) tprof_backends =
118 1.4 yamt LIST_HEAD_INITIALIZER(tprof_backend); /* S: */
119 1.4 yamt
120 1.1 yamt static kmutex_t tprof_reader_lock;
121 1.4 yamt static kcondvar_t tprof_reader_cv; /* L: */
122 1.4 yamt static off_t tprof_reader_offset; /* R: */
123 1.1 yamt
124 1.1 yamt static kmutex_t tprof_startstop_lock;
125 1.4 yamt static kcondvar_t tprof_cv; /* L: */
126 1.21 ryo static struct selinfo tprof_selp; /* L: */
127 1.1 yamt
128 1.4 yamt static struct tprof_stat tprof_stat; /* L: */
129 1.1 yamt
130 1.1 yamt static tprof_cpu_t *
131 1.18 ryo tprof_cpu_direct(struct cpu_info *ci)
132 1.18 ryo {
133 1.18 ryo tprof_cpu_t **cp;
134 1.18 ryo
135 1.18 ryo cp = percpu_getptr_remote(tprof_cpus, ci);
136 1.18 ryo return *cp;
137 1.18 ryo }
138 1.18 ryo
139 1.18 ryo static tprof_cpu_t *
140 1.1 yamt tprof_cpu(struct cpu_info *ci)
141 1.1 yamt {
142 1.18 ryo tprof_cpu_t *c;
143 1.1 yamt
144 1.15 riastrad /*
145 1.15 riastrad * As long as xcalls are blocked -- e.g., by kpreempt_disable
146 1.15 riastrad * -- the percpu object will not be swapped and destroyed. We
147 1.15 riastrad * can't write to it, because the data may have already been
148 1.15 riastrad * moved to a new buffer, but we can safely read from it.
149 1.15 riastrad */
150 1.15 riastrad kpreempt_disable();
151 1.18 ryo c = tprof_cpu_direct(ci);
152 1.15 riastrad kpreempt_enable();
153 1.15 riastrad
154 1.15 riastrad return c;
155 1.1 yamt }
156 1.1 yamt
157 1.1 yamt static tprof_cpu_t *
158 1.1 yamt tprof_curcpu(void)
159 1.1 yamt {
160 1.1 yamt
161 1.1 yamt return tprof_cpu(curcpu());
162 1.1 yamt }
163 1.1 yamt
164 1.1 yamt static tprof_buf_t *
165 1.1 yamt tprof_buf_alloc(void)
166 1.1 yamt {
167 1.1 yamt tprof_buf_t *new;
168 1.1 yamt u_int size = tprof_samples_per_buf;
169 1.15 riastrad
170 1.1 yamt new = kmem_alloc(TPROF_BUF_BYTESIZE(size), KM_SLEEP);
171 1.1 yamt new->b_used = 0;
172 1.1 yamt new->b_size = size;
173 1.1 yamt new->b_overflow = 0;
174 1.1 yamt return new;
175 1.1 yamt }
176 1.1 yamt
177 1.1 yamt static void
178 1.1 yamt tprof_buf_free(tprof_buf_t *buf)
179 1.1 yamt {
180 1.1 yamt
181 1.1 yamt kmem_free(buf, TPROF_BUF_BYTESIZE(buf->b_size));
182 1.1 yamt }
183 1.1 yamt
184 1.1 yamt static tprof_buf_t *
185 1.1 yamt tprof_buf_switch(tprof_cpu_t *c, tprof_buf_t *new)
186 1.1 yamt {
187 1.1 yamt tprof_buf_t *old;
188 1.1 yamt
189 1.1 yamt old = c->c_buf;
190 1.1 yamt c->c_buf = new;
191 1.1 yamt return old;
192 1.1 yamt }
193 1.1 yamt
194 1.1 yamt static tprof_buf_t *
195 1.1 yamt tprof_buf_refresh(void)
196 1.1 yamt {
197 1.1 yamt tprof_cpu_t * const c = tprof_curcpu();
198 1.1 yamt tprof_buf_t *new;
199 1.1 yamt
200 1.1 yamt new = tprof_buf_alloc();
201 1.1 yamt return tprof_buf_switch(c, new);
202 1.1 yamt }
203 1.1 yamt
204 1.1 yamt static void
205 1.1 yamt tprof_worker(struct work *wk, void *dummy)
206 1.1 yamt {
207 1.1 yamt tprof_cpu_t * const c = tprof_curcpu();
208 1.1 yamt tprof_buf_t *buf;
209 1.19 ryo tprof_backend_t *tb;
210 1.1 yamt bool shouldstop;
211 1.1 yamt
212 1.1 yamt KASSERT(wk == &c->c_work);
213 1.1 yamt KASSERT(dummy == NULL);
214 1.1 yamt
215 1.1 yamt /*
216 1.23 msaitoh * Get a per cpu buffer.
217 1.1 yamt */
218 1.1 yamt buf = tprof_buf_refresh();
219 1.1 yamt
220 1.1 yamt /*
221 1.1 yamt * and put it on the global list for read(2).
222 1.1 yamt */
223 1.1 yamt mutex_enter(&tprof_lock);
224 1.19 ryo tb = tprof_backend;
225 1.19 ryo shouldstop = (tb == NULL || tb->tb_softc.sc_ctr_running_mask == 0);
226 1.1 yamt if (shouldstop) {
227 1.1 yamt KASSERT(tprof_nworker > 0);
228 1.1 yamt tprof_nworker--;
229 1.1 yamt cv_broadcast(&tprof_cv);
230 1.1 yamt cv_broadcast(&tprof_reader_cv);
231 1.1 yamt }
232 1.1 yamt if (buf->b_used == 0) {
233 1.1 yamt tprof_stat.ts_emptybuf++;
234 1.21 ryo } else if (tprof_nbuf_on_list < tprof_max_buf) {
235 1.1 yamt tprof_stat.ts_sample += buf->b_used;
236 1.1 yamt tprof_stat.ts_overflow += buf->b_overflow;
237 1.1 yamt tprof_stat.ts_buf++;
238 1.1 yamt STAILQ_INSERT_TAIL(&tprof_list, buf, b_list);
239 1.1 yamt tprof_nbuf_on_list++;
240 1.1 yamt buf = NULL;
241 1.21 ryo selnotify(&tprof_selp, 0, NOTE_SUBMIT);
242 1.1 yamt cv_broadcast(&tprof_reader_cv);
243 1.1 yamt } else {
244 1.1 yamt tprof_stat.ts_dropbuf_sample += buf->b_used;
245 1.1 yamt tprof_stat.ts_dropbuf++;
246 1.1 yamt }
247 1.1 yamt mutex_exit(&tprof_lock);
248 1.23 msaitoh if (buf)
249 1.1 yamt tprof_buf_free(buf);
250 1.23 msaitoh
251 1.23 msaitoh if (!shouldstop)
252 1.21 ryo callout_schedule(&c->c_callout, hz / 8);
253 1.1 yamt }
254 1.1 yamt
255 1.1 yamt static void
256 1.1 yamt tprof_kick(void *vp)
257 1.1 yamt {
258 1.1 yamt struct cpu_info * const ci = vp;
259 1.1 yamt tprof_cpu_t * const c = tprof_cpu(ci);
260 1.1 yamt
261 1.1 yamt workqueue_enqueue(tprof_wq, &c->c_work, ci);
262 1.1 yamt }
263 1.1 yamt
264 1.1 yamt static void
265 1.1 yamt tprof_stop1(void)
266 1.1 yamt {
267 1.1 yamt CPU_INFO_ITERATOR cii;
268 1.1 yamt struct cpu_info *ci;
269 1.1 yamt
270 1.1 yamt KASSERT(mutex_owned(&tprof_startstop_lock));
271 1.6 yamt KASSERT(tprof_nworker == 0);
272 1.1 yamt
273 1.1 yamt for (CPU_INFO_FOREACH(cii, ci)) {
274 1.1 yamt tprof_cpu_t * const c = tprof_cpu(ci);
275 1.1 yamt tprof_buf_t *old;
276 1.1 yamt
277 1.1 yamt old = tprof_buf_switch(c, NULL);
278 1.23 msaitoh if (old != NULL)
279 1.1 yamt tprof_buf_free(old);
280 1.23 msaitoh
281 1.1 yamt callout_destroy(&c->c_callout);
282 1.1 yamt }
283 1.1 yamt workqueue_destroy(tprof_wq);
284 1.1 yamt }
285 1.1 yamt
286 1.14 maxv static void
287 1.14 maxv tprof_getinfo(struct tprof_info *info)
288 1.14 maxv {
289 1.14 maxv tprof_backend_t *tb;
290 1.14 maxv
291 1.14 maxv KASSERT(mutex_owned(&tprof_startstop_lock));
292 1.14 maxv
293 1.14 maxv memset(info, 0, sizeof(*info));
294 1.14 maxv info->ti_version = TPROF_VERSION;
295 1.23 msaitoh if ((tb = tprof_backend) != NULL)
296 1.14 maxv info->ti_ident = tb->tb_ops->tbo_ident();
297 1.14 maxv }
298 1.14 maxv
299 1.1 yamt static int
300 1.19 ryo tprof_getncounters(u_int *ncounters)
301 1.19 ryo {
302 1.19 ryo tprof_backend_t *tb;
303 1.19 ryo
304 1.19 ryo tb = tprof_backend;
305 1.19 ryo if (tb == NULL)
306 1.19 ryo return ENOENT;
307 1.19 ryo
308 1.19 ryo *ncounters = tb->tb_ops->tbo_ncounters();
309 1.19 ryo return 0;
310 1.19 ryo }
311 1.19 ryo
312 1.19 ryo static void
313 1.19 ryo tprof_start_cpu(void *arg1, void *arg2)
314 1.19 ryo {
315 1.19 ryo tprof_backend_t *tb = arg1;
316 1.19 ryo tprof_countermask_t runmask = (uintptr_t)arg2;
317 1.19 ryo
318 1.19 ryo tb->tb_ops->tbo_start(runmask);
319 1.19 ryo }
320 1.19 ryo
321 1.19 ryo static void
322 1.19 ryo tprof_stop_cpu(void *arg1, void *arg2)
323 1.19 ryo {
324 1.19 ryo tprof_backend_t *tb = arg1;
325 1.19 ryo tprof_countermask_t stopmask = (uintptr_t)arg2;
326 1.19 ryo
327 1.19 ryo tb->tb_ops->tbo_stop(stopmask);
328 1.19 ryo }
329 1.19 ryo
330 1.19 ryo static int
331 1.19 ryo tprof_start(tprof_countermask_t runmask)
332 1.1 yamt {
333 1.1 yamt CPU_INFO_ITERATOR cii;
334 1.1 yamt struct cpu_info *ci;
335 1.19 ryo tprof_backend_t *tb;
336 1.19 ryo uint64_t xc;
337 1.1 yamt int error;
338 1.19 ryo bool firstrun;
339 1.1 yamt
340 1.1 yamt KASSERT(mutex_owned(&tprof_startstop_lock));
341 1.1 yamt
342 1.4 yamt tb = tprof_backend;
343 1.4 yamt if (tb == NULL) {
344 1.4 yamt error = ENOENT;
345 1.4 yamt goto done;
346 1.4 yamt }
347 1.19 ryo
348 1.19 ryo runmask &= ~tb->tb_softc.sc_ctr_running_mask;
349 1.19 ryo runmask &= tb->tb_softc.sc_ctr_configured_mask;
350 1.19 ryo if (runmask == 0) {
351 1.19 ryo /*
352 1.23 msaitoh * Targets are already running.
353 1.23 msaitoh * Unconfigured counters are ignored.
354 1.19 ryo */
355 1.19 ryo error = 0;
356 1.4 yamt goto done;
357 1.4 yamt }
358 1.4 yamt
359 1.19 ryo firstrun = (tb->tb_softc.sc_ctr_running_mask == 0);
360 1.19 ryo if (firstrun) {
361 1.19 ryo if (tb->tb_ops->tbo_establish != NULL) {
362 1.19 ryo error = tb->tb_ops->tbo_establish(&tb->tb_softc);
363 1.19 ryo if (error != 0)
364 1.19 ryo goto done;
365 1.19 ryo }
366 1.19 ryo
367 1.19 ryo tprof_samples_per_buf = TPROF_MAX_SAMPLES_PER_BUF;
368 1.21 ryo tprof_max_buf = ncpu * 3;
369 1.19 ryo error = workqueue_create(&tprof_wq, "tprofmv", tprof_worker,
370 1.19 ryo NULL, PRI_NONE, IPL_SOFTCLOCK, WQ_MPSAFE | WQ_PERCPU);
371 1.19 ryo if (error != 0) {
372 1.19 ryo if (tb->tb_ops->tbo_disestablish != NULL)
373 1.19 ryo tb->tb_ops->tbo_disestablish(&tb->tb_softc);
374 1.19 ryo goto done;
375 1.19 ryo }
376 1.19 ryo
377 1.19 ryo for (CPU_INFO_FOREACH(cii, ci)) {
378 1.19 ryo tprof_cpu_t * const c = tprof_cpu(ci);
379 1.19 ryo tprof_buf_t *new;
380 1.19 ryo tprof_buf_t *old;
381 1.19 ryo
382 1.19 ryo new = tprof_buf_alloc();
383 1.19 ryo old = tprof_buf_switch(c, new);
384 1.19 ryo if (old != NULL) {
385 1.19 ryo tprof_buf_free(old);
386 1.19 ryo }
387 1.19 ryo callout_init(&c->c_callout, CALLOUT_MPSAFE);
388 1.19 ryo callout_setfunc(&c->c_callout, tprof_kick, ci);
389 1.19 ryo }
390 1.1 yamt }
391 1.1 yamt
392 1.19 ryo runmask &= tb->tb_softc.sc_ctr_configured_mask;
393 1.19 ryo xc = xc_broadcast(0, tprof_start_cpu, tb, (void *)(uintptr_t)runmask);
394 1.19 ryo xc_wait(xc);
395 1.19 ryo mutex_enter(&tprof_lock);
396 1.19 ryo tb->tb_softc.sc_ctr_running_mask |= runmask;
397 1.19 ryo mutex_exit(&tprof_lock);
398 1.19 ryo
399 1.19 ryo if (firstrun) {
400 1.19 ryo for (CPU_INFO_FOREACH(cii, ci)) {
401 1.19 ryo tprof_cpu_t * const c = tprof_cpu(ci);
402 1.1 yamt
403 1.19 ryo mutex_enter(&tprof_lock);
404 1.19 ryo tprof_nworker++;
405 1.19 ryo mutex_exit(&tprof_lock);
406 1.19 ryo workqueue_enqueue(tprof_wq, &c->c_work, ci);
407 1.1 yamt }
408 1.1 yamt }
409 1.20 chs error = 0;
410 1.20 chs
411 1.19 ryo done:
412 1.19 ryo return error;
413 1.19 ryo }
414 1.1 yamt
415 1.19 ryo static void
416 1.19 ryo tprof_stop(tprof_countermask_t stopmask)
417 1.19 ryo {
418 1.19 ryo tprof_backend_t *tb;
419 1.19 ryo uint64_t xc;
420 1.19 ryo
421 1.19 ryo tb = tprof_backend;
422 1.19 ryo if (tb == NULL)
423 1.19 ryo return;
424 1.19 ryo
425 1.19 ryo KASSERT(mutex_owned(&tprof_startstop_lock));
426 1.19 ryo stopmask &= tb->tb_softc.sc_ctr_running_mask;
427 1.19 ryo if (stopmask == 0) {
428 1.23 msaitoh /* Targets are not running */
429 1.1 yamt goto done;
430 1.1 yamt }
431 1.1 yamt
432 1.19 ryo xc = xc_broadcast(0, tprof_stop_cpu, tb, (void *)(uintptr_t)stopmask);
433 1.19 ryo xc_wait(xc);
434 1.1 yamt mutex_enter(&tprof_lock);
435 1.19 ryo tb->tb_softc.sc_ctr_running_mask &= ~stopmask;
436 1.1 yamt mutex_exit(&tprof_lock);
437 1.1 yamt
438 1.23 msaitoh /* All counters have stopped? */
439 1.19 ryo if (tb->tb_softc.sc_ctr_running_mask == 0) {
440 1.1 yamt mutex_enter(&tprof_lock);
441 1.19 ryo cv_broadcast(&tprof_reader_cv);
442 1.23 msaitoh while (tprof_nworker > 0)
443 1.19 ryo cv_wait(&tprof_cv, &tprof_lock);
444 1.23 msaitoh
445 1.1 yamt mutex_exit(&tprof_lock);
446 1.19 ryo
447 1.19 ryo tprof_stop1();
448 1.19 ryo if (tb->tb_ops->tbo_disestablish != NULL)
449 1.19 ryo tb->tb_ops->tbo_disestablish(&tb->tb_softc);
450 1.1 yamt }
451 1.1 yamt done:
452 1.19 ryo ;
453 1.19 ryo }
454 1.19 ryo
455 1.19 ryo static void
456 1.19 ryo tprof_init_percpu_counters_offset(void *vp, void *vp2, struct cpu_info *ci)
457 1.19 ryo {
458 1.19 ryo uint64_t *counters_offset = vp;
459 1.19 ryo u_int counter = (uintptr_t)vp2;
460 1.19 ryo
461 1.19 ryo tprof_backend_t *tb = tprof_backend;
462 1.19 ryo tprof_param_t *param = &tb->tb_softc.sc_count[counter].ctr_param;
463 1.19 ryo counters_offset[counter] = param->p_value;
464 1.1 yamt }
465 1.1 yamt
466 1.1 yamt static void
467 1.19 ryo tprof_configure_event_cpu(void *arg1, void *arg2)
468 1.19 ryo {
469 1.19 ryo tprof_backend_t *tb = arg1;
470 1.19 ryo u_int counter = (uintptr_t)arg2;
471 1.19 ryo tprof_param_t *param = &tb->tb_softc.sc_count[counter].ctr_param;
472 1.19 ryo
473 1.19 ryo tb->tb_ops->tbo_configure_event(counter, param);
474 1.19 ryo }
475 1.19 ryo
476 1.19 ryo static int
477 1.19 ryo tprof_configure_event(const tprof_param_t *param)
478 1.1 yamt {
479 1.4 yamt tprof_backend_t *tb;
480 1.19 ryo tprof_backend_softc_t *sc;
481 1.19 ryo tprof_param_t *sc_param;
482 1.19 ryo uint64_t xc;
483 1.19 ryo int c, error;
484 1.1 yamt
485 1.19 ryo if ((param->p_flags & (TPROF_PARAM_USER | TPROF_PARAM_KERN)) == 0) {
486 1.19 ryo error = EINVAL;
487 1.1 yamt goto done;
488 1.1 yamt }
489 1.1 yamt
490 1.4 yamt tb = tprof_backend;
491 1.19 ryo if (tb == NULL) {
492 1.19 ryo error = ENOENT;
493 1.19 ryo goto done;
494 1.19 ryo }
495 1.19 ryo sc = &tb->tb_softc;
496 1.19 ryo
497 1.19 ryo c = param->p_counter;
498 1.19 ryo if (c >= tb->tb_softc.sc_ncounters) {
499 1.19 ryo error = EINVAL;
500 1.19 ryo goto done;
501 1.19 ryo }
502 1.19 ryo
503 1.19 ryo if (tb->tb_ops->tbo_valid_event != NULL) {
504 1.19 ryo error = tb->tb_ops->tbo_valid_event(param->p_counter, param);
505 1.19 ryo if (error != 0)
506 1.19 ryo goto done;
507 1.19 ryo }
508 1.19 ryo
509 1.19 ryo /* if already running, stop the counter */
510 1.19 ryo if (ISSET(c, tb->tb_softc.sc_ctr_running_mask))
511 1.19 ryo tprof_stop(__BIT(c));
512 1.19 ryo
513 1.19 ryo sc->sc_count[c].ctr_bitwidth =
514 1.19 ryo tb->tb_ops->tbo_counter_bitwidth(param->p_counter);
515 1.19 ryo
516 1.19 ryo sc_param = &sc->sc_count[c].ctr_param;
517 1.23 msaitoh memcpy(sc_param, param, sizeof(*sc_param)); /* save copy of param */
518 1.19 ryo
519 1.19 ryo if (ISSET(param->p_flags, TPROF_PARAM_PROFILE)) {
520 1.19 ryo uint64_t freq, inum, dnum;
521 1.19 ryo
522 1.19 ryo freq = tb->tb_ops->tbo_counter_estimate_freq(c);
523 1.19 ryo sc->sc_count[c].ctr_counter_val = freq / TPROF_HZ;
524 1.19 ryo if (sc->sc_count[c].ctr_counter_val == 0) {
525 1.19 ryo printf("%s: counter#%d frequency (%"PRIu64") is"
526 1.19 ryo " very low relative to TPROF_HZ (%u)\n", __func__,
527 1.19 ryo c, freq, TPROF_HZ);
528 1.19 ryo sc->sc_count[c].ctr_counter_val =
529 1.19 ryo 4000000000ULL / TPROF_HZ;
530 1.19 ryo }
531 1.19 ryo
532 1.19 ryo switch (param->p_flags & TPROF_PARAM_VALUE2_MASK) {
533 1.19 ryo case TPROF_PARAM_VALUE2_SCALE:
534 1.19 ryo if (sc_param->p_value2 == 0)
535 1.19 ryo break;
536 1.19 ryo /*
537 1.19 ryo * p_value2 is 64-bit fixed-point
538 1.19 ryo * upper 32 bits are the integer part
539 1.19 ryo * lower 32 bits are the decimal part
540 1.19 ryo */
541 1.19 ryo inum = sc_param->p_value2 >> 32;
542 1.19 ryo dnum = sc_param->p_value2 & __BITS(31, 0);
543 1.19 ryo sc->sc_count[c].ctr_counter_val =
544 1.19 ryo sc->sc_count[c].ctr_counter_val * inum +
545 1.19 ryo (sc->sc_count[c].ctr_counter_val * dnum >> 32);
546 1.19 ryo if (sc->sc_count[c].ctr_counter_val == 0)
547 1.19 ryo sc->sc_count[c].ctr_counter_val = 1;
548 1.19 ryo break;
549 1.19 ryo case TPROF_PARAM_VALUE2_TRIGGERCOUNT:
550 1.19 ryo if (sc_param->p_value2 == 0)
551 1.19 ryo sc_param->p_value2 = 1;
552 1.19 ryo if (sc_param->p_value2 >
553 1.19 ryo __BITS(sc->sc_count[c].ctr_bitwidth - 1, 0)) {
554 1.19 ryo sc_param->p_value2 =
555 1.19 ryo __BITS(sc->sc_count[c].ctr_bitwidth - 1, 0);
556 1.19 ryo }
557 1.19 ryo sc->sc_count[c].ctr_counter_val = sc_param->p_value2;
558 1.19 ryo break;
559 1.19 ryo default:
560 1.19 ryo break;
561 1.19 ryo }
562 1.19 ryo sc->sc_count[c].ctr_counter_reset_val =
563 1.19 ryo -sc->sc_count[c].ctr_counter_val;
564 1.19 ryo sc->sc_count[c].ctr_counter_reset_val &=
565 1.19 ryo __BITS(sc->sc_count[c].ctr_bitwidth - 1, 0);
566 1.19 ryo } else {
567 1.19 ryo sc->sc_count[c].ctr_counter_val = 0;
568 1.19 ryo sc->sc_count[c].ctr_counter_reset_val = 0;
569 1.19 ryo }
570 1.19 ryo
571 1.19 ryo /* At this point, p_value is used as an initial value */
572 1.19 ryo percpu_foreach(tb->tb_softc.sc_ctr_offset_percpu,
573 1.19 ryo tprof_init_percpu_counters_offset, (void *)(uintptr_t)c);
574 1.19 ryo /* On the backend side, p_value is used as the reset value */
575 1.19 ryo sc_param->p_value = tb->tb_softc.sc_count[c].ctr_counter_reset_val;
576 1.19 ryo
577 1.19 ryo xc = xc_broadcast(0, tprof_configure_event_cpu,
578 1.19 ryo tb, (void *)(uintptr_t)c);
579 1.19 ryo xc_wait(xc);
580 1.1 yamt
581 1.1 yamt mutex_enter(&tprof_lock);
582 1.19 ryo /* update counters bitmasks */
583 1.19 ryo SET(tb->tb_softc.sc_ctr_configured_mask, __BIT(c));
584 1.19 ryo CLR(tb->tb_softc.sc_ctr_prof_mask, __BIT(c));
585 1.19 ryo CLR(tb->tb_softc.sc_ctr_ovf_mask, __BIT(c));
586 1.19 ryo /* profiled counter requires overflow handling */
587 1.19 ryo if (ISSET(param->p_flags, TPROF_PARAM_PROFILE)) {
588 1.19 ryo SET(tb->tb_softc.sc_ctr_prof_mask, __BIT(c));
589 1.19 ryo SET(tb->tb_softc.sc_ctr_ovf_mask, __BIT(c));
590 1.19 ryo }
591 1.19 ryo /* counters with less than 64bits also require overflow handling */
592 1.19 ryo if (sc->sc_count[c].ctr_bitwidth != 64)
593 1.19 ryo SET(tb->tb_softc.sc_ctr_ovf_mask, __BIT(c));
594 1.19 ryo mutex_exit(&tprof_lock);
595 1.19 ryo
596 1.19 ryo error = 0;
597 1.19 ryo
598 1.19 ryo done:
599 1.19 ryo return error;
600 1.19 ryo }
601 1.19 ryo
602 1.19 ryo static void
603 1.19 ryo tprof_getcounts_cpu(void *arg1, void *arg2)
604 1.19 ryo {
605 1.19 ryo tprof_backend_t *tb = arg1;
606 1.19 ryo tprof_backend_softc_t *sc = &tb->tb_softc;
607 1.19 ryo uint64_t *counters = arg2;
608 1.19 ryo uint64_t *counters_offset;
609 1.19 ryo unsigned int c;
610 1.19 ryo
611 1.19 ryo tprof_countermask_t configmask = sc->sc_ctr_configured_mask;
612 1.19 ryo counters_offset = percpu_getref(sc->sc_ctr_offset_percpu);
613 1.19 ryo for (c = 0; c < sc->sc_ncounters; c++) {
614 1.19 ryo if (ISSET(configmask, __BIT(c))) {
615 1.19 ryo uint64_t ctr = tb->tb_ops->tbo_counter_read(c);
616 1.19 ryo counters[c] = counters_offset[c] +
617 1.19 ryo ((ctr - sc->sc_count[c].ctr_counter_reset_val) &
618 1.19 ryo __BITS(sc->sc_count[c].ctr_bitwidth - 1, 0));
619 1.23 msaitoh } else
620 1.19 ryo counters[c] = 0;
621 1.8 yamt }
622 1.19 ryo percpu_putref(sc->sc_ctr_offset_percpu);
623 1.19 ryo }
624 1.19 ryo
625 1.19 ryo static int
626 1.19 ryo tprof_getcounts(tprof_counts_t *counts)
627 1.19 ryo {
628 1.19 ryo struct cpu_info *ci;
629 1.19 ryo tprof_backend_t *tb;
630 1.19 ryo uint64_t xc;
631 1.19 ryo
632 1.19 ryo tb = tprof_backend;
633 1.19 ryo if (tb == NULL)
634 1.19 ryo return ENOENT;
635 1.19 ryo
636 1.19 ryo if (counts->c_cpu >= ncpu)
637 1.19 ryo return ESRCH;
638 1.19 ryo ci = cpu_lookup(counts->c_cpu);
639 1.19 ryo if (ci == NULL)
640 1.19 ryo return ESRCH;
641 1.19 ryo
642 1.19 ryo xc = xc_unicast(0, tprof_getcounts_cpu, tb, counts->c_count, ci);
643 1.19 ryo xc_wait(xc);
644 1.1 yamt
645 1.19 ryo counts->c_ncounters = tb->tb_softc.sc_ncounters;
646 1.19 ryo counts->c_runningmask = tb->tb_softc.sc_ctr_running_mask;
647 1.19 ryo return 0;
648 1.1 yamt }
649 1.1 yamt
650 1.4 yamt /*
651 1.4 yamt * tprof_clear: drain unread samples.
652 1.4 yamt */
653 1.4 yamt
654 1.1 yamt static void
655 1.1 yamt tprof_clear(void)
656 1.1 yamt {
657 1.1 yamt tprof_buf_t *buf;
658 1.1 yamt
659 1.1 yamt mutex_enter(&tprof_reader_lock);
660 1.1 yamt mutex_enter(&tprof_lock);
661 1.1 yamt while ((buf = STAILQ_FIRST(&tprof_list)) != NULL) {
662 1.1 yamt if (buf != NULL) {
663 1.1 yamt STAILQ_REMOVE_HEAD(&tprof_list, b_list);
664 1.1 yamt KASSERT(tprof_nbuf_on_list > 0);
665 1.1 yamt tprof_nbuf_on_list--;
666 1.1 yamt mutex_exit(&tprof_lock);
667 1.1 yamt tprof_buf_free(buf);
668 1.1 yamt mutex_enter(&tprof_lock);
669 1.1 yamt }
670 1.1 yamt }
671 1.1 yamt KASSERT(tprof_nbuf_on_list == 0);
672 1.1 yamt mutex_exit(&tprof_lock);
673 1.1 yamt tprof_reader_offset = 0;
674 1.1 yamt mutex_exit(&tprof_reader_lock);
675 1.1 yamt
676 1.1 yamt memset(&tprof_stat, 0, sizeof(tprof_stat));
677 1.1 yamt }
678 1.1 yamt
679 1.4 yamt static tprof_backend_t *
680 1.4 yamt tprof_backend_lookup(const char *name)
681 1.4 yamt {
682 1.4 yamt tprof_backend_t *tb;
683 1.4 yamt
684 1.4 yamt KASSERT(mutex_owned(&tprof_startstop_lock));
685 1.4 yamt
686 1.4 yamt LIST_FOREACH(tb, &tprof_backends, tb_list) {
687 1.4 yamt if (!strcmp(tb->tb_name, name)) {
688 1.4 yamt return tb;
689 1.4 yamt }
690 1.4 yamt }
691 1.4 yamt return NULL;
692 1.4 yamt }
693 1.4 yamt
694 1.1 yamt /* -------------------- backend interfaces */
695 1.1 yamt
696 1.1 yamt /*
697 1.1 yamt * tprof_sample: record a sample on the per-cpu buffer.
698 1.1 yamt *
699 1.1 yamt * be careful; can be called in NMI context.
700 1.10 yamt * we are bluntly assuming the followings are safe.
701 1.10 yamt * curcpu()
702 1.10 yamt * curlwp->l_lid
703 1.10 yamt * curlwp->l_proc->p_pid
704 1.1 yamt */
705 1.1 yamt
706 1.1 yamt void
707 1.14 maxv tprof_sample(void *unused, const tprof_frame_info_t *tfi)
708 1.1 yamt {
709 1.18 ryo tprof_cpu_t * const c = tprof_cpu_direct(curcpu());
710 1.1 yamt tprof_buf_t * const buf = c->c_buf;
711 1.8 yamt tprof_sample_t *sp;
712 1.5 yamt const uintptr_t pc = tfi->tfi_pc;
713 1.10 yamt const lwp_t * const l = curlwp;
714 1.1 yamt u_int idx;
715 1.1 yamt
716 1.1 yamt idx = buf->b_used;
717 1.1 yamt if (__predict_false(idx >= buf->b_size)) {
718 1.1 yamt buf->b_overflow++;
719 1.1 yamt return;
720 1.1 yamt }
721 1.8 yamt sp = &buf->b_data[idx];
722 1.10 yamt sp->s_pid = l->l_proc->p_pid;
723 1.10 yamt sp->s_lwpid = l->l_lid;
724 1.10 yamt sp->s_cpuid = c->c_cpuid;
725 1.19 ryo sp->s_flags = ((tfi->tfi_inkernel) ? TPROF_SAMPLE_INKERNEL : 0) |
726 1.19 ryo __SHIFTIN(tfi->tfi_counter, TPROF_SAMPLE_COUNTER_MASK);
727 1.8 yamt sp->s_pc = pc;
728 1.1 yamt buf->b_used = idx + 1;
729 1.1 yamt }
730 1.1 yamt
731 1.4 yamt /*
732 1.16 skrll * tprof_backend_register:
733 1.4 yamt */
734 1.4 yamt
735 1.4 yamt int
736 1.4 yamt tprof_backend_register(const char *name, const tprof_backend_ops_t *ops,
737 1.4 yamt int vers)
738 1.4 yamt {
739 1.4 yamt tprof_backend_t *tb;
740 1.4 yamt
741 1.23 msaitoh if (vers != TPROF_BACKEND_VERSION)
742 1.4 yamt return EINVAL;
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.23 msaitoh /* 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.23 msaitoh if (tprof_backend == tb)
800 1.4 yamt tprof_backend = NULL;
801 1.4 yamt #endif
802 1.4 yamt LIST_REMOVE(tb, tb_list);
803 1.4 yamt mutex_exit(&tprof_startstop_lock);
804 1.4 yamt
805 1.19 ryo /* fini backend softc */
806 1.19 ryo percpu_free(tb->tb_softc.sc_ctr_offset_percpu,
807 1.19 ryo tb->tb_softc.sc_ctr_offset_percpu_size);
808 1.19 ryo
809 1.23 msaitoh /* Free backend */
810 1.4 yamt kmem_free(tb, sizeof(*tb));
811 1.4 yamt
812 1.4 yamt return 0;
813 1.4 yamt }
814 1.4 yamt
815 1.1 yamt /* -------------------- cdevsw interfaces */
816 1.1 yamt
817 1.1 yamt static int
818 1.1 yamt tprof_open(dev_t dev, int flags, int type, struct lwp *l)
819 1.1 yamt {
820 1.1 yamt
821 1.23 msaitoh if (minor(dev) != 0)
822 1.1 yamt return EXDEV;
823 1.23 msaitoh
824 1.1 yamt mutex_enter(&tprof_lock);
825 1.1 yamt if (tprof_owner != NULL) {
826 1.1 yamt mutex_exit(&tprof_lock);
827 1.1 yamt return EBUSY;
828 1.1 yamt }
829 1.1 yamt tprof_owner = curlwp;
830 1.1 yamt mutex_exit(&tprof_lock);
831 1.1 yamt
832 1.1 yamt return 0;
833 1.1 yamt }
834 1.1 yamt
835 1.1 yamt static int
836 1.1 yamt tprof_close(dev_t dev, int flags, int type, struct lwp *l)
837 1.1 yamt {
838 1.1 yamt
839 1.1 yamt KASSERT(minor(dev) == 0);
840 1.1 yamt
841 1.1 yamt mutex_enter(&tprof_startstop_lock);
842 1.1 yamt mutex_enter(&tprof_lock);
843 1.1 yamt tprof_owner = NULL;
844 1.1 yamt mutex_exit(&tprof_lock);
845 1.19 ryo tprof_stop(TPROF_COUNTERMASK_ALL);
846 1.1 yamt tprof_clear();
847 1.19 ryo
848 1.19 ryo tprof_backend_t *tb = tprof_backend;
849 1.19 ryo if (tb != NULL) {
850 1.19 ryo KASSERT(tb->tb_softc.sc_ctr_running_mask == 0);
851 1.19 ryo tb->tb_softc.sc_ctr_configured_mask = 0;
852 1.19 ryo tb->tb_softc.sc_ctr_prof_mask = 0;
853 1.19 ryo tb->tb_softc.sc_ctr_ovf_mask = 0;
854 1.19 ryo }
855 1.19 ryo
856 1.1 yamt mutex_exit(&tprof_startstop_lock);
857 1.1 yamt
858 1.1 yamt return 0;
859 1.1 yamt }
860 1.1 yamt
861 1.1 yamt static int
862 1.21 ryo tprof_poll(dev_t dev, int events, struct lwp *l)
863 1.21 ryo {
864 1.21 ryo int revents;
865 1.21 ryo
866 1.21 ryo revents = events & (POLLIN | POLLRDNORM);
867 1.21 ryo if (revents == 0)
868 1.21 ryo return 0;
869 1.21 ryo
870 1.21 ryo mutex_enter(&tprof_lock);
871 1.21 ryo if (STAILQ_EMPTY(&tprof_list)) {
872 1.21 ryo revents = 0;
873 1.21 ryo selrecord(l, &tprof_selp);
874 1.21 ryo }
875 1.21 ryo mutex_exit(&tprof_lock);
876 1.21 ryo
877 1.21 ryo return revents;
878 1.21 ryo }
879 1.21 ryo
880 1.21 ryo static void
881 1.21 ryo filt_tprof_read_detach(struct knote *kn)
882 1.21 ryo {
883 1.22 ryo mutex_enter(&tprof_lock);
884 1.21 ryo selremove_knote(&tprof_selp, kn);
885 1.22 ryo mutex_exit(&tprof_lock);
886 1.21 ryo }
887 1.21 ryo
888 1.21 ryo static int
889 1.21 ryo filt_tprof_read_event(struct knote *kn, long hint)
890 1.21 ryo {
891 1.21 ryo int rv = 0;
892 1.21 ryo
893 1.21 ryo if ((hint & NOTE_SUBMIT) == 0)
894 1.22 ryo mutex_enter(&tprof_lock);
895 1.21 ryo
896 1.21 ryo if (!STAILQ_EMPTY(&tprof_list)) {
897 1.21 ryo tprof_buf_t *buf;
898 1.21 ryo int64_t n = 0;
899 1.21 ryo
900 1.21 ryo STAILQ_FOREACH(buf, &tprof_list, b_list) {
901 1.21 ryo n += buf->b_used;
902 1.21 ryo }
903 1.21 ryo kn->kn_data = n * sizeof(tprof_sample_t);
904 1.21 ryo
905 1.21 ryo rv = 1;
906 1.21 ryo }
907 1.21 ryo
908 1.21 ryo if ((hint & NOTE_SUBMIT) == 0)
909 1.22 ryo mutex_exit(&tprof_lock);
910 1.21 ryo
911 1.21 ryo return rv;
912 1.21 ryo }
913 1.21 ryo
914 1.21 ryo static const struct filterops tprof_read_filtops = {
915 1.21 ryo .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
916 1.21 ryo .f_attach = NULL,
917 1.21 ryo .f_detach = filt_tprof_read_detach,
918 1.21 ryo .f_event = filt_tprof_read_event,
919 1.21 ryo };
920 1.21 ryo
921 1.21 ryo static int
922 1.21 ryo tprof_kqfilter(dev_t dev, struct knote *kn)
923 1.21 ryo {
924 1.21 ryo switch (kn->kn_filter) {
925 1.21 ryo case EVFILT_READ:
926 1.21 ryo kn->kn_fop = &tprof_read_filtops;
927 1.22 ryo mutex_enter(&tprof_lock);
928 1.21 ryo selrecord_knote(&tprof_selp, kn);
929 1.22 ryo mutex_exit(&tprof_lock);
930 1.21 ryo break;
931 1.21 ryo default:
932 1.21 ryo return EINVAL;
933 1.21 ryo }
934 1.21 ryo
935 1.21 ryo return 0;
936 1.21 ryo }
937 1.21 ryo
938 1.21 ryo static int
939 1.1 yamt tprof_read(dev_t dev, struct uio *uio, int flags)
940 1.1 yamt {
941 1.1 yamt tprof_buf_t *buf;
942 1.1 yamt size_t bytes;
943 1.1 yamt size_t resid;
944 1.21 ryo size_t done = 0;
945 1.1 yamt int error = 0;
946 1.1 yamt
947 1.1 yamt KASSERT(minor(dev) == 0);
948 1.1 yamt mutex_enter(&tprof_reader_lock);
949 1.1 yamt while (uio->uio_resid > 0 && error == 0) {
950 1.1 yamt /*
951 1.23 msaitoh * Take the first buffer from the list.
952 1.1 yamt */
953 1.1 yamt mutex_enter(&tprof_lock);
954 1.1 yamt buf = STAILQ_FIRST(&tprof_list);
955 1.1 yamt if (buf == NULL) {
956 1.21 ryo if (tprof_nworker == 0 || done != 0) {
957 1.1 yamt mutex_exit(&tprof_lock);
958 1.1 yamt error = 0;
959 1.1 yamt break;
960 1.1 yamt }
961 1.1 yamt mutex_exit(&tprof_reader_lock);
962 1.1 yamt error = cv_wait_sig(&tprof_reader_cv, &tprof_lock);
963 1.1 yamt mutex_exit(&tprof_lock);
964 1.1 yamt mutex_enter(&tprof_reader_lock);
965 1.1 yamt continue;
966 1.1 yamt }
967 1.1 yamt STAILQ_REMOVE_HEAD(&tprof_list, b_list);
968 1.1 yamt KASSERT(tprof_nbuf_on_list > 0);
969 1.1 yamt tprof_nbuf_on_list--;
970 1.1 yamt mutex_exit(&tprof_lock);
971 1.1 yamt
972 1.1 yamt /*
973 1.23 msaitoh * Copy it out.
974 1.1 yamt */
975 1.1 yamt bytes = MIN(buf->b_used * sizeof(tprof_sample_t) -
976 1.1 yamt tprof_reader_offset, uio->uio_resid);
977 1.1 yamt resid = uio->uio_resid;
978 1.1 yamt error = uiomove((char *)buf->b_data + tprof_reader_offset,
979 1.1 yamt bytes, uio);
980 1.1 yamt done = resid - uio->uio_resid;
981 1.1 yamt tprof_reader_offset += done;
982 1.1 yamt
983 1.1 yamt /*
984 1.23 msaitoh * If we didn't consume the whole buffer,
985 1.1 yamt * put it back to the list.
986 1.1 yamt */
987 1.1 yamt if (tprof_reader_offset <
988 1.1 yamt buf->b_used * sizeof(tprof_sample_t)) {
989 1.1 yamt mutex_enter(&tprof_lock);
990 1.1 yamt STAILQ_INSERT_HEAD(&tprof_list, buf, b_list);
991 1.1 yamt tprof_nbuf_on_list++;
992 1.1 yamt cv_broadcast(&tprof_reader_cv);
993 1.1 yamt mutex_exit(&tprof_lock);
994 1.1 yamt } else {
995 1.1 yamt tprof_buf_free(buf);
996 1.1 yamt tprof_reader_offset = 0;
997 1.1 yamt }
998 1.1 yamt }
999 1.1 yamt mutex_exit(&tprof_reader_lock);
1000 1.1 yamt
1001 1.1 yamt return error;
1002 1.1 yamt }
1003 1.1 yamt
1004 1.1 yamt static int
1005 1.1 yamt tprof_ioctl(dev_t dev, u_long cmd, void *data, int flags, struct lwp *l)
1006 1.1 yamt {
1007 1.14 maxv const tprof_param_t *param;
1008 1.19 ryo tprof_counts_t *counts;
1009 1.1 yamt int error = 0;
1010 1.1 yamt
1011 1.1 yamt KASSERT(minor(dev) == 0);
1012 1.1 yamt
1013 1.1 yamt switch (cmd) {
1014 1.14 maxv case TPROF_IOC_GETINFO:
1015 1.14 maxv mutex_enter(&tprof_startstop_lock);
1016 1.14 maxv tprof_getinfo(data);
1017 1.14 maxv mutex_exit(&tprof_startstop_lock);
1018 1.1 yamt break;
1019 1.19 ryo case TPROF_IOC_GETNCOUNTERS:
1020 1.19 ryo mutex_enter(&tprof_lock);
1021 1.19 ryo error = tprof_getncounters((u_int *)data);
1022 1.19 ryo mutex_exit(&tprof_lock);
1023 1.19 ryo break;
1024 1.1 yamt case TPROF_IOC_START:
1025 1.1 yamt mutex_enter(&tprof_startstop_lock);
1026 1.19 ryo error = tprof_start(*(tprof_countermask_t *)data);
1027 1.1 yamt mutex_exit(&tprof_startstop_lock);
1028 1.1 yamt break;
1029 1.1 yamt case TPROF_IOC_STOP:
1030 1.1 yamt mutex_enter(&tprof_startstop_lock);
1031 1.19 ryo tprof_stop(*(tprof_countermask_t *)data);
1032 1.1 yamt mutex_exit(&tprof_startstop_lock);
1033 1.1 yamt break;
1034 1.1 yamt case TPROF_IOC_GETSTAT:
1035 1.1 yamt mutex_enter(&tprof_lock);
1036 1.1 yamt memcpy(data, &tprof_stat, sizeof(tprof_stat));
1037 1.1 yamt mutex_exit(&tprof_lock);
1038 1.1 yamt break;
1039 1.19 ryo case TPROF_IOC_CONFIGURE_EVENT:
1040 1.19 ryo param = data;
1041 1.19 ryo mutex_enter(&tprof_startstop_lock);
1042 1.19 ryo error = tprof_configure_event(param);
1043 1.19 ryo mutex_exit(&tprof_startstop_lock);
1044 1.19 ryo break;
1045 1.19 ryo case TPROF_IOC_GETCOUNTS:
1046 1.19 ryo counts = data;
1047 1.19 ryo mutex_enter(&tprof_startstop_lock);
1048 1.19 ryo error = tprof_getcounts(counts);
1049 1.19 ryo mutex_exit(&tprof_startstop_lock);
1050 1.19 ryo break;
1051 1.1 yamt default:
1052 1.1 yamt error = EINVAL;
1053 1.1 yamt break;
1054 1.1 yamt }
1055 1.1 yamt
1056 1.1 yamt return error;
1057 1.1 yamt }
1058 1.1 yamt
1059 1.1 yamt const struct cdevsw tprof_cdevsw = {
1060 1.1 yamt .d_open = tprof_open,
1061 1.1 yamt .d_close = tprof_close,
1062 1.1 yamt .d_read = tprof_read,
1063 1.1 yamt .d_write = nowrite,
1064 1.1 yamt .d_ioctl = tprof_ioctl,
1065 1.1 yamt .d_stop = nostop,
1066 1.1 yamt .d_tty = notty,
1067 1.21 ryo .d_poll = tprof_poll,
1068 1.1 yamt .d_mmap = nommap,
1069 1.21 ryo .d_kqfilter = tprof_kqfilter,
1070 1.12 dholland .d_discard = nodiscard,
1071 1.11 dholland .d_flag = D_OTHER | D_MPSAFE
1072 1.1 yamt };
1073 1.1 yamt
1074 1.1 yamt void
1075 1.1 yamt tprofattach(int nunits)
1076 1.1 yamt {
1077 1.1 yamt
1078 1.23 msaitoh /* Nothing */
1079 1.4 yamt }
1080 1.4 yamt
1081 1.4 yamt MODULE(MODULE_CLASS_DRIVER, tprof, NULL);
1082 1.4 yamt
1083 1.4 yamt static void
1084 1.15 riastrad tprof_cpu_init(void *vcp, void *vcookie, struct cpu_info *ci)
1085 1.15 riastrad {
1086 1.15 riastrad tprof_cpu_t **cp = vcp, *c;
1087 1.15 riastrad
1088 1.15 riastrad c = kmem_zalloc(sizeof(*c), KM_SLEEP);
1089 1.15 riastrad c->c_buf = NULL;
1090 1.15 riastrad c->c_cpuid = cpu_index(ci);
1091 1.15 riastrad *cp = c;
1092 1.15 riastrad }
1093 1.15 riastrad
1094 1.15 riastrad static void
1095 1.15 riastrad tprof_cpu_fini(void *vcp, void *vcookie, struct cpu_info *ci)
1096 1.15 riastrad {
1097 1.15 riastrad tprof_cpu_t **cp = vcp, *c;
1098 1.15 riastrad
1099 1.15 riastrad c = *cp;
1100 1.15 riastrad KASSERT(c->c_cpuid == cpu_index(ci));
1101 1.15 riastrad KASSERT(c->c_buf == NULL);
1102 1.15 riastrad kmem_free(c, sizeof(*c));
1103 1.15 riastrad *cp = NULL;
1104 1.15 riastrad }
1105 1.15 riastrad
1106 1.15 riastrad static void
1107 1.4 yamt tprof_driver_init(void)
1108 1.4 yamt {
1109 1.4 yamt
1110 1.1 yamt mutex_init(&tprof_lock, MUTEX_DEFAULT, IPL_NONE);
1111 1.1 yamt mutex_init(&tprof_reader_lock, MUTEX_DEFAULT, IPL_NONE);
1112 1.1 yamt mutex_init(&tprof_startstop_lock, MUTEX_DEFAULT, IPL_NONE);
1113 1.21 ryo selinit(&tprof_selp);
1114 1.1 yamt cv_init(&tprof_cv, "tprof");
1115 1.7 pgoyette cv_init(&tprof_reader_cv, "tprof_rd");
1116 1.1 yamt STAILQ_INIT(&tprof_list);
1117 1.15 riastrad tprof_cpus = percpu_create(sizeof(tprof_cpu_t *),
1118 1.15 riastrad tprof_cpu_init, tprof_cpu_fini, NULL);
1119 1.1 yamt }
1120 1.4 yamt
1121 1.4 yamt static void
1122 1.4 yamt tprof_driver_fini(void)
1123 1.4 yamt {
1124 1.4 yamt
1125 1.15 riastrad percpu_free(tprof_cpus, sizeof(tprof_cpu_t *));
1126 1.4 yamt mutex_destroy(&tprof_lock);
1127 1.4 yamt mutex_destroy(&tprof_reader_lock);
1128 1.4 yamt mutex_destroy(&tprof_startstop_lock);
1129 1.21 ryo seldestroy(&tprof_selp);
1130 1.4 yamt cv_destroy(&tprof_cv);
1131 1.4 yamt cv_destroy(&tprof_reader_cv);
1132 1.4 yamt }
1133 1.4 yamt
1134 1.4 yamt static int
1135 1.4 yamt tprof_modcmd(modcmd_t cmd, void *arg)
1136 1.4 yamt {
1137 1.4 yamt
1138 1.4 yamt switch (cmd) {
1139 1.4 yamt case MODULE_CMD_INIT:
1140 1.4 yamt tprof_driver_init();
1141 1.4 yamt #if defined(_MODULE)
1142 1.4 yamt {
1143 1.4 yamt devmajor_t bmajor = NODEVMAJOR;
1144 1.4 yamt devmajor_t cmajor = NODEVMAJOR;
1145 1.4 yamt int error;
1146 1.4 yamt
1147 1.4 yamt error = devsw_attach("tprof", NULL, &bmajor,
1148 1.4 yamt &tprof_cdevsw, &cmajor);
1149 1.4 yamt if (error) {
1150 1.4 yamt tprof_driver_fini();
1151 1.4 yamt return error;
1152 1.4 yamt }
1153 1.4 yamt }
1154 1.4 yamt #endif /* defined(_MODULE) */
1155 1.4 yamt return 0;
1156 1.4 yamt
1157 1.4 yamt case MODULE_CMD_FINI:
1158 1.4 yamt #if defined(_MODULE)
1159 1.17 riastrad devsw_detach(NULL, &tprof_cdevsw);
1160 1.4 yamt #endif /* defined(_MODULE) */
1161 1.4 yamt tprof_driver_fini();
1162 1.4 yamt return 0;
1163 1.4 yamt
1164 1.4 yamt default:
1165 1.4 yamt return ENOTTY;
1166 1.4 yamt }
1167 1.4 yamt }
1168