The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/hwpmc/hwpmc_logging.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d11e9ff108cc06ddfaf5576fe370a338


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.