xref: /freebsd/sys/kern/kern_pmc.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
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