kern_pmc.c revision 222813
1/*- 2 * Copyright (c) 2003-2008 Joseph Koshy 3 * Copyright (c) 2007 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by A. Joseph Koshy under 7 * sponsorship from the FreeBSD Foundation and Google, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD: head/sys/kern/kern_pmc.c 222813 2011-06-07 08:46:13Z attilio $"); 33 34#include "opt_hwpmc_hooks.h" 35 36#include <sys/types.h> 37#include <sys/pmc.h> 38#include <sys/pmckern.h> 39#include <sys/smp.h> 40#include <sys/sysctl.h> 41 42#ifdef HWPMC_HOOKS 43FEATURE(hwpmc_hooks, "Kernel support for HW PMC"); 44#define PMC_KERNEL_VERSION PMC_VERSION 45#else 46#define PMC_KERNEL_VERSION 0 47#endif 48 49const int pmc_kernel_version = PMC_KERNEL_VERSION; 50 51/* Hook variable. */ 52int (*pmc_hook)(struct thread *td, int function, void *arg) = NULL; 53 54/* Interrupt handler */ 55int (*pmc_intr)(int cpu, struct trapframe *tf) = NULL; 56 57/* Bitmask of CPUs requiring servicing at hardclock time */ 58volatile cpuset_t pmc_cpumask; 59 60/* 61 * A global count of SS mode PMCs. When non-zero, this means that 62 * we have processes that are sampling the system as a whole. 63 */ 64volatile int pmc_ss_count; 65 66/* 67 * Since PMC(4) may not be loaded in the current kernel, the 68 * convention followed is that a non-NULL value of 'pmc_hook' implies 69 * the presence of this kernel module. 70 * 71 * This requires us to protect 'pmc_hook' with a 72 * shared (sx) lock -- thus making the process of calling into PMC(4) 73 * somewhat more expensive than a simple 'if' check and indirect call. 74 */ 75struct sx pmc_sx; 76 77static void 78pmc_init_sx(void) 79{ 80 sx_init_flags(&pmc_sx, "pmc-sx", SX_NOWITNESS); 81} 82 83SYSINIT(pmcsx, SI_SUB_LOCK, SI_ORDER_MIDDLE, pmc_init_sx, NULL); 84 85/* 86 * Helper functions. 87 */ 88 89/* 90 * A note on the CPU numbering scheme used by the hwpmc(4) driver. 91 * 92 * CPUs are denoted using numbers in the range 0..[pmc_cpu_max()-1]. 93 * CPUs could be numbered "sparsely" in this range; the predicate 94 * `pmc_cpu_is_present()' is used to test whether a given CPU is 95 * physically present. 96 * 97 * Further, a CPU that is physically present may be administratively 98 * disabled or otherwise unavailable for use by hwpmc(4). The 99 * `pmc_cpu_is_active()' predicate tests for CPU usability. An 100 * "active" CPU participates in thread scheduling and can field 101 * interrupts raised by PMC hardware. 102 * 103 * On systems with hyperthreaded CPUs, multiple logical CPUs may share 104 * PMC hardware resources. For such processors one logical CPU is 105 * denoted as the primary owner of the in-CPU PMC resources. The 106 * pmc_cpu_is_primary() predicate is used to distinguish this primary 107 * CPU from the others. 108 */ 109 110int 111pmc_cpu_is_active(int cpu) 112{ 113#ifdef SMP 114 return (pmc_cpu_is_present(cpu) && 115 !CPU_ISSET(cpu, &hlt_cpus_mask)); 116#else 117 return (1); 118#endif 119} 120 121/* Deprecated. */ 122int 123pmc_cpu_is_disabled(int cpu) 124{ 125 return (!pmc_cpu_is_active(cpu)); 126} 127 128int 129pmc_cpu_is_present(int cpu) 130{ 131#ifdef SMP 132 return (!CPU_ABSENT(cpu)); 133#else 134 return (1); 135#endif 136} 137 138int 139pmc_cpu_is_primary(int cpu) 140{ 141#ifdef SMP 142 return (!CPU_ISSET(cpu, &logical_cpus_mask)); 143#else 144 return (1); 145#endif 146} 147 148 149/* 150 * Return the maximum CPU number supported by the system. The return 151 * value is used for scaling internal data structures and for runtime 152 * checks. 153 */ 154unsigned int 155pmc_cpu_max(void) 156{ 157#ifdef SMP 158 return (mp_maxid+1); 159#else 160 return (1); 161#endif 162} 163 164#ifdef INVARIANTS 165 166/* 167 * Return the count of CPUs in the `active' state in the system. 168 */ 169int 170pmc_cpu_max_active(void) 171{ 172#ifdef SMP 173 /* 174 * When support for CPU hot-plugging is added to the kernel, 175 * this function would change to return the current number 176 * of "active" CPUs. 177 */ 178 return (mp_ncpus); 179#else 180 return (1); 181#endif 182} 183 184#endif 185