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