xref: /freebsd/sys/kern/kern_pmc.c (revision eb7c901995d407fa177d99270a2684f844db3921)
1ebccf1e3SJoseph Koshy /*-
28a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 
38fadcc6e2SJoseph Koshy #include <sys/types.h>
39f5f9340bSFabien Thomas #include <sys/ctype.h>
40f5f9340bSFabien Thomas #include <sys/param.h>
41f5f9340bSFabien Thomas #include <sys/malloc.h>
42f5f9340bSFabien Thomas #include <sys/kernel.h>
43f5f9340bSFabien Thomas #include <sys/lock.h>
44f5f9340bSFabien Thomas #include <sys/mutex.h>
45fadcc6e2SJoseph Koshy #include <sys/pmc.h>
46ebccf1e3SJoseph Koshy #include <sys/pmckern.h>
47ebccf1e3SJoseph Koshy #include <sys/smp.h>
48de5b1952SAlexander Leidinger #include <sys/sysctl.h>
49f5f9340bSFabien Thomas #include <sys/systm.h>
50ebccf1e3SJoseph Koshy 
510f00315cSMatt Macy #include <vm/vm.h>
520f00315cSMatt Macy #include <vm/vm_extern.h>
530f00315cSMatt Macy #include <vm/vm_kern.h>
540f00315cSMatt Macy 
55f4e98881SRuslan Ermilov #ifdef	HWPMC_HOOKS
56de5b1952SAlexander Leidinger FEATURE(hwpmc_hooks, "Kernel support for HW PMC");
57fadcc6e2SJoseph Koshy #define	PMC_KERNEL_VERSION	PMC_VERSION
58fadcc6e2SJoseph Koshy #else
59fadcc6e2SJoseph Koshy #define	PMC_KERNEL_VERSION	0
60fadcc6e2SJoseph Koshy #endif
61fadcc6e2SJoseph Koshy 
62f5f9340bSFabien Thomas MALLOC_DECLARE(M_PMCHOOKS);
63f5f9340bSFabien Thomas MALLOC_DEFINE(M_PMCHOOKS, "pmchooks", "Memory space for PMC hooks");
64f5f9340bSFabien Thomas 
650f00315cSMatt Macy /* memory pool */
660f00315cSMatt Macy MALLOC_DEFINE(M_PMC, "pmc", "Memory space for the PMC module");
670f00315cSMatt Macy 
68fadcc6e2SJoseph Koshy const int pmc_kernel_version = PMC_KERNEL_VERSION;
69ebccf1e3SJoseph Koshy 
70ebccf1e3SJoseph Koshy /* Hook variable. */
7195839d3dSMateusz Guzik int __read_mostly (*pmc_hook)(struct thread *td, int function, void *arg) = NULL;
72ebccf1e3SJoseph Koshy 
73ebccf1e3SJoseph Koshy /* Interrupt handler */
74*eb7c9019SMatt Macy int __read_mostly (*pmc_intr)(struct trapframe *tf) = NULL;
7536c0fd9dSJoseph Koshy 
76e6b475e0SMatt Macy DPCPU_DEFINE(uint8_t, pmc_sampled);
77f263522aSJoseph Koshy 
78f263522aSJoseph Koshy /*
79f263522aSJoseph Koshy  * A global count of SS mode PMCs.  When non-zero, this means that
80f263522aSJoseph Koshy  * we have processes that are sampling the system as a whole.
81f263522aSJoseph Koshy  */
82f263522aSJoseph Koshy volatile int pmc_ss_count;
83ebccf1e3SJoseph Koshy 
84ebccf1e3SJoseph Koshy /*
85ebccf1e3SJoseph Koshy  * Since PMC(4) may not be loaded in the current kernel, the
86ebccf1e3SJoseph Koshy  * convention followed is that a non-NULL value of 'pmc_hook' implies
87ebccf1e3SJoseph Koshy  * the presence of this kernel module.
88ebccf1e3SJoseph Koshy  *
89ebccf1e3SJoseph Koshy  * This requires us to protect 'pmc_hook' with a
90ebccf1e3SJoseph Koshy  * shared (sx) lock -- thus making the process of calling into PMC(4)
91ebccf1e3SJoseph Koshy  * somewhat more expensive than a simple 'if' check and indirect call.
92ebccf1e3SJoseph Koshy  */
93fadcc6e2SJoseph Koshy struct sx pmc_sx;
940f00315cSMatt Macy SX_SYSINIT(pmcsx, &pmc_sx, "pmc-sx");
95d07f36b0SJoseph Koshy 
96f5f9340bSFabien Thomas /*
97f5f9340bSFabien Thomas  * PMC Soft per cpu trapframe.
98f5f9340bSFabien Thomas  */
99f5f9340bSFabien Thomas struct trapframe pmc_tf[MAXCPU];
100f5f9340bSFabien Thomas 
101f5f9340bSFabien Thomas /*
1020f00315cSMatt Macy  * Per domain list of buffer headers
1030f00315cSMatt Macy  */
1040f00315cSMatt Macy __read_mostly struct pmc_domain_buffer_header *pmc_dom_hdrs[MAXMEMDOM];
1050f00315cSMatt Macy 
1060f00315cSMatt Macy /*
107f5f9340bSFabien Thomas  * PMC Soft use a global table to store registered events.
108f5f9340bSFabien Thomas  */
109f5f9340bSFabien Thomas 
110f5f9340bSFabien Thomas SYSCTL_NODE(_kern, OID_AUTO, hwpmc, CTLFLAG_RW, 0, "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
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
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
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
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 /*
187122ccdc1SJoseph Koshy  * Return the maximum CPU number supported by the system.  The return
188122ccdc1SJoseph Koshy  * value is used for scaling internal data structures and for runtime
189122ccdc1SJoseph Koshy  * checks.
190122ccdc1SJoseph Koshy  */
191122ccdc1SJoseph Koshy unsigned int
192122ccdc1SJoseph Koshy pmc_cpu_max(void)
193122ccdc1SJoseph Koshy {
194122ccdc1SJoseph Koshy #ifdef	SMP
195122ccdc1SJoseph Koshy 	return (mp_maxid+1);
196122ccdc1SJoseph Koshy #else
197122ccdc1SJoseph Koshy 	return (1);
198122ccdc1SJoseph Koshy #endif
199122ccdc1SJoseph Koshy }
200122ccdc1SJoseph Koshy 
201122ccdc1SJoseph Koshy #ifdef	INVARIANTS
202122ccdc1SJoseph Koshy 
203122ccdc1SJoseph Koshy /*
204122ccdc1SJoseph Koshy  * Return the count of CPUs in the `active' state in the system.
205122ccdc1SJoseph Koshy  */
206122ccdc1SJoseph Koshy int
207122ccdc1SJoseph Koshy pmc_cpu_max_active(void)
208122ccdc1SJoseph Koshy {
209122ccdc1SJoseph Koshy #ifdef	SMP
210122ccdc1SJoseph Koshy 	/*
211122ccdc1SJoseph Koshy 	 * When support for CPU hot-plugging is added to the kernel,
212122ccdc1SJoseph Koshy 	 * this function would change to return the current number
213122ccdc1SJoseph Koshy 	 * of "active" CPUs.
214122ccdc1SJoseph Koshy 	 */
215122ccdc1SJoseph Koshy 	return (mp_ncpus);
216122ccdc1SJoseph Koshy #else
217122ccdc1SJoseph Koshy 	return (1);
218122ccdc1SJoseph Koshy #endif
219122ccdc1SJoseph Koshy }
220122ccdc1SJoseph Koshy 
221122ccdc1SJoseph Koshy #endif
222f5f9340bSFabien Thomas 
223f5f9340bSFabien Thomas /*
224f5f9340bSFabien Thomas  * Cleanup event name:
225f5f9340bSFabien Thomas  * - remove duplicate '_'
226f5f9340bSFabien Thomas  * - all uppercase
227f5f9340bSFabien Thomas  */
228f5f9340bSFabien Thomas static void
229f5f9340bSFabien Thomas pmc_soft_namecleanup(char *name)
230f5f9340bSFabien Thomas {
231f5f9340bSFabien Thomas 	char *p, *q;
232f5f9340bSFabien Thomas 
233f5f9340bSFabien Thomas 	p = q = name;
234f5f9340bSFabien Thomas 
235f5f9340bSFabien Thomas 	for ( ; *p == '_' ; p++)
236f5f9340bSFabien Thomas 		;
237f5f9340bSFabien Thomas 	for ( ; *p ; p++) {
238f5f9340bSFabien Thomas 		if (*p == '_' && (*(p + 1) == '_' || *(p + 1) == '\0'))
239f5f9340bSFabien Thomas 			continue;
240f5f9340bSFabien Thomas 		else
241f5f9340bSFabien Thomas 			*q++ = toupper(*p);
242f5f9340bSFabien Thomas 	}
243f5f9340bSFabien Thomas 	*q = '\0';
244f5f9340bSFabien Thomas }
245f5f9340bSFabien Thomas 
246f5f9340bSFabien Thomas void
247f5f9340bSFabien Thomas pmc_soft_ev_register(struct pmc_soft *ps)
248f5f9340bSFabien Thomas {
249f5f9340bSFabien Thomas 	static int warned = 0;
250f5f9340bSFabien Thomas 	int n;
251f5f9340bSFabien Thomas 
252f5f9340bSFabien Thomas 	ps->ps_running  = 0;
253f5f9340bSFabien Thomas 	ps->ps_ev.pm_ev_code = 0; /* invalid */
254f5f9340bSFabien Thomas 	pmc_soft_namecleanup(ps->ps_ev.pm_ev_name);
255f5f9340bSFabien Thomas 
256f5f9340bSFabien Thomas 	mtx_lock_spin(&pmc_softs_mtx);
257f5f9340bSFabien Thomas 
258f5f9340bSFabien Thomas 	if (pmc_softs_count >= pmc_softevents) {
259f5f9340bSFabien Thomas 		/*
260f5f9340bSFabien Thomas 		 * XXX Reusing events can enter a race condition where
261f5f9340bSFabien Thomas 		 * new allocated event will be used as an old one.
262f5f9340bSFabien Thomas 		 */
263f5f9340bSFabien Thomas 		for (n = 0; n < pmc_softevents; n++)
264f5f9340bSFabien Thomas 			if (pmc_softs[n] == NULL)
265f5f9340bSFabien Thomas 				break;
266f5f9340bSFabien Thomas 		if (n == pmc_softevents) {
267f5f9340bSFabien Thomas 			mtx_unlock_spin(&pmc_softs_mtx);
268f5f9340bSFabien Thomas 			if (!warned) {
269f5f9340bSFabien Thomas 				printf("hwpmc: too many soft events, "
270f5f9340bSFabien Thomas 				    "increase kern.hwpmc.softevents tunable\n");
271f5f9340bSFabien Thomas 				warned = 1;
272f5f9340bSFabien Thomas 			}
273f5f9340bSFabien Thomas 			return;
274f5f9340bSFabien Thomas 		}
275f5f9340bSFabien Thomas 
276f5f9340bSFabien Thomas 		ps->ps_ev.pm_ev_code = PMC_EV_SOFT_FIRST + n;
277f5f9340bSFabien Thomas 		pmc_softs[n] = ps;
278f5f9340bSFabien Thomas 	} else {
279f5f9340bSFabien Thomas 		ps->ps_ev.pm_ev_code = PMC_EV_SOFT_FIRST + pmc_softs_count;
280f5f9340bSFabien Thomas 		pmc_softs[pmc_softs_count++] = ps;
281f5f9340bSFabien Thomas 	}
282f5f9340bSFabien Thomas 
283f5f9340bSFabien Thomas 	mtx_unlock_spin(&pmc_softs_mtx);
284f5f9340bSFabien Thomas }
285f5f9340bSFabien Thomas 
286f5f9340bSFabien Thomas void
287f5f9340bSFabien Thomas pmc_soft_ev_deregister(struct pmc_soft *ps)
288f5f9340bSFabien Thomas {
289f5f9340bSFabien Thomas 
290f5f9340bSFabien Thomas 	KASSERT(ps != NULL, ("pmc_soft_deregister: called with NULL"));
291f5f9340bSFabien Thomas 
292f5f9340bSFabien Thomas 	mtx_lock_spin(&pmc_softs_mtx);
293f5f9340bSFabien Thomas 
294f5f9340bSFabien Thomas 	if (ps->ps_ev.pm_ev_code != 0 &&
295f5f9340bSFabien Thomas 	    (ps->ps_ev.pm_ev_code - PMC_EV_SOFT_FIRST) < pmc_softevents) {
296bbf6e514SWarner Losh 		KASSERT((int)ps->ps_ev.pm_ev_code >= PMC_EV_SOFT_FIRST &&
297bbf6e514SWarner Losh 		    (int)ps->ps_ev.pm_ev_code <= PMC_EV_SOFT_LAST,
298f5f9340bSFabien Thomas 		    ("pmc_soft_deregister: invalid event value"));
299f5f9340bSFabien Thomas 		pmc_softs[ps->ps_ev.pm_ev_code - PMC_EV_SOFT_FIRST] = NULL;
300f5f9340bSFabien Thomas 	}
301f5f9340bSFabien Thomas 
302f5f9340bSFabien Thomas 	mtx_unlock_spin(&pmc_softs_mtx);
303f5f9340bSFabien Thomas }
304f5f9340bSFabien Thomas 
305f5f9340bSFabien Thomas struct pmc_soft *
306f5f9340bSFabien Thomas pmc_soft_ev_acquire(enum pmc_event ev)
307f5f9340bSFabien Thomas {
308f5f9340bSFabien Thomas 	struct pmc_soft *ps;
309f5f9340bSFabien Thomas 
310f5f9340bSFabien Thomas 	if (ev == 0 || (ev - PMC_EV_SOFT_FIRST) >= pmc_softevents)
311f5f9340bSFabien Thomas 		return NULL;
312f5f9340bSFabien Thomas 
313bbf6e514SWarner Losh 	KASSERT((int)ev >= PMC_EV_SOFT_FIRST &&
314bbf6e514SWarner Losh 	    (int)ev <= PMC_EV_SOFT_LAST,
315f5f9340bSFabien Thomas 	    ("event out of range"));
316f5f9340bSFabien Thomas 
317f5f9340bSFabien Thomas 	mtx_lock_spin(&pmc_softs_mtx);
318f5f9340bSFabien Thomas 
319f5f9340bSFabien Thomas 	ps = pmc_softs[ev - PMC_EV_SOFT_FIRST];
320f5f9340bSFabien Thomas 	if (ps == NULL)
321f5f9340bSFabien Thomas 		mtx_unlock_spin(&pmc_softs_mtx);
322f5f9340bSFabien Thomas 
323f5f9340bSFabien Thomas 	return ps;
324f5f9340bSFabien Thomas }
325f5f9340bSFabien Thomas 
326f5f9340bSFabien Thomas void
327f5f9340bSFabien Thomas pmc_soft_ev_release(struct pmc_soft *ps)
328f5f9340bSFabien Thomas {
329f5f9340bSFabien Thomas 
330f5f9340bSFabien Thomas 	mtx_unlock_spin(&pmc_softs_mtx);
331f5f9340bSFabien Thomas }
332f5f9340bSFabien Thomas 
3330f00315cSMatt Macy #ifdef NUMA
3340f00315cSMatt Macy #define NDOMAINS vm_ndomains
3350f00315cSMatt Macy 
3360f00315cSMatt Macy static int
3370f00315cSMatt Macy getdomain(int cpu)
3380f00315cSMatt Macy {
3390f00315cSMatt Macy 	struct pcpu *pc;
3400f00315cSMatt Macy 
3410f00315cSMatt Macy 	pc = pcpu_find(cpu);
3420f00315cSMatt Macy 	return (pc->pc_domain);
3430f00315cSMatt Macy }
3440f00315cSMatt Macy #else
3450f00315cSMatt Macy #define NDOMAINS 1
3460f00315cSMatt Macy #define malloc_domain(size, type, domain, flags) malloc((size), (type), (flags))
3470f00315cSMatt Macy #define getdomain(cpu) 0
3480f00315cSMatt Macy #endif
349f5f9340bSFabien Thomas /*
350f5f9340bSFabien Thomas  *  Initialise hwpmc.
351f5f9340bSFabien Thomas  */
352f5f9340bSFabien Thomas static void
353f5f9340bSFabien Thomas init_hwpmc(void *dummy __unused)
354f5f9340bSFabien Thomas {
3550f00315cSMatt Macy 	int domain, cpu;
3560f00315cSMatt Macy 
357f5f9340bSFabien Thomas 	if (pmc_softevents <= 0 ||
358f5f9340bSFabien Thomas 	    pmc_softevents > PMC_EV_DYN_COUNT) {
359f5f9340bSFabien Thomas 		(void) printf("hwpmc: tunable \"softevents\"=%d out of "
360f5f9340bSFabien Thomas 		    "range.\n", pmc_softevents);
361f5f9340bSFabien Thomas 		pmc_softevents = PMC_EV_DYN_COUNT;
362f5f9340bSFabien Thomas 	}
363ac2fffa4SPedro F. Giffuni 	pmc_softs = malloc(pmc_softevents * sizeof(struct pmc_soft *), M_PMCHOOKS, M_NOWAIT|M_ZERO);
364f5f9340bSFabien Thomas 	KASSERT(pmc_softs != NULL, ("cannot allocate soft events table"));
3650f00315cSMatt Macy 
3660f00315cSMatt Macy 	for (domain = 0; domain < NDOMAINS; domain++) {
3670f00315cSMatt Macy 		pmc_dom_hdrs[domain] = malloc_domain(sizeof(struct pmc_domain_buffer_header), M_PMC, domain,
3680f00315cSMatt Macy 										M_WAITOK|M_ZERO);
3690f00315cSMatt Macy 		mtx_init(&pmc_dom_hdrs[domain]->pdbh_mtx, "pmc_bufferlist_mtx", "pmc-leaf", MTX_SPIN);
3700f00315cSMatt Macy 		TAILQ_INIT(&pmc_dom_hdrs[domain]->pdbh_head);
3710f00315cSMatt Macy 	}
3720f00315cSMatt Macy 	CPU_FOREACH(cpu) {
3730f00315cSMatt Macy 		domain = getdomain(cpu);
3740f00315cSMatt Macy 		KASSERT(pmc_dom_hdrs[domain] != NULL, ("no mem allocated for domain: %d", domain));
3750f00315cSMatt Macy 		pmc_dom_hdrs[domain]->pdbh_ncpus++;
3760f00315cSMatt Macy 	}
3770f00315cSMatt Macy 
378f5f9340bSFabien Thomas }
379f5f9340bSFabien Thomas 
380f5f9340bSFabien Thomas SYSINIT(hwpmc, SI_SUB_KDTRACE, SI_ORDER_FIRST, init_hwpmc, NULL);
381f5f9340bSFabien Thomas 
382