1ebccf1e3SJoseph Koshy /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 4122ccdc1SJoseph Koshy * Copyright (c) 2003-2008 Joseph Koshy 5d07f36b0SJoseph Koshy * Copyright (c) 2007 The FreeBSD Foundation 6d07f36b0SJoseph Koshy * All rights reserved. 7d07f36b0SJoseph Koshy * 8d07f36b0SJoseph Koshy * Portions of this software were developed by A. Joseph Koshy under 9d07f36b0SJoseph Koshy * sponsorship from the FreeBSD Foundation and Google, Inc. 10ebccf1e3SJoseph Koshy * 11ebccf1e3SJoseph Koshy * Redistribution and use in source and binary forms, with or without 12ebccf1e3SJoseph Koshy * modification, are permitted provided that the following conditions 13ebccf1e3SJoseph Koshy * are met: 14ebccf1e3SJoseph Koshy * 1. Redistributions of source code must retain the above copyright 15ebccf1e3SJoseph Koshy * notice, this list of conditions and the following disclaimer. 16ebccf1e3SJoseph Koshy * 2. Redistributions in binary form must reproduce the above copyright 17ebccf1e3SJoseph Koshy * notice, this list of conditions and the following disclaimer in the 18ebccf1e3SJoseph Koshy * documentation and/or other materials provided with the distribution. 19ebccf1e3SJoseph Koshy * 20ebccf1e3SJoseph Koshy * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 21ebccf1e3SJoseph Koshy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22ebccf1e3SJoseph Koshy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23ebccf1e3SJoseph Koshy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 24ebccf1e3SJoseph Koshy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25ebccf1e3SJoseph Koshy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26ebccf1e3SJoseph Koshy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27ebccf1e3SJoseph Koshy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28ebccf1e3SJoseph Koshy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29ebccf1e3SJoseph Koshy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30ebccf1e3SJoseph Koshy * SUCH DAMAGE. 31ebccf1e3SJoseph Koshy */ 32ebccf1e3SJoseph Koshy 33ebccf1e3SJoseph Koshy #include <sys/cdefs.h> 34ebccf1e3SJoseph Koshy __FBSDID("$FreeBSD$"); 35ebccf1e3SJoseph Koshy 36fadcc6e2SJoseph Koshy #include "opt_hwpmc_hooks.h" 37fadcc6e2SJoseph Koshy 389978bd99SMark Johnston #include <sys/param.h> 39f5f9340bSFabien Thomas #include <sys/ctype.h> 409978bd99SMark Johnston #include <sys/domainset.h> 41f5f9340bSFabien Thomas #include <sys/param.h> 42f5f9340bSFabien Thomas #include <sys/malloc.h> 43f5f9340bSFabien Thomas #include <sys/kernel.h> 44f5f9340bSFabien Thomas #include <sys/lock.h> 45f5f9340bSFabien Thomas #include <sys/mutex.h> 46fadcc6e2SJoseph Koshy #include <sys/pmc.h> 47ebccf1e3SJoseph Koshy #include <sys/pmckern.h> 48ebccf1e3SJoseph Koshy #include <sys/smp.h> 49de5b1952SAlexander Leidinger #include <sys/sysctl.h> 50f5f9340bSFabien Thomas #include <sys/systm.h> 51ebccf1e3SJoseph Koshy 520f00315cSMatt Macy #include <vm/vm.h> 530f00315cSMatt Macy #include <vm/vm_extern.h> 540f00315cSMatt Macy #include <vm/vm_kern.h> 550f00315cSMatt Macy 56f4e98881SRuslan Ermilov #ifdef HWPMC_HOOKS 57de5b1952SAlexander Leidinger FEATURE(hwpmc_hooks, "Kernel support for HW PMC"); 58fadcc6e2SJoseph Koshy #define PMC_KERNEL_VERSION PMC_VERSION 59fadcc6e2SJoseph Koshy #else 60fadcc6e2SJoseph Koshy #define PMC_KERNEL_VERSION 0 61fadcc6e2SJoseph Koshy #endif 62fadcc6e2SJoseph Koshy 63f5f9340bSFabien Thomas MALLOC_DECLARE(M_PMCHOOKS); 64f5f9340bSFabien Thomas MALLOC_DEFINE(M_PMCHOOKS, "pmchooks", "Memory space for PMC hooks"); 65f5f9340bSFabien Thomas 660f00315cSMatt Macy /* memory pool */ 670f00315cSMatt Macy MALLOC_DEFINE(M_PMC, "pmc", "Memory space for the PMC module"); 680f00315cSMatt Macy 69fadcc6e2SJoseph Koshy const int pmc_kernel_version = PMC_KERNEL_VERSION; 70ebccf1e3SJoseph Koshy 71ebccf1e3SJoseph Koshy /* Hook variable. */ 7295839d3dSMateusz Guzik int __read_mostly (*pmc_hook)(struct thread *td, int function, void *arg) = NULL; 73ebccf1e3SJoseph Koshy 74ebccf1e3SJoseph Koshy /* Interrupt handler */ 75eb7c9019SMatt Macy int __read_mostly (*pmc_intr)(struct trapframe *tf) = NULL; 7636c0fd9dSJoseph Koshy 77e6b475e0SMatt Macy DPCPU_DEFINE(uint8_t, pmc_sampled); 78f263522aSJoseph Koshy 79f263522aSJoseph Koshy /* 80f263522aSJoseph Koshy * A global count of SS mode PMCs. When non-zero, this means that 81f263522aSJoseph Koshy * we have processes that are sampling the system as a whole. 82f263522aSJoseph Koshy */ 83f263522aSJoseph Koshy volatile int pmc_ss_count; 84ebccf1e3SJoseph Koshy 85ebccf1e3SJoseph Koshy /* 86ebccf1e3SJoseph Koshy * Since PMC(4) may not be loaded in the current kernel, the 87ebccf1e3SJoseph Koshy * convention followed is that a non-NULL value of 'pmc_hook' implies 88ebccf1e3SJoseph Koshy * the presence of this kernel module. 89ebccf1e3SJoseph Koshy * 90ebccf1e3SJoseph Koshy * This requires us to protect 'pmc_hook' with a 91ebccf1e3SJoseph Koshy * shared (sx) lock -- thus making the process of calling into PMC(4) 92ebccf1e3SJoseph Koshy * somewhat more expensive than a simple 'if' check and indirect call. 93ebccf1e3SJoseph Koshy */ 94fadcc6e2SJoseph Koshy struct sx pmc_sx; 950f00315cSMatt Macy SX_SYSINIT(pmcsx, &pmc_sx, "pmc-sx"); 96d07f36b0SJoseph Koshy 97f5f9340bSFabien Thomas /* 98f5f9340bSFabien Thomas * PMC Soft per cpu trapframe. 99f5f9340bSFabien Thomas */ 100f5f9340bSFabien Thomas struct trapframe pmc_tf[MAXCPU]; 101f5f9340bSFabien Thomas 102f5f9340bSFabien Thomas /* 1030f00315cSMatt Macy * Per domain list of buffer headers 1040f00315cSMatt Macy */ 1050f00315cSMatt Macy __read_mostly struct pmc_domain_buffer_header *pmc_dom_hdrs[MAXMEMDOM]; 1060f00315cSMatt Macy 1070f00315cSMatt Macy /* 108f5f9340bSFabien Thomas * PMC Soft use a global table to store registered events. 109f5f9340bSFabien Thomas */ 110f5f9340bSFabien Thomas 1117029da5cSPawel Biernacki SYSCTL_NODE(_kern, OID_AUTO, hwpmc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 1127029da5cSPawel Biernacki "HWPMC parameters"); 113f5f9340bSFabien Thomas 114f5f9340bSFabien Thomas static int pmc_softevents = 16; 115af3b2549SHans Petter Selasky SYSCTL_INT(_kern_hwpmc, OID_AUTO, softevents, CTLFLAG_RDTUN, 116f5f9340bSFabien Thomas &pmc_softevents, 0, "maximum number of soft events"); 117f5f9340bSFabien Thomas 118f5f9340bSFabien Thomas int pmc_softs_count; 119f5f9340bSFabien Thomas struct pmc_soft **pmc_softs; 120f5f9340bSFabien Thomas 1210f00315cSMatt Macy struct mtx pmc_softs_mtx; 122f5f9340bSFabien Thomas MTX_SYSINIT(pmc_soft_mtx, &pmc_softs_mtx, "pmc-softs", MTX_SPIN); 123f5f9340bSFabien Thomas 124ebccf1e3SJoseph Koshy /* 125122ccdc1SJoseph Koshy * Helper functions. 126122ccdc1SJoseph Koshy */ 127122ccdc1SJoseph Koshy 128122ccdc1SJoseph Koshy /* 129122ccdc1SJoseph Koshy * A note on the CPU numbering scheme used by the hwpmc(4) driver. 130122ccdc1SJoseph Koshy * 131122ccdc1SJoseph Koshy * CPUs are denoted using numbers in the range 0..[pmc_cpu_max()-1]. 132122ccdc1SJoseph Koshy * CPUs could be numbered "sparsely" in this range; the predicate 133122ccdc1SJoseph Koshy * `pmc_cpu_is_present()' is used to test whether a given CPU is 134122ccdc1SJoseph Koshy * physically present. 135122ccdc1SJoseph Koshy * 136122ccdc1SJoseph Koshy * Further, a CPU that is physically present may be administratively 137122ccdc1SJoseph Koshy * disabled or otherwise unavailable for use by hwpmc(4). The 138122ccdc1SJoseph Koshy * `pmc_cpu_is_active()' predicate tests for CPU usability. An 139122ccdc1SJoseph Koshy * "active" CPU participates in thread scheduling and can field 140122ccdc1SJoseph Koshy * interrupts raised by PMC hardware. 141122ccdc1SJoseph Koshy * 142122ccdc1SJoseph Koshy * On systems with hyperthreaded CPUs, multiple logical CPUs may share 143122ccdc1SJoseph Koshy * PMC hardware resources. For such processors one logical CPU is 144122ccdc1SJoseph Koshy * denoted as the primary owner of the in-CPU PMC resources. The 145122ccdc1SJoseph Koshy * pmc_cpu_is_primary() predicate is used to distinguish this primary 146122ccdc1SJoseph Koshy * CPU from the others. 147ebccf1e3SJoseph Koshy */ 148ebccf1e3SJoseph Koshy 149ebccf1e3SJoseph Koshy int 150122ccdc1SJoseph Koshy pmc_cpu_is_active(int cpu) 151ebccf1e3SJoseph Koshy { 152ebccf1e3SJoseph Koshy #ifdef SMP 153122ccdc1SJoseph Koshy return (pmc_cpu_is_present(cpu) && 15471a19bdcSAttilio Rao !CPU_ISSET(cpu, &hlt_cpus_mask)); 155ebccf1e3SJoseph Koshy #else 156122ccdc1SJoseph Koshy return (1); 157122ccdc1SJoseph Koshy #endif 158122ccdc1SJoseph Koshy } 159122ccdc1SJoseph Koshy 160122ccdc1SJoseph Koshy /* Deprecated. */ 161122ccdc1SJoseph Koshy int 162122ccdc1SJoseph Koshy pmc_cpu_is_disabled(int cpu) 163122ccdc1SJoseph Koshy { 164122ccdc1SJoseph Koshy return (!pmc_cpu_is_active(cpu)); 165122ccdc1SJoseph Koshy } 166122ccdc1SJoseph Koshy 167122ccdc1SJoseph Koshy int 168122ccdc1SJoseph Koshy pmc_cpu_is_present(int cpu) 169122ccdc1SJoseph Koshy { 170122ccdc1SJoseph Koshy #ifdef SMP 171122ccdc1SJoseph Koshy return (!CPU_ABSENT(cpu)); 172122ccdc1SJoseph Koshy #else 173122ccdc1SJoseph Koshy return (1); 174ebccf1e3SJoseph Koshy #endif 175ebccf1e3SJoseph Koshy } 176ebccf1e3SJoseph Koshy 177ebccf1e3SJoseph Koshy int 178122ccdc1SJoseph Koshy pmc_cpu_is_primary(int cpu) 179ebccf1e3SJoseph Koshy { 180ebccf1e3SJoseph Koshy #ifdef SMP 18171a19bdcSAttilio Rao return (!CPU_ISSET(cpu, &logical_cpus_mask)); 182ebccf1e3SJoseph Koshy #else 183122ccdc1SJoseph Koshy return (1); 184ebccf1e3SJoseph Koshy #endif 185ebccf1e3SJoseph Koshy } 186122ccdc1SJoseph Koshy 187122ccdc1SJoseph Koshy /* 188122ccdc1SJoseph Koshy * Return the maximum CPU number supported by the system. The return 189122ccdc1SJoseph Koshy * value is used for scaling internal data structures and for runtime 190122ccdc1SJoseph Koshy * checks. 191122ccdc1SJoseph Koshy */ 192122ccdc1SJoseph Koshy unsigned int 193122ccdc1SJoseph Koshy pmc_cpu_max(void) 194122ccdc1SJoseph Koshy { 195122ccdc1SJoseph Koshy #ifdef SMP 196122ccdc1SJoseph Koshy return (mp_maxid+1); 197122ccdc1SJoseph Koshy #else 198122ccdc1SJoseph Koshy return (1); 199122ccdc1SJoseph Koshy #endif 200122ccdc1SJoseph Koshy } 201122ccdc1SJoseph Koshy 202122ccdc1SJoseph Koshy #ifdef INVARIANTS 203122ccdc1SJoseph Koshy 204122ccdc1SJoseph Koshy /* 205122ccdc1SJoseph Koshy * Return the count of CPUs in the `active' state in the system. 206122ccdc1SJoseph Koshy */ 207122ccdc1SJoseph Koshy int 208122ccdc1SJoseph Koshy pmc_cpu_max_active(void) 209122ccdc1SJoseph Koshy { 210122ccdc1SJoseph Koshy #ifdef SMP 211122ccdc1SJoseph Koshy /* 212122ccdc1SJoseph Koshy * When support for CPU hot-plugging is added to the kernel, 213122ccdc1SJoseph Koshy * this function would change to return the current number 214122ccdc1SJoseph Koshy * of "active" CPUs. 215122ccdc1SJoseph Koshy */ 216122ccdc1SJoseph Koshy return (mp_ncpus); 217122ccdc1SJoseph Koshy #else 218122ccdc1SJoseph Koshy return (1); 219122ccdc1SJoseph Koshy #endif 220122ccdc1SJoseph Koshy } 221122ccdc1SJoseph Koshy 222122ccdc1SJoseph Koshy #endif 223f5f9340bSFabien Thomas 224f5f9340bSFabien Thomas /* 225f5f9340bSFabien Thomas * Cleanup event name: 226f5f9340bSFabien Thomas * - remove duplicate '_' 227f5f9340bSFabien Thomas * - all uppercase 228f5f9340bSFabien Thomas */ 229f5f9340bSFabien Thomas static void 230f5f9340bSFabien Thomas pmc_soft_namecleanup(char *name) 231f5f9340bSFabien Thomas { 232f5f9340bSFabien Thomas char *p, *q; 233f5f9340bSFabien Thomas 234f5f9340bSFabien Thomas p = q = name; 235f5f9340bSFabien Thomas 236f5f9340bSFabien Thomas for ( ; *p == '_' ; p++) 237f5f9340bSFabien Thomas ; 238f5f9340bSFabien Thomas for ( ; *p ; p++) { 239f5f9340bSFabien Thomas if (*p == '_' && (*(p + 1) == '_' || *(p + 1) == '\0')) 240f5f9340bSFabien Thomas continue; 241f5f9340bSFabien Thomas else 242f5f9340bSFabien Thomas *q++ = toupper(*p); 243f5f9340bSFabien Thomas } 244f5f9340bSFabien Thomas *q = '\0'; 245f5f9340bSFabien Thomas } 246f5f9340bSFabien Thomas 247f5f9340bSFabien Thomas void 248f5f9340bSFabien Thomas pmc_soft_ev_register(struct pmc_soft *ps) 249f5f9340bSFabien Thomas { 250f5f9340bSFabien Thomas static int warned = 0; 251f5f9340bSFabien Thomas int n; 252f5f9340bSFabien Thomas 253f5f9340bSFabien Thomas ps->ps_running = 0; 254f5f9340bSFabien Thomas ps->ps_ev.pm_ev_code = 0; /* invalid */ 255f5f9340bSFabien Thomas pmc_soft_namecleanup(ps->ps_ev.pm_ev_name); 256f5f9340bSFabien Thomas 257f5f9340bSFabien Thomas mtx_lock_spin(&pmc_softs_mtx); 258f5f9340bSFabien Thomas 259f5f9340bSFabien Thomas if (pmc_softs_count >= pmc_softevents) { 260f5f9340bSFabien Thomas /* 261f5f9340bSFabien Thomas * XXX Reusing events can enter a race condition where 262f5f9340bSFabien Thomas * new allocated event will be used as an old one. 263f5f9340bSFabien Thomas */ 264f5f9340bSFabien Thomas for (n = 0; n < pmc_softevents; n++) 265f5f9340bSFabien Thomas if (pmc_softs[n] == NULL) 266f5f9340bSFabien Thomas break; 267f5f9340bSFabien Thomas if (n == pmc_softevents) { 268f5f9340bSFabien Thomas mtx_unlock_spin(&pmc_softs_mtx); 269f5f9340bSFabien Thomas if (!warned) { 270f5f9340bSFabien Thomas printf("hwpmc: too many soft events, " 271f5f9340bSFabien Thomas "increase kern.hwpmc.softevents tunable\n"); 272f5f9340bSFabien Thomas warned = 1; 273f5f9340bSFabien Thomas } 274f5f9340bSFabien Thomas return; 275f5f9340bSFabien Thomas } 276f5f9340bSFabien Thomas 277f5f9340bSFabien Thomas ps->ps_ev.pm_ev_code = PMC_EV_SOFT_FIRST + n; 278f5f9340bSFabien Thomas pmc_softs[n] = ps; 279f5f9340bSFabien Thomas } else { 280f5f9340bSFabien Thomas ps->ps_ev.pm_ev_code = PMC_EV_SOFT_FIRST + pmc_softs_count; 281f5f9340bSFabien Thomas pmc_softs[pmc_softs_count++] = ps; 282f5f9340bSFabien Thomas } 283f5f9340bSFabien Thomas 284f5f9340bSFabien Thomas mtx_unlock_spin(&pmc_softs_mtx); 285f5f9340bSFabien Thomas } 286f5f9340bSFabien Thomas 287f5f9340bSFabien Thomas void 288f5f9340bSFabien Thomas pmc_soft_ev_deregister(struct pmc_soft *ps) 289f5f9340bSFabien Thomas { 290f5f9340bSFabien Thomas 291f5f9340bSFabien Thomas KASSERT(ps != NULL, ("pmc_soft_deregister: called with NULL")); 292f5f9340bSFabien Thomas 293f5f9340bSFabien Thomas mtx_lock_spin(&pmc_softs_mtx); 294f5f9340bSFabien Thomas 295f5f9340bSFabien Thomas if (ps->ps_ev.pm_ev_code != 0 && 296f5f9340bSFabien Thomas (ps->ps_ev.pm_ev_code - PMC_EV_SOFT_FIRST) < pmc_softevents) { 297bbf6e514SWarner Losh KASSERT((int)ps->ps_ev.pm_ev_code >= PMC_EV_SOFT_FIRST && 298bbf6e514SWarner Losh (int)ps->ps_ev.pm_ev_code <= PMC_EV_SOFT_LAST, 299f5f9340bSFabien Thomas ("pmc_soft_deregister: invalid event value")); 300f5f9340bSFabien Thomas pmc_softs[ps->ps_ev.pm_ev_code - PMC_EV_SOFT_FIRST] = NULL; 301f5f9340bSFabien Thomas } 302f5f9340bSFabien Thomas 303f5f9340bSFabien Thomas mtx_unlock_spin(&pmc_softs_mtx); 304f5f9340bSFabien Thomas } 305f5f9340bSFabien Thomas 306f5f9340bSFabien Thomas struct pmc_soft * 307f5f9340bSFabien Thomas pmc_soft_ev_acquire(enum pmc_event ev) 308f5f9340bSFabien Thomas { 309f5f9340bSFabien Thomas struct pmc_soft *ps; 310f5f9340bSFabien Thomas 311f5f9340bSFabien Thomas if (ev == 0 || (ev - PMC_EV_SOFT_FIRST) >= pmc_softevents) 312f5f9340bSFabien Thomas return NULL; 313f5f9340bSFabien Thomas 314bbf6e514SWarner Losh KASSERT((int)ev >= PMC_EV_SOFT_FIRST && 315bbf6e514SWarner Losh (int)ev <= PMC_EV_SOFT_LAST, 316f5f9340bSFabien Thomas ("event out of range")); 317f5f9340bSFabien Thomas 318f5f9340bSFabien Thomas mtx_lock_spin(&pmc_softs_mtx); 319f5f9340bSFabien Thomas 320f5f9340bSFabien Thomas ps = pmc_softs[ev - PMC_EV_SOFT_FIRST]; 321f5f9340bSFabien Thomas if (ps == NULL) 322f5f9340bSFabien Thomas mtx_unlock_spin(&pmc_softs_mtx); 323f5f9340bSFabien Thomas 324f5f9340bSFabien Thomas return ps; 325f5f9340bSFabien Thomas } 326f5f9340bSFabien Thomas 327f5f9340bSFabien Thomas void 328f5f9340bSFabien Thomas pmc_soft_ev_release(struct pmc_soft *ps) 329f5f9340bSFabien Thomas { 330f5f9340bSFabien Thomas 331f5f9340bSFabien Thomas mtx_unlock_spin(&pmc_softs_mtx); 332f5f9340bSFabien Thomas } 333f5f9340bSFabien Thomas 334f5f9340bSFabien Thomas /* 335f5f9340bSFabien Thomas * Initialise hwpmc. 336f5f9340bSFabien Thomas */ 337f5f9340bSFabien Thomas static void 338f5f9340bSFabien Thomas init_hwpmc(void *dummy __unused) 339f5f9340bSFabien Thomas { 3400f00315cSMatt Macy int domain, cpu; 3410f00315cSMatt Macy 342f5f9340bSFabien Thomas if (pmc_softevents <= 0 || 343f5f9340bSFabien Thomas pmc_softevents > PMC_EV_DYN_COUNT) { 344f5f9340bSFabien Thomas (void) printf("hwpmc: tunable \"softevents\"=%d out of " 345f5f9340bSFabien Thomas "range.\n", pmc_softevents); 346f5f9340bSFabien Thomas pmc_softevents = PMC_EV_DYN_COUNT; 347f5f9340bSFabien Thomas } 3484aed5937SMark Johnston pmc_softs = malloc(pmc_softevents * sizeof(*pmc_softs), M_PMCHOOKS, 3494aed5937SMark Johnston M_WAITOK | M_ZERO); 3509978bd99SMark Johnston 3519978bd99SMark Johnston for (domain = 0; domain < vm_ndomains; domain++) { 3529978bd99SMark Johnston pmc_dom_hdrs[domain] = malloc_domainset( 3539978bd99SMark Johnston sizeof(struct pmc_domain_buffer_header), M_PMC, 3549978bd99SMark Johnston DOMAINSET_PREF(domain), M_WAITOK | M_ZERO); 3550f00315cSMatt Macy mtx_init(&pmc_dom_hdrs[domain]->pdbh_mtx, "pmc_bufferlist_mtx", "pmc-leaf", MTX_SPIN); 3560f00315cSMatt Macy TAILQ_INIT(&pmc_dom_hdrs[domain]->pdbh_head); 3570f00315cSMatt Macy } 3580f00315cSMatt Macy CPU_FOREACH(cpu) { 3599978bd99SMark Johnston domain = pcpu_find(cpu)->pc_domain; 3600f00315cSMatt Macy KASSERT(pmc_dom_hdrs[domain] != NULL, ("no mem allocated for domain: %d", domain)); 3610f00315cSMatt Macy pmc_dom_hdrs[domain]->pdbh_ncpus++; 3620f00315cSMatt Macy } 3630f00315cSMatt Macy 364f5f9340bSFabien Thomas } 365f5f9340bSFabien Thomas 366f5f9340bSFabien Thomas SYSINIT(hwpmc, SI_SUB_KDTRACE, SI_ORDER_FIRST, init_hwpmc, NULL); 367