xref: /freebsd/sys/kern/kern_pmc.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
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>
34fadcc6e2SJoseph Koshy #include "opt_hwpmc_hooks.h"
35fadcc6e2SJoseph Koshy 
369978bd99SMark Johnston #include <sys/param.h>
37f5f9340bSFabien Thomas #include <sys/ctype.h>
389978bd99SMark Johnston #include <sys/domainset.h>
39f5f9340bSFabien Thomas #include <sys/param.h>
40f5f9340bSFabien Thomas #include <sys/malloc.h>
41f5f9340bSFabien Thomas #include <sys/kernel.h>
42f5f9340bSFabien Thomas #include <sys/lock.h>
43f5f9340bSFabien Thomas #include <sys/mutex.h>
44fadcc6e2SJoseph Koshy #include <sys/pmc.h>
45ebccf1e3SJoseph Koshy #include <sys/pmckern.h>
46ebccf1e3SJoseph Koshy #include <sys/smp.h>
47de5b1952SAlexander Leidinger #include <sys/sysctl.h>
48f5f9340bSFabien Thomas #include <sys/systm.h>
49ebccf1e3SJoseph Koshy 
500f00315cSMatt Macy #include <vm/vm.h>
510f00315cSMatt Macy #include <vm/vm_extern.h>
520f00315cSMatt Macy #include <vm/vm_kern.h>
530f00315cSMatt Macy 
54f4e98881SRuslan Ermilov #ifdef	HWPMC_HOOKS
55de5b1952SAlexander Leidinger FEATURE(hwpmc_hooks, "Kernel support for HW PMC");
56fadcc6e2SJoseph Koshy #define	PMC_KERNEL_VERSION	PMC_VERSION
57fadcc6e2SJoseph Koshy #else
58fadcc6e2SJoseph Koshy #define	PMC_KERNEL_VERSION	0
59fadcc6e2SJoseph Koshy #endif
60fadcc6e2SJoseph Koshy 
61f5f9340bSFabien Thomas MALLOC_DECLARE(M_PMCHOOKS);
62f5f9340bSFabien Thomas MALLOC_DEFINE(M_PMCHOOKS, "pmchooks", "Memory space for PMC hooks");
63f5f9340bSFabien Thomas 
640f00315cSMatt Macy /* memory pool */
650f00315cSMatt Macy MALLOC_DEFINE(M_PMC, "pmc", "Memory space for the PMC module");
660f00315cSMatt Macy 
67fadcc6e2SJoseph Koshy const int pmc_kernel_version = PMC_KERNEL_VERSION;
68ebccf1e3SJoseph Koshy 
69ebccf1e3SJoseph Koshy /* Hook variable. */
7095839d3dSMateusz Guzik int __read_mostly (*pmc_hook)(struct thread *td, int function, void *arg) = NULL;
71ebccf1e3SJoseph Koshy 
72ebccf1e3SJoseph Koshy /* Interrupt handler */
73eb7c9019SMatt Macy int __read_mostly (*pmc_intr)(struct trapframe *tf) = NULL;
7436c0fd9dSJoseph Koshy 
75e6b475e0SMatt Macy DPCPU_DEFINE(uint8_t, pmc_sampled);
76f263522aSJoseph Koshy 
77f263522aSJoseph Koshy /*
78f263522aSJoseph Koshy  * A global count of SS mode PMCs.  When non-zero, this means that
79f263522aSJoseph Koshy  * we have processes that are sampling the system as a whole.
80f263522aSJoseph Koshy  */
81f263522aSJoseph Koshy volatile int pmc_ss_count;
82ebccf1e3SJoseph Koshy 
83ebccf1e3SJoseph Koshy /*
84ebccf1e3SJoseph Koshy  * Since PMC(4) may not be loaded in the current kernel, the
85ebccf1e3SJoseph Koshy  * convention followed is that a non-NULL value of 'pmc_hook' implies
86ebccf1e3SJoseph Koshy  * the presence of this kernel module.
87ebccf1e3SJoseph Koshy  *
88ebccf1e3SJoseph Koshy  * This requires us to protect 'pmc_hook' with a
89ebccf1e3SJoseph Koshy  * shared (sx) lock -- thus making the process of calling into PMC(4)
90ebccf1e3SJoseph Koshy  * somewhat more expensive than a simple 'if' check and indirect call.
91ebccf1e3SJoseph Koshy  */
92fadcc6e2SJoseph Koshy struct sx pmc_sx;
930f00315cSMatt Macy SX_SYSINIT(pmcsx, &pmc_sx, "pmc-sx");
94d07f36b0SJoseph Koshy 
95f5f9340bSFabien Thomas /*
96f5f9340bSFabien Thomas  * PMC Soft per cpu trapframe.
97f5f9340bSFabien Thomas  */
98f5f9340bSFabien Thomas struct trapframe pmc_tf[MAXCPU];
99f5f9340bSFabien Thomas 
100f5f9340bSFabien Thomas /*
1010f00315cSMatt Macy  * Per domain list of buffer headers
1020f00315cSMatt Macy  */
1030f00315cSMatt Macy __read_mostly struct pmc_domain_buffer_header *pmc_dom_hdrs[MAXMEMDOM];
1040f00315cSMatt Macy 
1050f00315cSMatt Macy /*
106f5f9340bSFabien Thomas  * PMC Soft use a global table to store registered events.
107f5f9340bSFabien Thomas  */
108f5f9340bSFabien Thomas 
1097029da5cSPawel Biernacki SYSCTL_NODE(_kern, OID_AUTO, hwpmc, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1107029da5cSPawel Biernacki     "HWPMC parameters");
111f5f9340bSFabien Thomas 
112f5f9340bSFabien Thomas static int pmc_softevents = 16;
113af3b2549SHans Petter Selasky SYSCTL_INT(_kern_hwpmc, OID_AUTO, softevents, CTLFLAG_RDTUN,
114f5f9340bSFabien Thomas     &pmc_softevents, 0, "maximum number of soft events");
115f5f9340bSFabien Thomas 
116f5f9340bSFabien Thomas int pmc_softs_count;
117f5f9340bSFabien Thomas struct pmc_soft **pmc_softs;
118f5f9340bSFabien Thomas 
1190f00315cSMatt Macy struct mtx pmc_softs_mtx;
120f5f9340bSFabien Thomas MTX_SYSINIT(pmc_soft_mtx, &pmc_softs_mtx, "pmc-softs", MTX_SPIN);
121f5f9340bSFabien Thomas 
122ebccf1e3SJoseph Koshy /*
123122ccdc1SJoseph Koshy  * Helper functions.
124122ccdc1SJoseph Koshy  */
125122ccdc1SJoseph Koshy 
126122ccdc1SJoseph Koshy /*
127122ccdc1SJoseph Koshy  * A note on the CPU numbering scheme used by the hwpmc(4) driver.
128122ccdc1SJoseph Koshy  *
129122ccdc1SJoseph Koshy  * CPUs are denoted using numbers in the range 0..[pmc_cpu_max()-1].
130122ccdc1SJoseph Koshy  * CPUs could be numbered "sparsely" in this range; the predicate
131122ccdc1SJoseph Koshy  * `pmc_cpu_is_present()' is used to test whether a given CPU is
132122ccdc1SJoseph Koshy  * physically present.
133122ccdc1SJoseph Koshy  *
134122ccdc1SJoseph Koshy  * Further, a CPU that is physically present may be administratively
135122ccdc1SJoseph Koshy  * disabled or otherwise unavailable for use by hwpmc(4).  The
136122ccdc1SJoseph Koshy  * `pmc_cpu_is_active()' predicate tests for CPU usability.  An
137122ccdc1SJoseph Koshy  * "active" CPU participates in thread scheduling and can field
138122ccdc1SJoseph Koshy  * interrupts raised by PMC hardware.
139122ccdc1SJoseph Koshy  *
140122ccdc1SJoseph Koshy  * On systems with hyperthreaded CPUs, multiple logical CPUs may share
141122ccdc1SJoseph Koshy  * PMC hardware resources.  For such processors one logical CPU is
142122ccdc1SJoseph Koshy  * denoted as the primary owner of the in-CPU PMC resources. The
143122ccdc1SJoseph Koshy  * pmc_cpu_is_primary() predicate is used to distinguish this primary
144122ccdc1SJoseph Koshy  * CPU from the others.
145ebccf1e3SJoseph Koshy  */
146ebccf1e3SJoseph Koshy 
147ebccf1e3SJoseph Koshy int
pmc_cpu_is_active(int cpu)148122ccdc1SJoseph Koshy pmc_cpu_is_active(int cpu)
149ebccf1e3SJoseph Koshy {
150ebccf1e3SJoseph Koshy #ifdef	SMP
151122ccdc1SJoseph Koshy 	return (pmc_cpu_is_present(cpu) &&
15271a19bdcSAttilio Rao 	    !CPU_ISSET(cpu, &hlt_cpus_mask));
153ebccf1e3SJoseph Koshy #else
154122ccdc1SJoseph Koshy 	return (1);
155122ccdc1SJoseph Koshy #endif
156122ccdc1SJoseph Koshy }
157122ccdc1SJoseph Koshy 
158122ccdc1SJoseph Koshy /* Deprecated. */
159122ccdc1SJoseph Koshy int
pmc_cpu_is_disabled(int cpu)160122ccdc1SJoseph Koshy pmc_cpu_is_disabled(int cpu)
161122ccdc1SJoseph Koshy {
162122ccdc1SJoseph Koshy 	return (!pmc_cpu_is_active(cpu));
163122ccdc1SJoseph Koshy }
164122ccdc1SJoseph Koshy 
165122ccdc1SJoseph Koshy int
pmc_cpu_is_present(int cpu)166122ccdc1SJoseph Koshy pmc_cpu_is_present(int cpu)
167122ccdc1SJoseph Koshy {
168122ccdc1SJoseph Koshy #ifdef	SMP
169122ccdc1SJoseph Koshy 	return (!CPU_ABSENT(cpu));
170122ccdc1SJoseph Koshy #else
171122ccdc1SJoseph Koshy 	return (1);
172ebccf1e3SJoseph Koshy #endif
173ebccf1e3SJoseph Koshy }
174ebccf1e3SJoseph Koshy 
175ebccf1e3SJoseph Koshy int
pmc_cpu_is_primary(int cpu)176122ccdc1SJoseph Koshy pmc_cpu_is_primary(int cpu)
177ebccf1e3SJoseph Koshy {
178ebccf1e3SJoseph Koshy #ifdef	SMP
17971a19bdcSAttilio Rao 	return (!CPU_ISSET(cpu, &logical_cpus_mask));
180ebccf1e3SJoseph Koshy #else
181122ccdc1SJoseph Koshy 	return (1);
182ebccf1e3SJoseph Koshy #endif
183ebccf1e3SJoseph Koshy }
184122ccdc1SJoseph Koshy 
185122ccdc1SJoseph Koshy /*
186122ccdc1SJoseph Koshy  * Return the maximum CPU number supported by the system.  The return
187122ccdc1SJoseph Koshy  * value is used for scaling internal data structures and for runtime
188122ccdc1SJoseph Koshy  * checks.
189122ccdc1SJoseph Koshy  */
190122ccdc1SJoseph Koshy unsigned int
pmc_cpu_max(void)191122ccdc1SJoseph Koshy pmc_cpu_max(void)
192122ccdc1SJoseph Koshy {
193122ccdc1SJoseph Koshy #ifdef	SMP
194122ccdc1SJoseph Koshy 	return (mp_maxid+1);
195122ccdc1SJoseph Koshy #else
196122ccdc1SJoseph Koshy 	return (1);
197122ccdc1SJoseph Koshy #endif
198122ccdc1SJoseph Koshy }
199122ccdc1SJoseph Koshy 
200122ccdc1SJoseph Koshy #ifdef	INVARIANTS
201122ccdc1SJoseph Koshy 
202122ccdc1SJoseph Koshy /*
203122ccdc1SJoseph Koshy  * Return the count of CPUs in the `active' state in the system.
204122ccdc1SJoseph Koshy  */
205122ccdc1SJoseph Koshy int
pmc_cpu_max_active(void)206122ccdc1SJoseph Koshy pmc_cpu_max_active(void)
207122ccdc1SJoseph Koshy {
208122ccdc1SJoseph Koshy #ifdef	SMP
209122ccdc1SJoseph Koshy 	/*
210122ccdc1SJoseph Koshy 	 * When support for CPU hot-plugging is added to the kernel,
211122ccdc1SJoseph Koshy 	 * this function would change to return the current number
212122ccdc1SJoseph Koshy 	 * of "active" CPUs.
213122ccdc1SJoseph Koshy 	 */
214122ccdc1SJoseph Koshy 	return (mp_ncpus);
215122ccdc1SJoseph Koshy #else
216122ccdc1SJoseph Koshy 	return (1);
217122ccdc1SJoseph Koshy #endif
218122ccdc1SJoseph Koshy }
219122ccdc1SJoseph Koshy 
220122ccdc1SJoseph Koshy #endif
221f5f9340bSFabien Thomas 
222f5f9340bSFabien Thomas /*
223f5f9340bSFabien Thomas  * Cleanup event name:
224f5f9340bSFabien Thomas  * - remove duplicate '_'
225f5f9340bSFabien Thomas  * - all uppercase
226f5f9340bSFabien Thomas  */
227f5f9340bSFabien Thomas static void
pmc_soft_namecleanup(char * name)228f5f9340bSFabien Thomas pmc_soft_namecleanup(char *name)
229f5f9340bSFabien Thomas {
230f5f9340bSFabien Thomas 	char *p, *q;
231f5f9340bSFabien Thomas 
232f5f9340bSFabien Thomas 	p = q = name;
233f5f9340bSFabien Thomas 
234f5f9340bSFabien Thomas 	for ( ; *p == '_' ; p++)
235f5f9340bSFabien Thomas 		;
236f5f9340bSFabien Thomas 	for ( ; *p ; p++) {
237f5f9340bSFabien Thomas 		if (*p == '_' && (*(p + 1) == '_' || *(p + 1) == '\0'))
238f5f9340bSFabien Thomas 			continue;
239f5f9340bSFabien Thomas 		else
240f5f9340bSFabien Thomas 			*q++ = toupper(*p);
241f5f9340bSFabien Thomas 	}
242f5f9340bSFabien Thomas 	*q = '\0';
243f5f9340bSFabien Thomas }
244f5f9340bSFabien Thomas 
245f5f9340bSFabien Thomas void
pmc_soft_ev_register(struct pmc_soft * ps)246f5f9340bSFabien Thomas pmc_soft_ev_register(struct pmc_soft *ps)
247f5f9340bSFabien Thomas {
248f5f9340bSFabien Thomas 	static int warned = 0;
249f5f9340bSFabien Thomas 	int n;
250f5f9340bSFabien Thomas 
251f5f9340bSFabien Thomas 	ps->ps_running  = 0;
252f5f9340bSFabien Thomas 	ps->ps_ev.pm_ev_code = 0; /* invalid */
253f5f9340bSFabien Thomas 	pmc_soft_namecleanup(ps->ps_ev.pm_ev_name);
254f5f9340bSFabien Thomas 
255f5f9340bSFabien Thomas 	mtx_lock_spin(&pmc_softs_mtx);
256f5f9340bSFabien Thomas 
257f5f9340bSFabien Thomas 	if (pmc_softs_count >= pmc_softevents) {
258f5f9340bSFabien Thomas 		/*
259f5f9340bSFabien Thomas 		 * XXX Reusing events can enter a race condition where
260f5f9340bSFabien Thomas 		 * new allocated event will be used as an old one.
261f5f9340bSFabien Thomas 		 */
262f5f9340bSFabien Thomas 		for (n = 0; n < pmc_softevents; n++)
263f5f9340bSFabien Thomas 			if (pmc_softs[n] == NULL)
264f5f9340bSFabien Thomas 				break;
265f5f9340bSFabien Thomas 		if (n == pmc_softevents) {
266f5f9340bSFabien Thomas 			mtx_unlock_spin(&pmc_softs_mtx);
267f5f9340bSFabien Thomas 			if (!warned) {
268f5f9340bSFabien Thomas 				printf("hwpmc: too many soft events, "
269f5f9340bSFabien Thomas 				    "increase kern.hwpmc.softevents tunable\n");
270f5f9340bSFabien Thomas 				warned = 1;
271f5f9340bSFabien Thomas 			}
272f5f9340bSFabien Thomas 			return;
273f5f9340bSFabien Thomas 		}
274f5f9340bSFabien Thomas 
275f5f9340bSFabien Thomas 		ps->ps_ev.pm_ev_code = PMC_EV_SOFT_FIRST + n;
276f5f9340bSFabien Thomas 		pmc_softs[n] = ps;
277f5f9340bSFabien Thomas 	} else {
278f5f9340bSFabien Thomas 		ps->ps_ev.pm_ev_code = PMC_EV_SOFT_FIRST + pmc_softs_count;
279f5f9340bSFabien Thomas 		pmc_softs[pmc_softs_count++] = ps;
280f5f9340bSFabien Thomas 	}
281f5f9340bSFabien Thomas 
282f5f9340bSFabien Thomas 	mtx_unlock_spin(&pmc_softs_mtx);
283f5f9340bSFabien Thomas }
284f5f9340bSFabien Thomas 
285f5f9340bSFabien Thomas void
pmc_soft_ev_deregister(struct pmc_soft * ps)286f5f9340bSFabien Thomas pmc_soft_ev_deregister(struct pmc_soft *ps)
287f5f9340bSFabien Thomas {
288f5f9340bSFabien Thomas 
289f5f9340bSFabien Thomas 	KASSERT(ps != NULL, ("pmc_soft_deregister: called with NULL"));
290f5f9340bSFabien Thomas 
291f5f9340bSFabien Thomas 	mtx_lock_spin(&pmc_softs_mtx);
292f5f9340bSFabien Thomas 
293f5f9340bSFabien Thomas 	if (ps->ps_ev.pm_ev_code != 0 &&
294f5f9340bSFabien Thomas 	    (ps->ps_ev.pm_ev_code - PMC_EV_SOFT_FIRST) < pmc_softevents) {
295bbf6e514SWarner Losh 		KASSERT((int)ps->ps_ev.pm_ev_code >= PMC_EV_SOFT_FIRST &&
296bbf6e514SWarner Losh 		    (int)ps->ps_ev.pm_ev_code <= PMC_EV_SOFT_LAST,
297f5f9340bSFabien Thomas 		    ("pmc_soft_deregister: invalid event value"));
298f5f9340bSFabien Thomas 		pmc_softs[ps->ps_ev.pm_ev_code - PMC_EV_SOFT_FIRST] = NULL;
299f5f9340bSFabien Thomas 	}
300f5f9340bSFabien Thomas 
301f5f9340bSFabien Thomas 	mtx_unlock_spin(&pmc_softs_mtx);
302f5f9340bSFabien Thomas }
303f5f9340bSFabien Thomas 
304f5f9340bSFabien Thomas struct pmc_soft *
pmc_soft_ev_acquire(enum pmc_event ev)305f5f9340bSFabien Thomas pmc_soft_ev_acquire(enum pmc_event ev)
306f5f9340bSFabien Thomas {
307f5f9340bSFabien Thomas 	struct pmc_soft *ps;
308f5f9340bSFabien Thomas 
309f5f9340bSFabien Thomas 	if (ev == 0 || (ev - PMC_EV_SOFT_FIRST) >= pmc_softevents)
310f5f9340bSFabien Thomas 		return NULL;
311f5f9340bSFabien Thomas 
312bbf6e514SWarner Losh 	KASSERT((int)ev >= PMC_EV_SOFT_FIRST &&
313bbf6e514SWarner Losh 	    (int)ev <= PMC_EV_SOFT_LAST,
314f5f9340bSFabien Thomas 	    ("event out of range"));
315f5f9340bSFabien Thomas 
316f5f9340bSFabien Thomas 	mtx_lock_spin(&pmc_softs_mtx);
317f5f9340bSFabien Thomas 
318f5f9340bSFabien Thomas 	ps = pmc_softs[ev - PMC_EV_SOFT_FIRST];
319f5f9340bSFabien Thomas 	if (ps == NULL)
320f5f9340bSFabien Thomas 		mtx_unlock_spin(&pmc_softs_mtx);
321f5f9340bSFabien Thomas 
322f5f9340bSFabien Thomas 	return ps;
323f5f9340bSFabien Thomas }
324f5f9340bSFabien Thomas 
325f5f9340bSFabien Thomas void
pmc_soft_ev_release(struct pmc_soft * ps)326f5f9340bSFabien Thomas pmc_soft_ev_release(struct pmc_soft *ps)
327f5f9340bSFabien Thomas {
328f5f9340bSFabien Thomas 
329f5f9340bSFabien Thomas 	mtx_unlock_spin(&pmc_softs_mtx);
330f5f9340bSFabien Thomas }
331f5f9340bSFabien Thomas 
332f5f9340bSFabien Thomas /*
333f5f9340bSFabien Thomas  *  Initialise hwpmc.
334f5f9340bSFabien Thomas  */
335f5f9340bSFabien Thomas static void
init_hwpmc(void * dummy __unused)336f5f9340bSFabien Thomas init_hwpmc(void *dummy __unused)
337f5f9340bSFabien Thomas {
3380f00315cSMatt Macy 	int domain, cpu;
3390f00315cSMatt Macy 
340f5f9340bSFabien Thomas 	if (pmc_softevents <= 0 ||
341f5f9340bSFabien Thomas 	    pmc_softevents > PMC_EV_DYN_COUNT) {
342f5f9340bSFabien Thomas 		(void) printf("hwpmc: tunable \"softevents\"=%d out of "
343f5f9340bSFabien Thomas 		    "range.\n", pmc_softevents);
344f5f9340bSFabien Thomas 		pmc_softevents = PMC_EV_DYN_COUNT;
345f5f9340bSFabien Thomas 	}
3464aed5937SMark Johnston 	pmc_softs = malloc(pmc_softevents * sizeof(*pmc_softs), M_PMCHOOKS,
3474aed5937SMark Johnston 	    M_WAITOK | M_ZERO);
3489978bd99SMark Johnston 
3499978bd99SMark Johnston 	for (domain = 0; domain < vm_ndomains; domain++) {
3509978bd99SMark Johnston 		pmc_dom_hdrs[domain] = malloc_domainset(
3519978bd99SMark Johnston 		    sizeof(struct pmc_domain_buffer_header), M_PMC,
3529978bd99SMark Johnston 		    DOMAINSET_PREF(domain), M_WAITOK | M_ZERO);
3530f00315cSMatt Macy 		mtx_init(&pmc_dom_hdrs[domain]->pdbh_mtx, "pmc_bufferlist_mtx", "pmc-leaf", MTX_SPIN);
3540f00315cSMatt Macy 		TAILQ_INIT(&pmc_dom_hdrs[domain]->pdbh_head);
3550f00315cSMatt Macy 	}
3560f00315cSMatt Macy 	CPU_FOREACH(cpu) {
3579978bd99SMark Johnston 		domain = pcpu_find(cpu)->pc_domain;
3580f00315cSMatt Macy 		KASSERT(pmc_dom_hdrs[domain] != NULL, ("no mem allocated for domain: %d", domain));
3590f00315cSMatt Macy 		pmc_dom_hdrs[domain]->pdbh_ncpus++;
3600f00315cSMatt Macy 	}
3610f00315cSMatt Macy 
362f5f9340bSFabien Thomas }
363f5f9340bSFabien Thomas 
364f5f9340bSFabien Thomas SYSINIT(hwpmc, SI_SUB_KDTRACE, SI_ORDER_FIRST, init_hwpmc, NULL);
365