1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2005-2007 Joseph Koshy 5 * Copyright (c) 2007 The FreeBSD Foundation 6 * Copyright (c) 2018 Matthew Macy 7 * All rights reserved. 8 * 9 * Portions of this software were developed by A. Joseph Koshy under 10 * sponsorship from the FreeBSD Foundation and Google, Inc. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 */ 34 35 /* 36 * Logging code for hwpmc(4) 37 */ 38 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include <sys/param.h> 43 #include <sys/capsicum.h> 44 #include <sys/file.h> 45 #include <sys/kernel.h> 46 #include <sys/kthread.h> 47 #include <sys/lock.h> 48 #include <sys/module.h> 49 #include <sys/mutex.h> 50 #include <sys/pmc.h> 51 #include <sys/pmckern.h> 52 #include <sys/pmclog.h> 53 #include <sys/proc.h> 54 #include <sys/sched.h> 55 #include <sys/signalvar.h> 56 #include <sys/smp.h> 57 #include <sys/syscallsubr.h> 58 #include <sys/sysctl.h> 59 #include <sys/systm.h> 60 #include <sys/uio.h> 61 #include <sys/unistd.h> 62 #include <sys/vnode.h> 63 64 #if defined(__i386__) || defined(__amd64__) 65 #include <machine/clock.h> 66 #endif 67 68 #ifdef NUMA 69 #define NDOMAINS vm_ndomains 70 #define curdomain PCPU_GET(domain) 71 #else 72 #define NDOMAINS 1 73 #define curdomain 0 74 #define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags)) 75 #define free_domain(addr, type) free(addr, type) 76 #endif 77 78 /* 79 * Sysctl tunables 80 */ 81 82 SYSCTL_DECL(_kern_hwpmc); 83 84 /* 85 * kern.hwpmc.logbuffersize -- size of the per-cpu owner buffers. 86 */ 87 88 static int pmclog_buffer_size = PMC_LOG_BUFFER_SIZE; 89 #if (__FreeBSD_version < 1100000) 90 TUNABLE_INT(PMC_SYSCTL_NAME_PREFIX "logbuffersize", &pmclog_buffer_size); 91 #endif 92 SYSCTL_INT(_kern_hwpmc, OID_AUTO, logbuffersize, CTLFLAG_RDTUN, 93 &pmclog_buffer_size, 0, "size of log buffers in kilobytes"); 94 95 /* 96 * kern.hwpmc.nbuffer -- number of global log buffers 97 */ 98 99 static int pmc_nlogbuffers_pcpu = PMC_NLOGBUFFERS_PCPU; 100 #if (__FreeBSD_version < 1100000) 101 TUNABLE_INT(PMC_SYSCTL_NAME_PREFIX "nbuffers", &pmc_nlogbuffers_pcpu); 102 #endif 103 SYSCTL_INT(_kern_hwpmc, OID_AUTO, nbuffers_pcpu, CTLFLAG_RDTUN, 104 &pmc_nlogbuffers_pcpu, 0, "number of log buffers per cpu"); 105 106 /* 107 * Global log buffer list and associated spin lock. 108 */ 109 110 static struct mtx pmc_kthread_mtx; /* sleep lock */ 111 112 #define PMCLOG_INIT_BUFFER_DESCRIPTOR(D, buf, domain) do { \ 113 (D)->plb_fence = ((char *) (buf)) + 1024*pmclog_buffer_size; \ 114 (D)->plb_base = (D)->plb_ptr = ((char *) (buf)); \ 115 (D)->plb_domain = domain; \ 116 } while (0) 117 118 #define PMCLOG_RESET_BUFFER_DESCRIPTOR(D) do { \ 119 (D)->plb_ptr = (D)->plb_base; \ 120 } while (0) 121 122 /* 123 * Log file record constructors. 124 */ 125 #define _PMCLOG_TO_HEADER(T,L) \ 126 ((PMCLOG_HEADER_MAGIC << 24) | \ 127 (PMCLOG_TYPE_ ## T << 16) | \ 128 ((L) & 0xFFFF)) 129 130 /* reserve LEN bytes of space and initialize the entry header */ 131 #define _PMCLOG_RESERVE_SAFE(PO,TYPE,LEN,ACTION, TSC) do { \ 132 uint32_t *_le; \ 133 int _len = roundup((LEN), sizeof(uint32_t)); \ 134 struct pmclog_header *ph; \ 135 if ((_le = pmclog_reserve((PO), _len)) == NULL) { \ 136 ACTION; \ 137 } \ 138 ph = (struct pmclog_header *)_le; \ 139 ph->pl_header =_PMCLOG_TO_HEADER(TYPE,_len); \ 140 ph->pl_tsc = (TSC); \ 141 _le += sizeof(*ph)/4 /* skip over timestamp */ 142 143 /* reserve LEN bytes of space and initialize the entry header */ 144 #define _PMCLOG_RESERVE(PO,TYPE,LEN,ACTION) do { \ 145 uint32_t *_le; \ 146 int _len = roundup((LEN), sizeof(uint32_t)); \ 147 uint64_t tsc; \ 148 struct pmclog_header *ph; \ 149 tsc = pmc_rdtsc(); \ 150 spinlock_enter(); \ 151 if ((_le = pmclog_reserve((PO), _len)) == NULL) { \ 152 spinlock_exit(); \ 153 ACTION; \ 154 } \ 155 ph = (struct pmclog_header *)_le; \ 156 ph->pl_header =_PMCLOG_TO_HEADER(TYPE,_len); \ 157 ph->pl_tsc = tsc; \ 158 _le += sizeof(*ph)/4 /* skip over timestamp */ 159 160 161 162 #define PMCLOG_RESERVE_SAFE(P,T,L,TSC) _PMCLOG_RESERVE_SAFE(P,T,L,return,TSC) 163 #define PMCLOG_RESERVE(P,T,L) _PMCLOG_RESERVE(P,T,L,return) 164 #define PMCLOG_RESERVE_WITH_ERROR(P,T,L) _PMCLOG_RESERVE(P,T,L, \ 165 error=ENOMEM;goto error) 166 167 #define PMCLOG_EMIT32(V) do { *_le++ = (V); } while (0) 168 #define PMCLOG_EMIT64(V) do { \ 169 *_le++ = (uint32_t) ((V) & 0xFFFFFFFF); \ 170 *_le++ = (uint32_t) (((V) >> 32) & 0xFFFFFFFF); \ 171 } while (0) 172 173 174 /* Emit a string. Caution: does NOT update _le, so needs to be last */ 175 #define PMCLOG_EMITSTRING(S,L) do { bcopy((S), _le, (L)); } while (0) 176 #define PMCLOG_EMITNULLSTRING(L) do { bzero(_le, (L)); } while (0) 177 178 #define PMCLOG_DESPATCH_SAFE(PO) \ 179 pmclog_release((PO)); \ 180 } while (0) 181 182 #define PMCLOG_DESPATCH_SCHED_LOCK(PO) \ 183 pmclog_release_flags((PO), 0); \ 184 } while (0) 185 186 #define PMCLOG_DESPATCH(PO) \ 187 pmclog_release((PO)); \ 188 spinlock_exit(); \ 189 } while (0) 190 191 #define PMCLOG_DESPATCH_SYNC(PO) \ 192 pmclog_schedule_io((PO), 1); \ 193 spinlock_exit(); \ 194 } while (0) 195 196 197 #define TSDELTA 4 198 /* 199 * Assertions about the log file format. 200 */ 201 CTASSERT(sizeof(struct pmclog_callchain) == 7*4 + TSDELTA + 202 PMC_CALLCHAIN_DEPTH_MAX*sizeof(uintfptr_t)); 203 CTASSERT(sizeof(struct pmclog_closelog) == 3*4 + TSDELTA); 204 CTASSERT(sizeof(struct pmclog_dropnotify) == 3*4 + TSDELTA); 205 CTASSERT(sizeof(struct pmclog_map_in) == PATH_MAX + TSDELTA + 206 5*4 + sizeof(uintfptr_t)); 207 CTASSERT(offsetof(struct pmclog_map_in,pl_pathname) == 208 5*4 + TSDELTA + sizeof(uintfptr_t)); 209 CTASSERT(sizeof(struct pmclog_map_out) == 5*4 + 2*sizeof(uintfptr_t) + TSDELTA); 210 CTASSERT(sizeof(struct pmclog_pmcallocate) == 9*4 + TSDELTA); 211 CTASSERT(sizeof(struct pmclog_pmcattach) == 5*4 + PATH_MAX + TSDELTA); 212 CTASSERT(offsetof(struct pmclog_pmcattach,pl_pathname) == 5*4 + TSDELTA); 213 CTASSERT(sizeof(struct pmclog_pmcdetach) == 5*4 + TSDELTA); 214 CTASSERT(sizeof(struct pmclog_proccsw) == 7*4 + 8 + TSDELTA); 215 CTASSERT(sizeof(struct pmclog_procexec) == 5*4 + PATH_MAX + 216 sizeof(uintfptr_t) + TSDELTA); 217 CTASSERT(offsetof(struct pmclog_procexec,pl_pathname) == 5*4 + TSDELTA + 218 sizeof(uintfptr_t)); 219 CTASSERT(sizeof(struct pmclog_procexit) == 5*4 + 8 + TSDELTA); 220 CTASSERT(sizeof(struct pmclog_procfork) == 5*4 + TSDELTA); 221 CTASSERT(sizeof(struct pmclog_sysexit) == 6*4); 222 CTASSERT(sizeof(struct pmclog_userdata) == 6*4); 223 224 /* 225 * Log buffer structure 226 */ 227 228 struct pmclog_buffer { 229 TAILQ_ENTRY(pmclog_buffer) plb_next; 230 char *plb_base; 231 char *plb_ptr; 232 char *plb_fence; 233 uint16_t plb_domain; 234 } __aligned(CACHE_LINE_SIZE); 235 236 /* 237 * Prototypes 238 */ 239 240 static int pmclog_get_buffer(struct pmc_owner *po); 241 static void pmclog_loop(void *arg); 242 static void pmclog_release(struct pmc_owner *po); 243 static uint32_t *pmclog_reserve(struct pmc_owner *po, int length); 244 static void pmclog_schedule_io(struct pmc_owner *po, int wakeup); 245 static void pmclog_schedule_all(struct pmc_owner *po, int force); 246 static void pmclog_stop_kthread(struct pmc_owner *po); 247 248 /* 249 * Helper functions 250 */ 251 252 static inline void 253 pmc_plb_rele_unlocked(struct pmclog_buffer *plb) 254 { 255 TAILQ_INSERT_HEAD(&pmc_dom_hdrs[plb->plb_domain]->pdbh_head, plb, plb_next); 256 } 257 258 static inline void 259 pmc_plb_rele(struct pmclog_buffer *plb) 260 { 261 mtx_lock_spin(&pmc_dom_hdrs[plb->plb_domain]->pdbh_mtx); 262 pmc_plb_rele_unlocked(plb); 263 mtx_unlock_spin(&pmc_dom_hdrs[plb->plb_domain]->pdbh_mtx); 264 } 265 266 /* 267 * Get a log buffer 268 */ 269 static int 270 pmclog_get_buffer(struct pmc_owner *po) 271 { 272 struct pmclog_buffer *plb; 273 int domain; 274 275 KASSERT(po->po_curbuf[curcpu] == NULL, 276 ("[pmclog,%d] po=%p current buffer still valid", __LINE__, po)); 277 278 domain = curdomain; 279 MPASS(pmc_dom_hdrs[domain]); 280 mtx_lock_spin(&pmc_dom_hdrs[domain]->pdbh_mtx); 281 if ((plb = TAILQ_FIRST(&pmc_dom_hdrs[domain]->pdbh_head)) != NULL) 282 TAILQ_REMOVE(&pmc_dom_hdrs[domain]->pdbh_head, plb, plb_next); 283 mtx_unlock_spin(&pmc_dom_hdrs[domain]->pdbh_mtx); 284 285 PMCDBG2(LOG,GTB,1, "po=%p plb=%p", po, plb); 286 287 #ifdef HWPMC_DEBUG 288 if (plb) 289 KASSERT(plb->plb_ptr == plb->plb_base && 290 plb->plb_base < plb->plb_fence, 291 ("[pmclog,%d] po=%p buffer invariants: ptr=%p " 292 "base=%p fence=%p", __LINE__, po, plb->plb_ptr, 293 plb->plb_base, plb->plb_fence)); 294 #endif 295 296 po->po_curbuf[curcpu] = plb; 297 298 /* update stats */ 299 counter_u64_add(pmc_stats.pm_buffer_requests, 1); 300 if (plb == NULL) 301 counter_u64_add(pmc_stats.pm_buffer_requests_failed, 1); 302 303 return (plb ? 0 : ENOMEM); 304 } 305 306 struct pmclog_proc_init_args { 307 struct proc *kthr; 308 struct pmc_owner *po; 309 bool exit; 310 bool acted; 311 }; 312 313 int 314 pmclog_proc_create(struct thread *td, void **handlep) 315 { 316 struct pmclog_proc_init_args *ia; 317 int error; 318 319 ia = malloc(sizeof(*ia), M_TEMP, M_WAITOK | M_ZERO); 320 error = kproc_create(pmclog_loop, ia, &ia->kthr, 321 RFHIGHPID, 0, "hwpmc: proc(%d)", td->td_proc->p_pid); 322 if (error == 0) 323 *handlep = ia; 324 return (error); 325 } 326 327 void 328 pmclog_proc_ignite(void *handle, struct pmc_owner *po) 329 { 330 struct pmclog_proc_init_args *ia; 331 332 ia = handle; 333 mtx_lock(&pmc_kthread_mtx); 334 MPASS(!ia->acted); 335 MPASS(ia->po == NULL); 336 MPASS(!ia->exit); 337 MPASS(ia->kthr != NULL); 338 if (po == NULL) { 339 ia->exit = true; 340 } else { 341 ia->po = po; 342 KASSERT(po->po_kthread == NULL, 343 ("[pmclog,%d] po=%p kthread (%p) already present", 344 __LINE__, po, po->po_kthread)); 345 po->po_kthread = ia->kthr; 346 } 347 wakeup(ia); 348 while (!ia->acted) 349 msleep(ia, &pmc_kthread_mtx, PWAIT, "pmclogw", 0); 350 mtx_unlock(&pmc_kthread_mtx); 351 free(ia, M_TEMP); 352 } 353 354 /* 355 * Log handler loop. 356 * 357 * This function is executed by each pmc owner's helper thread. 358 */ 359 static void 360 pmclog_loop(void *arg) 361 { 362 struct pmclog_proc_init_args *ia; 363 struct pmc_owner *po; 364 struct pmclog_buffer *lb; 365 struct proc *p; 366 struct ucred *ownercred; 367 struct ucred *mycred; 368 struct thread *td; 369 sigset_t unb; 370 struct uio auio; 371 struct iovec aiov; 372 size_t nbytes; 373 int error; 374 375 td = curthread; 376 377 SIGEMPTYSET(unb); 378 SIGADDSET(unb, SIGHUP); 379 (void)kern_sigprocmask(td, SIG_UNBLOCK, &unb, NULL, 0); 380 381 ia = arg; 382 MPASS(ia->kthr == curproc); 383 MPASS(!ia->acted); 384 mtx_lock(&pmc_kthread_mtx); 385 while (ia->po == NULL && !ia->exit) 386 msleep(ia, &pmc_kthread_mtx, PWAIT, "pmclogi", 0); 387 if (ia->exit) { 388 ia->acted = true; 389 wakeup(ia); 390 mtx_unlock(&pmc_kthread_mtx); 391 kproc_exit(0); 392 } 393 MPASS(ia->po != NULL); 394 po = ia->po; 395 ia->acted = true; 396 wakeup(ia); 397 mtx_unlock(&pmc_kthread_mtx); 398 ia = NULL; 399 400 p = po->po_owner; 401 mycred = td->td_ucred; 402 403 PROC_LOCK(p); 404 ownercred = crhold(p->p_ucred); 405 PROC_UNLOCK(p); 406 407 PMCDBG2(LOG,INI,1, "po=%p kt=%p", po, po->po_kthread); 408 KASSERT(po->po_kthread == curthread->td_proc, 409 ("[pmclog,%d] proc mismatch po=%p po/kt=%p curproc=%p", __LINE__, 410 po, po->po_kthread, curthread->td_proc)); 411 412 lb = NULL; 413 414 415 /* 416 * Loop waiting for I/O requests to be added to the owner 417 * struct's queue. The loop is exited when the log file 418 * is deconfigured. 419 */ 420 421 mtx_lock(&pmc_kthread_mtx); 422 423 for (;;) { 424 425 /* check if we've been asked to exit */ 426 if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) 427 break; 428 429 if (lb == NULL) { /* look for a fresh buffer to write */ 430 mtx_lock_spin(&po->po_mtx); 431 if ((lb = TAILQ_FIRST(&po->po_logbuffers)) == NULL) { 432 mtx_unlock_spin(&po->po_mtx); 433 434 /* No more buffers and shutdown required. */ 435 if (po->po_flags & PMC_PO_SHUTDOWN) 436 break; 437 438 (void) msleep(po, &pmc_kthread_mtx, PWAIT, 439 "pmcloop", 250); 440 continue; 441 } 442 443 TAILQ_REMOVE(&po->po_logbuffers, lb, plb_next); 444 mtx_unlock_spin(&po->po_mtx); 445 } 446 447 mtx_unlock(&pmc_kthread_mtx); 448 449 /* process the request */ 450 PMCDBG3(LOG,WRI,2, "po=%p base=%p ptr=%p", po, 451 lb->plb_base, lb->plb_ptr); 452 /* change our thread's credentials before issuing the I/O */ 453 454 aiov.iov_base = lb->plb_base; 455 aiov.iov_len = nbytes = lb->plb_ptr - lb->plb_base; 456 457 auio.uio_iov = &aiov; 458 auio.uio_iovcnt = 1; 459 auio.uio_offset = -1; 460 auio.uio_resid = nbytes; 461 auio.uio_rw = UIO_WRITE; 462 auio.uio_segflg = UIO_SYSSPACE; 463 auio.uio_td = td; 464 465 /* switch thread credentials -- see kern_ktrace.c */ 466 td->td_ucred = ownercred; 467 error = fo_write(po->po_file, &auio, ownercred, 0, td); 468 td->td_ucred = mycred; 469 470 if (error) { 471 /* XXX some errors are recoverable */ 472 /* send a SIGIO to the owner and exit */ 473 PROC_LOCK(p); 474 kern_psignal(p, SIGIO); 475 PROC_UNLOCK(p); 476 477 mtx_lock(&pmc_kthread_mtx); 478 479 po->po_error = error; /* save for flush log */ 480 481 PMCDBG2(LOG,WRI,2, "po=%p error=%d", po, error); 482 483 break; 484 } 485 486 mtx_lock(&pmc_kthread_mtx); 487 488 /* put the used buffer back into the global pool */ 489 PMCLOG_RESET_BUFFER_DESCRIPTOR(lb); 490 491 pmc_plb_rele(lb); 492 lb = NULL; 493 } 494 495 wakeup_one(po->po_kthread); 496 po->po_kthread = NULL; 497 498 mtx_unlock(&pmc_kthread_mtx); 499 500 /* return the current I/O buffer to the global pool */ 501 if (lb) { 502 PMCLOG_RESET_BUFFER_DESCRIPTOR(lb); 503 504 pmc_plb_rele(lb); 505 } 506 507 /* 508 * Exit this thread, signalling the waiter 509 */ 510 511 crfree(ownercred); 512 513 kproc_exit(0); 514 } 515 516 /* 517 * Release and log entry and schedule an I/O if needed. 518 */ 519 520 static void 521 pmclog_release_flags(struct pmc_owner *po, int wakeup) 522 { 523 struct pmclog_buffer *plb; 524 525 plb = po->po_curbuf[curcpu]; 526 KASSERT(plb->plb_ptr >= plb->plb_base, 527 ("[pmclog,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, 528 po, plb->plb_ptr, plb->plb_base)); 529 KASSERT(plb->plb_ptr <= plb->plb_fence, 530 ("[pmclog,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, 531 po, plb->plb_ptr, plb->plb_fence)); 532 533 /* schedule an I/O if we've filled a buffer */ 534 if (plb->plb_ptr >= plb->plb_fence) 535 pmclog_schedule_io(po, wakeup); 536 537 PMCDBG1(LOG,REL,1, "po=%p", po); 538 } 539 540 static void 541 pmclog_release(struct pmc_owner *po) 542 { 543 544 pmclog_release_flags(po, 1); 545 } 546 547 548 /* 549 * Attempt to reserve 'length' bytes of space in an owner's log 550 * buffer. The function returns a pointer to 'length' bytes of space 551 * if there was enough space or returns NULL if no space was 552 * available. Non-null returns do so with the po mutex locked. The 553 * caller must invoke pmclog_release() on the pmc owner structure 554 * when done. 555 */ 556 557 static uint32_t * 558 pmclog_reserve(struct pmc_owner *po, int length) 559 { 560 uintptr_t newptr, oldptr; 561 struct pmclog_buffer *plb, **pplb; 562 563 PMCDBG2(LOG,ALL,1, "po=%p len=%d", po, length); 564 565 KASSERT(length % sizeof(uint32_t) == 0, 566 ("[pmclog,%d] length not a multiple of word size", __LINE__)); 567 568 /* No more data when shutdown in progress. */ 569 if (po->po_flags & PMC_PO_SHUTDOWN) 570 return (NULL); 571 572 pplb = &po->po_curbuf[curcpu]; 573 if (*pplb == NULL && pmclog_get_buffer(po) != 0) 574 goto fail; 575 576 KASSERT(*pplb != NULL, 577 ("[pmclog,%d] po=%p no current buffer", __LINE__, po)); 578 579 plb = *pplb; 580 KASSERT(plb->plb_ptr >= plb->plb_base && 581 plb->plb_ptr <= plb->plb_fence, 582 ("[pmclog,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", 583 __LINE__, po, plb->plb_ptr, plb->plb_base, 584 plb->plb_fence)); 585 586 oldptr = (uintptr_t) plb->plb_ptr; 587 newptr = oldptr + length; 588 589 KASSERT(oldptr != (uintptr_t) NULL, 590 ("[pmclog,%d] po=%p Null log buffer pointer", __LINE__, po)); 591 592 /* 593 * If we have space in the current buffer, return a pointer to 594 * available space with the PO structure locked. 595 */ 596 if (newptr <= (uintptr_t) plb->plb_fence) { 597 plb->plb_ptr = (char *) newptr; 598 goto done; 599 } 600 601 /* 602 * Otherwise, schedule the current buffer for output and get a 603 * fresh buffer. 604 */ 605 pmclog_schedule_io(po, 0); 606 607 if (pmclog_get_buffer(po) != 0) 608 goto fail; 609 610 plb = *pplb; 611 KASSERT(plb != NULL, 612 ("[pmclog,%d] po=%p no current buffer", __LINE__, po)); 613 614 KASSERT(plb->plb_ptr != NULL, 615 ("[pmclog,%d] null return from pmc_get_log_buffer", __LINE__)); 616 617 KASSERT(plb->plb_ptr == plb->plb_base && 618 plb->plb_ptr <= plb->plb_fence, 619 ("[pmclog,%d] po=%p buffer invariants: ptr=%p base=%p fence=%p", 620 __LINE__, po, plb->plb_ptr, plb->plb_base, 621 plb->plb_fence)); 622 623 oldptr = (uintptr_t) plb->plb_ptr; 624 625 done: 626 return ((uint32_t *) oldptr); 627 fail: 628 return (NULL); 629 } 630 631 /* 632 * Schedule an I/O. 633 * 634 * Transfer the current buffer to the helper kthread. 635 */ 636 637 static void 638 pmclog_schedule_io(struct pmc_owner *po, int wakeup) 639 { 640 struct pmclog_buffer *plb; 641 642 plb = po->po_curbuf[curcpu]; 643 po->po_curbuf[curcpu] = NULL; 644 KASSERT(plb != NULL, 645 ("[pmclog,%d] schedule_io with null buffer po=%p", __LINE__, po)); 646 KASSERT(plb->plb_ptr >= plb->plb_base, 647 ("[pmclog,%d] buffer invariants po=%p ptr=%p base=%p", __LINE__, 648 po, plb->plb_ptr, plb->plb_base)); 649 KASSERT(plb->plb_ptr <= plb->plb_fence, 650 ("[pmclog,%d] buffer invariants po=%p ptr=%p fenc=%p", __LINE__, 651 po, plb->plb_ptr, plb->plb_fence)); 652 653 PMCDBG1(LOG,SIO, 1, "po=%p", po); 654 655 /* 656 * Add the current buffer to the tail of the buffer list and 657 * wakeup the helper. 658 */ 659 mtx_lock_spin(&po->po_mtx); 660 TAILQ_INSERT_TAIL(&po->po_logbuffers, plb, plb_next); 661 mtx_unlock_spin(&po->po_mtx); 662 if (wakeup) 663 wakeup_one(po); 664 } 665 666 /* 667 * Stop the helper kthread. 668 */ 669 670 static void 671 pmclog_stop_kthread(struct pmc_owner *po) 672 { 673 674 mtx_lock(&pmc_kthread_mtx); 675 po->po_flags &= ~PMC_PO_OWNS_LOGFILE; 676 if (po->po_kthread != NULL) { 677 PROC_LOCK(po->po_kthread); 678 kern_psignal(po->po_kthread, SIGHUP); 679 PROC_UNLOCK(po->po_kthread); 680 } 681 wakeup_one(po); 682 while (po->po_kthread) 683 msleep(po->po_kthread, &pmc_kthread_mtx, PPAUSE, "pmckstp", 0); 684 mtx_unlock(&pmc_kthread_mtx); 685 } 686 687 /* 688 * Public functions 689 */ 690 691 /* 692 * Configure a log file for pmc owner 'po'. 693 * 694 * Parameter 'logfd' is a file handle referencing an open file in the 695 * owner process. This file needs to have been opened for writing. 696 */ 697 698 int 699 pmclog_configure_log(struct pmc_mdep *md, struct pmc_owner *po, int logfd) 700 { 701 struct proc *p; 702 struct timespec ts; 703 uint64_t tsc; 704 int error; 705 706 sx_assert(&pmc_sx, SA_XLOCKED); 707 PMCDBG2(LOG,CFG,1, "config po=%p logfd=%d", po, logfd); 708 709 p = po->po_owner; 710 711 /* return EBUSY if a log file was already present */ 712 if (po->po_flags & PMC_PO_OWNS_LOGFILE) 713 return (EBUSY); 714 715 KASSERT(po->po_file == NULL, 716 ("[pmclog,%d] po=%p file (%p) already present", __LINE__, po, 717 po->po_file)); 718 719 /* get a reference to the file state */ 720 error = fget_write(curthread, logfd, &cap_write_rights, &po->po_file); 721 if (error) 722 goto error; 723 724 /* mark process as owning a log file */ 725 po->po_flags |= PMC_PO_OWNS_LOGFILE; 726 727 /* mark process as using HWPMCs */ 728 PROC_LOCK(p); 729 p->p_flag |= P_HWPMC; 730 PROC_UNLOCK(p); 731 nanotime(&ts); 732 tsc = pmc_rdtsc(); 733 /* create a log initialization entry */ 734 PMCLOG_RESERVE_WITH_ERROR(po, INITIALIZE, 735 sizeof(struct pmclog_initialize)); 736 PMCLOG_EMIT32(PMC_VERSION); 737 PMCLOG_EMIT32(md->pmd_cputype); 738 #if defined(__i386__) || defined(__amd64__) 739 PMCLOG_EMIT64(tsc_freq); 740 #else 741 /* other architectures will need to fill this in */ 742 PMCLOG_EMIT32(0); 743 PMCLOG_EMIT32(0); 744 #endif 745 memcpy(_le, &ts, sizeof(ts)); 746 _le += sizeof(ts)/4; 747 PMCLOG_EMITSTRING(pmc_cpuid, PMC_CPUID_LEN); 748 PMCLOG_DESPATCH_SYNC(po); 749 750 return (0); 751 752 error: 753 KASSERT(po->po_kthread == NULL, ("[pmclog,%d] po=%p kthread not " 754 "stopped", __LINE__, po)); 755 756 if (po->po_file) 757 (void) fdrop(po->po_file, curthread); 758 po->po_file = NULL; /* clear file and error state */ 759 po->po_error = 0; 760 po->po_flags &= ~PMC_PO_OWNS_LOGFILE; 761 762 return (error); 763 } 764 765 766 /* 767 * De-configure a log file. This will throw away any buffers queued 768 * for this owner process. 769 */ 770 771 int 772 pmclog_deconfigure_log(struct pmc_owner *po) 773 { 774 int error; 775 struct pmclog_buffer *lb; 776 777 PMCDBG1(LOG,CFG,1, "de-config po=%p", po); 778 779 if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) 780 return (EINVAL); 781 782 KASSERT(po->po_sscount == 0, 783 ("[pmclog,%d] po=%p still owning SS PMCs", __LINE__, po)); 784 KASSERT(po->po_file != NULL, 785 ("[pmclog,%d] po=%p no log file", __LINE__, po)); 786 787 /* stop the kthread, this will reset the 'OWNS_LOGFILE' flag */ 788 pmclog_stop_kthread(po); 789 790 KASSERT(po->po_kthread == NULL, 791 ("[pmclog,%d] po=%p kthread not stopped", __LINE__, po)); 792 793 /* return all queued log buffers to the global pool */ 794 while ((lb = TAILQ_FIRST(&po->po_logbuffers)) != NULL) { 795 TAILQ_REMOVE(&po->po_logbuffers, lb, plb_next); 796 PMCLOG_RESET_BUFFER_DESCRIPTOR(lb); 797 pmc_plb_rele(lb); 798 } 799 for (int i = 0; i < mp_ncpus; i++) { 800 thread_lock(curthread); 801 sched_bind(curthread, i); 802 thread_unlock(curthread); 803 /* return the 'current' buffer to the global pool */ 804 if ((lb = po->po_curbuf[curcpu]) != NULL) { 805 PMCLOG_RESET_BUFFER_DESCRIPTOR(lb); 806 pmc_plb_rele(lb); 807 } 808 } 809 thread_lock(curthread); 810 sched_unbind(curthread); 811 thread_unlock(curthread); 812 813 /* drop a reference to the fd */ 814 if (po->po_file != NULL) { 815 error = fdrop(po->po_file, curthread); 816 po->po_file = NULL; 817 } else 818 error = 0; 819 po->po_error = 0; 820 821 return (error); 822 } 823 824 /* 825 * Flush a process' log buffer. 826 */ 827 828 int 829 pmclog_flush(struct pmc_owner *po, int force) 830 { 831 int error; 832 833 PMCDBG1(LOG,FLS,1, "po=%p", po); 834 835 /* 836 * If there is a pending error recorded by the logger thread, 837 * return that. 838 */ 839 if (po->po_error) 840 return (po->po_error); 841 842 error = 0; 843 844 /* 845 * Check that we do have an active log file. 846 */ 847 mtx_lock(&pmc_kthread_mtx); 848 if ((po->po_flags & PMC_PO_OWNS_LOGFILE) == 0) { 849 error = EINVAL; 850 goto error; 851 } 852 853 pmclog_schedule_all(po, force); 854 error: 855 mtx_unlock(&pmc_kthread_mtx); 856 857 return (error); 858 } 859 860 static void 861 pmclog_schedule_one_cond(struct pmc_owner *po, int force) 862 { 863 struct pmclog_buffer *plb; 864 int cpu; 865 866 spinlock_enter(); 867 cpu = curcpu; 868 /* tell hardclock not to run again */ 869 if (PMC_CPU_HAS_SAMPLES(cpu)) 870 PMC_CALL_HOOK_UNLOCKED(curthread, PMC_FN_DO_SAMPLES, NULL); 871 if (force) 872 pmc_flush_samples(cpu); 873 plb = po->po_curbuf[cpu]; 874 if (plb && plb->plb_ptr != plb->plb_base) 875 pmclog_schedule_io(po, 1); 876 spinlock_exit(); 877 } 878 879 static void 880 pmclog_schedule_all(struct pmc_owner *po, int force) 881 { 882 /* 883 * Schedule the current buffer if any and not empty. 884 */ 885 for (int i = 0; i < mp_ncpus; i++) { 886 thread_lock(curthread); 887 sched_bind(curthread, i); 888 thread_unlock(curthread); 889 pmclog_schedule_one_cond(po, force); 890 } 891 thread_lock(curthread); 892 sched_unbind(curthread); 893 thread_unlock(curthread); 894 } 895 896 int 897 pmclog_close(struct pmc_owner *po) 898 { 899 900 PMCDBG1(LOG,CLO,1, "po=%p", po); 901 902 pmclog_process_closelog(po); 903 904 mtx_lock(&pmc_kthread_mtx); 905 /* 906 * Initiate shutdown: no new data queued, 907 * thread will close file on last block. 908 */ 909 po->po_flags |= PMC_PO_SHUTDOWN; 910 /* give time for all to see */ 911 DELAY(50); 912 913 /* 914 * Schedule the current buffer. 915 */ 916 pmclog_schedule_all(po, 0); 917 wakeup_one(po); 918 919 mtx_unlock(&pmc_kthread_mtx); 920 921 return (0); 922 } 923 924 void 925 pmclog_process_callchain(struct pmc *pm, struct pmc_sample *ps) 926 { 927 int n, recordlen; 928 uint32_t flags; 929 struct pmc_owner *po; 930 931 PMCDBG3(LOG,SAM,1,"pm=%p pid=%d n=%d", pm, ps->ps_pid, 932 ps->ps_nsamples); 933 934 recordlen = offsetof(struct pmclog_callchain, pl_pc) + 935 ps->ps_nsamples * sizeof(uintfptr_t); 936 po = pm->pm_owner; 937 flags = PMC_CALLCHAIN_TO_CPUFLAGS(ps->ps_cpu,ps->ps_flags); 938 PMCLOG_RESERVE_SAFE(po, CALLCHAIN, recordlen, ps->ps_tsc); 939 PMCLOG_EMIT32(ps->ps_pid); 940 PMCLOG_EMIT32(ps->ps_tid); 941 PMCLOG_EMIT32(pm->pm_id); 942 PMCLOG_EMIT32(flags); 943 for (n = 0; n < ps->ps_nsamples; n++) 944 PMCLOG_EMITADDR(ps->ps_pc[n]); 945 PMCLOG_DESPATCH_SAFE(po); 946 } 947 948 void 949 pmclog_process_closelog(struct pmc_owner *po) 950 { 951 PMCLOG_RESERVE(po,CLOSELOG,sizeof(struct pmclog_closelog)); 952 PMCLOG_DESPATCH_SYNC(po); 953 } 954 955 void 956 pmclog_process_dropnotify(struct pmc_owner *po) 957 { 958 PMCLOG_RESERVE(po,DROPNOTIFY,sizeof(struct pmclog_dropnotify)); 959 PMCLOG_DESPATCH(po); 960 } 961 962 void 963 pmclog_process_map_in(struct pmc_owner *po, pid_t pid, uintfptr_t start, 964 const char *path) 965 { 966 int pathlen, recordlen; 967 968 KASSERT(path != NULL, ("[pmclog,%d] map-in, null path", __LINE__)); 969 970 pathlen = strlen(path) + 1; /* #bytes for path name */ 971 recordlen = offsetof(struct pmclog_map_in, pl_pathname) + 972 pathlen; 973 974 PMCLOG_RESERVE(po, MAP_IN, recordlen); 975 PMCLOG_EMIT32(pid); 976 PMCLOG_EMIT32(0); 977 PMCLOG_EMITADDR(start); 978 PMCLOG_EMITSTRING(path,pathlen); 979 PMCLOG_DESPATCH_SYNC(po); 980 } 981 982 void 983 pmclog_process_map_out(struct pmc_owner *po, pid_t pid, uintfptr_t start, 984 uintfptr_t end) 985 { 986 KASSERT(start <= end, ("[pmclog,%d] start > end", __LINE__)); 987 988 PMCLOG_RESERVE(po, MAP_OUT, sizeof(struct pmclog_map_out)); 989 PMCLOG_EMIT32(pid); 990 PMCLOG_EMIT32(0); 991 PMCLOG_EMITADDR(start); 992 PMCLOG_EMITADDR(end); 993 PMCLOG_DESPATCH(po); 994 } 995 996 void 997 pmclog_process_pmcallocate(struct pmc *pm) 998 { 999 struct pmc_owner *po; 1000 struct pmc_soft *ps; 1001 1002 po = pm->pm_owner; 1003 1004 PMCDBG1(LOG,ALL,1, "pm=%p", pm); 1005 1006 if (PMC_TO_CLASS(pm) == PMC_CLASS_SOFT) { 1007 PMCLOG_RESERVE(po, PMCALLOCATEDYN, 1008 sizeof(struct pmclog_pmcallocatedyn)); 1009 PMCLOG_EMIT32(pm->pm_id); 1010 PMCLOG_EMIT32(pm->pm_event); 1011 PMCLOG_EMIT32(pm->pm_flags); 1012 PMCLOG_EMIT32(0); 1013 PMCLOG_EMIT64(pm->pm_sc.pm_reloadcount); 1014 ps = pmc_soft_ev_acquire(pm->pm_event); 1015 if (ps != NULL) 1016 PMCLOG_EMITSTRING(ps->ps_ev.pm_ev_name,PMC_NAME_MAX); 1017 else 1018 PMCLOG_EMITNULLSTRING(PMC_NAME_MAX); 1019 pmc_soft_ev_release(ps); 1020 PMCLOG_DESPATCH_SYNC(po); 1021 } else { 1022 PMCLOG_RESERVE(po, PMCALLOCATE, 1023 sizeof(struct pmclog_pmcallocate)); 1024 PMCLOG_EMIT32(pm->pm_id); 1025 PMCLOG_EMIT32(pm->pm_event); 1026 PMCLOG_EMIT32(pm->pm_flags); 1027 PMCLOG_EMIT32(0); 1028 PMCLOG_EMIT64(pm->pm_sc.pm_reloadcount); 1029 PMCLOG_DESPATCH_SYNC(po); 1030 } 1031 } 1032 1033 void 1034 pmclog_process_pmcattach(struct pmc *pm, pid_t pid, char *path) 1035 { 1036 int pathlen, recordlen; 1037 struct pmc_owner *po; 1038 1039 PMCDBG2(LOG,ATT,1,"pm=%p pid=%d", pm, pid); 1040 1041 po = pm->pm_owner; 1042 1043 pathlen = strlen(path) + 1; /* #bytes for the string */ 1044 recordlen = offsetof(struct pmclog_pmcattach, pl_pathname) + pathlen; 1045 1046 PMCLOG_RESERVE(po, PMCATTACH, recordlen); 1047 PMCLOG_EMIT32(pm->pm_id); 1048 PMCLOG_EMIT32(pid); 1049 PMCLOG_EMITSTRING(path, pathlen); 1050 PMCLOG_DESPATCH_SYNC(po); 1051 } 1052 1053 void 1054 pmclog_process_pmcdetach(struct pmc *pm, pid_t pid) 1055 { 1056 struct pmc_owner *po; 1057 1058 PMCDBG2(LOG,ATT,1,"!pm=%p pid=%d", pm, pid); 1059 1060 po = pm->pm_owner; 1061 1062 PMCLOG_RESERVE(po, PMCDETACH, sizeof(struct pmclog_pmcdetach)); 1063 PMCLOG_EMIT32(pm->pm_id); 1064 PMCLOG_EMIT32(pid); 1065 PMCLOG_DESPATCH_SYNC(po); 1066 } 1067 1068 void 1069 pmclog_process_proccreate(struct pmc_owner *po, struct proc *p, int sync) 1070 { 1071 if (sync) { 1072 PMCLOG_RESERVE(po, PROC_CREATE, sizeof(struct pmclog_proccreate)); 1073 PMCLOG_EMIT32(p->p_pid); 1074 PMCLOG_EMIT32(p->p_flag); 1075 PMCLOG_EMITSTRING(p->p_comm, MAXCOMLEN+1); 1076 PMCLOG_DESPATCH_SYNC(po); 1077 } else { 1078 PMCLOG_RESERVE(po, PROC_CREATE, sizeof(struct pmclog_proccreate)); 1079 PMCLOG_EMIT32(p->p_pid); 1080 PMCLOG_EMIT32(p->p_flag); 1081 PMCLOG_EMITSTRING(p->p_comm, MAXCOMLEN+1); 1082 PMCLOG_DESPATCH(po); 1083 } 1084 } 1085 1086 /* 1087 * Log a context switch event to the log file. 1088 */ 1089 1090 void 1091 pmclog_process_proccsw(struct pmc *pm, struct pmc_process *pp, pmc_value_t v, struct thread *td) 1092 { 1093 struct pmc_owner *po; 1094 1095 KASSERT(pm->pm_flags & PMC_F_LOG_PROCCSW, 1096 ("[pmclog,%d] log-process-csw called gratuitously", __LINE__)); 1097 1098 PMCDBG3(LOG,SWO,1,"pm=%p pid=%d v=%jx", pm, pp->pp_proc->p_pid, 1099 v); 1100 1101 po = pm->pm_owner; 1102 1103 PMCLOG_RESERVE_SAFE(po, PROCCSW, sizeof(struct pmclog_proccsw), pmc_rdtsc()); 1104 PMCLOG_EMIT64(v); 1105 PMCLOG_EMIT32(pm->pm_id); 1106 PMCLOG_EMIT32(pp->pp_proc->p_pid); 1107 PMCLOG_EMIT32(td->td_tid); 1108 PMCLOG_EMIT32(0); 1109 PMCLOG_DESPATCH_SCHED_LOCK(po); 1110 } 1111 1112 void 1113 pmclog_process_procexec(struct pmc_owner *po, pmc_id_t pmid, pid_t pid, 1114 uintfptr_t startaddr, char *path) 1115 { 1116 int pathlen, recordlen; 1117 1118 PMCDBG3(LOG,EXC,1,"po=%p pid=%d path=\"%s\"", po, pid, path); 1119 1120 pathlen = strlen(path) + 1; /* #bytes for the path */ 1121 recordlen = offsetof(struct pmclog_procexec, pl_pathname) + pathlen; 1122 PMCLOG_RESERVE(po, PROCEXEC, recordlen); 1123 PMCLOG_EMIT32(pid); 1124 PMCLOG_EMIT32(pmid); 1125 PMCLOG_EMITADDR(startaddr); 1126 PMCLOG_EMITSTRING(path,pathlen); 1127 PMCLOG_DESPATCH_SYNC(po); 1128 } 1129 1130 /* 1131 * Log a process exit event (and accumulated pmc value) to the log file. 1132 */ 1133 1134 void 1135 pmclog_process_procexit(struct pmc *pm, struct pmc_process *pp) 1136 { 1137 int ri; 1138 struct pmc_owner *po; 1139 1140 ri = PMC_TO_ROWINDEX(pm); 1141 PMCDBG3(LOG,EXT,1,"pm=%p pid=%d v=%jx", pm, pp->pp_proc->p_pid, 1142 pp->pp_pmcs[ri].pp_pmcval); 1143 1144 po = pm->pm_owner; 1145 1146 PMCLOG_RESERVE(po, PROCEXIT, sizeof(struct pmclog_procexit)); 1147 PMCLOG_EMIT32(pm->pm_id); 1148 PMCLOG_EMIT32(pp->pp_proc->p_pid); 1149 PMCLOG_EMIT64(pp->pp_pmcs[ri].pp_pmcval); 1150 PMCLOG_DESPATCH(po); 1151 } 1152 1153 /* 1154 * Log a fork event. 1155 */ 1156 1157 void 1158 pmclog_process_procfork(struct pmc_owner *po, pid_t oldpid, pid_t newpid) 1159 { 1160 PMCLOG_RESERVE(po, PROCFORK, sizeof(struct pmclog_procfork)); 1161 PMCLOG_EMIT32(oldpid); 1162 PMCLOG_EMIT32(newpid); 1163 PMCLOG_DESPATCH(po); 1164 } 1165 1166 /* 1167 * Log a process exit event of the form suitable for system-wide PMCs. 1168 */ 1169 1170 void 1171 pmclog_process_sysexit(struct pmc_owner *po, pid_t pid) 1172 { 1173 PMCLOG_RESERVE(po, SYSEXIT, sizeof(struct pmclog_sysexit)); 1174 PMCLOG_EMIT32(pid); 1175 PMCLOG_DESPATCH(po); 1176 } 1177 1178 void 1179 pmclog_process_threadcreate(struct pmc_owner *po, struct thread *td, int sync) 1180 { 1181 struct proc *p; 1182 1183 p = td->td_proc; 1184 if (sync) { 1185 PMCLOG_RESERVE(po, THR_CREATE, sizeof(struct pmclog_threadcreate)); 1186 PMCLOG_EMIT32(td->td_tid); 1187 PMCLOG_EMIT32(p->p_pid); 1188 PMCLOG_EMIT32(p->p_flag); 1189 PMCLOG_EMIT32(0); 1190 PMCLOG_EMITSTRING(td->td_name, MAXCOMLEN+1); 1191 PMCLOG_DESPATCH_SYNC(po); 1192 } else { 1193 PMCLOG_RESERVE(po, THR_CREATE, sizeof(struct pmclog_threadcreate)); 1194 PMCLOG_EMIT32(td->td_tid); 1195 PMCLOG_EMIT32(p->p_pid); 1196 PMCLOG_EMIT32(p->p_flag); 1197 PMCLOG_EMIT32(0); 1198 PMCLOG_EMITSTRING(td->td_name, MAXCOMLEN+1); 1199 PMCLOG_DESPATCH(po); 1200 } 1201 } 1202 1203 void 1204 pmclog_process_threadexit(struct pmc_owner *po, struct thread *td) 1205 { 1206 1207 PMCLOG_RESERVE(po, THR_EXIT, sizeof(struct pmclog_threadexit)); 1208 PMCLOG_EMIT32(td->td_tid); 1209 PMCLOG_DESPATCH(po); 1210 } 1211 1212 /* 1213 * Write a user log entry. 1214 */ 1215 1216 int 1217 pmclog_process_userlog(struct pmc_owner *po, struct pmc_op_writelog *wl) 1218 { 1219 int error; 1220 1221 PMCDBG2(LOG,WRI,1, "writelog po=%p ud=0x%x", po, wl->pm_userdata); 1222 1223 error = 0; 1224 1225 PMCLOG_RESERVE_WITH_ERROR(po, USERDATA, 1226 sizeof(struct pmclog_userdata)); 1227 PMCLOG_EMIT32(wl->pm_userdata); 1228 PMCLOG_DESPATCH(po); 1229 1230 error: 1231 return (error); 1232 } 1233 1234 /* 1235 * Initialization. 1236 * 1237 * Create a pool of log buffers and initialize mutexes. 1238 */ 1239 1240 void 1241 pmclog_initialize() 1242 { 1243 int domain; 1244 struct pmclog_buffer *plb; 1245 1246 if (pmclog_buffer_size <= 0 || pmclog_buffer_size > 16*1024) { 1247 (void) printf("hwpmc: tunable logbuffersize=%d must be " 1248 "greater than zero and less than or equal to 16MB.\n", 1249 pmclog_buffer_size); 1250 pmclog_buffer_size = PMC_LOG_BUFFER_SIZE; 1251 } 1252 1253 if (pmc_nlogbuffers_pcpu <= 0) { 1254 (void) printf("hwpmc: tunable nlogbuffers=%d must be greater " 1255 "than zero.\n", pmc_nlogbuffers_pcpu); 1256 pmc_nlogbuffers_pcpu = PMC_NLOGBUFFERS_PCPU; 1257 } 1258 if (pmc_nlogbuffers_pcpu*pmclog_buffer_size > 32*1024) { 1259 (void) printf("hwpmc: memory allocated pcpu must be less than 32MB (is %dK).\n", 1260 pmc_nlogbuffers_pcpu*pmclog_buffer_size); 1261 pmc_nlogbuffers_pcpu = PMC_NLOGBUFFERS_PCPU; 1262 pmclog_buffer_size = PMC_LOG_BUFFER_SIZE; 1263 } 1264 for (domain = 0; domain < NDOMAINS; domain++) { 1265 int ncpus = pmc_dom_hdrs[domain]->pdbh_ncpus; 1266 int total = ncpus*pmc_nlogbuffers_pcpu; 1267 1268 plb = malloc_domain(sizeof(struct pmclog_buffer)*total, M_PMC, domain, M_WAITOK|M_ZERO); 1269 pmc_dom_hdrs[domain]->pdbh_plbs = plb; 1270 for (int i = 0; i < total; i++, plb++) { 1271 void *buf; 1272 1273 buf = malloc_domain(1024 * pmclog_buffer_size, M_PMC, domain, 1274 M_WAITOK|M_ZERO); 1275 PMCLOG_INIT_BUFFER_DESCRIPTOR(plb, buf, domain); 1276 pmc_plb_rele_unlocked(plb); 1277 } 1278 } 1279 mtx_init(&pmc_kthread_mtx, "pmc-kthread", "pmc-sleep", MTX_DEF); 1280 } 1281 1282 /* 1283 * Shutdown logging. 1284 * 1285 * Destroy mutexes and release memory back the to free pool. 1286 */ 1287 1288 void 1289 pmclog_shutdown() 1290 { 1291 struct pmclog_buffer *plb; 1292 int domain; 1293 1294 mtx_destroy(&pmc_kthread_mtx); 1295 1296 for (domain = 0; domain < NDOMAINS; domain++) { 1297 while ((plb = TAILQ_FIRST(&pmc_dom_hdrs[domain]->pdbh_head)) != NULL) { 1298 TAILQ_REMOVE(&pmc_dom_hdrs[domain]->pdbh_head, plb, plb_next); 1299 free(plb->plb_base, M_PMC); 1300 } 1301 free(pmc_dom_hdrs[domain]->pdbh_plbs, M_PMC); 1302 } 1303 } 1304