Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 | /* * Copyright (c) 2012 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. The rights granted to you under the License * may not be used to create, or enable the creation or redistribution of, * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #ifndef KERN_KPC_H #define KERN_KPC_H /* Kernel interfaces to KPC PMC infrastructure. */ #include <machine/machine_kpc.h> #include <kern/thread.h> /* thread_* */ __BEGIN_DECLS /* cross-platform class constants */ #define KPC_CLASS_FIXED (0) #define KPC_CLASS_CONFIGURABLE (1) #define KPC_CLASS_POWER (2) #define KPC_CLASS_RAWPMU (3) #define KPC_CLASS_FIXED_MASK (1u << KPC_CLASS_FIXED) #define KPC_CLASS_CONFIGURABLE_MASK (1u << KPC_CLASS_CONFIGURABLE) #define KPC_CLASS_POWER_MASK (1u << KPC_CLASS_POWER) #define KPC_CLASS_RAWPMU_MASK (1u << KPC_CLASS_RAWPMU) #define KPC_PMU_ERROR (0) #define KPC_PMU_INTEL_V3 (1) #define KPC_PMU_ARM_APPLE (2) #define KPC_PMU_INTEL_V2 (3) #define KPC_PMU_ARM_V2 (4) #define KPC_ALL_CPUS (1u << 31) /* action id setters/getters */ #define FIXED_ACTIONID(ctr) (kpc_actionid[(ctr)]) #define CONFIGURABLE_ACTIONID(ctr) (kpc_actionid[(ctr) + kpc_fixed_count()]) /* reload counter setters/getters */ #define FIXED_RELOAD(ctr) (current_cpu_datap()->cpu_kpc_reload[(ctr)]) #define FIXED_RELOAD_CPU(cpu, ctr) (cpu_datap(cpu)->cpu_kpc_reload[(ctr)]) #define CONFIGURABLE_RELOAD(ctr) (current_cpu_datap()->cpu_kpc_reload[(ctr) + kpc_fixed_count()]) #define CONFIGURABLE_RELOAD_CPU(cpu, ctr) (cpu_datap(cpu)->cpu_kpc_reload[(ctr) + kpc_fixed_count()]) /* shadow counter setters/getters */ #define FIXED_SHADOW(ctr) (current_cpu_datap()->cpu_kpc_shadow[(ctr)]) #define FIXED_SHADOW_CPU(cpu, ctr) (cpu_datap(cpu)->cpu_kpc_shadow[(ctr)]) #define CONFIGURABLE_SHADOW(ctr) (current_cpu_datap()->cpu_kpc_shadow[(ctr) + kpc_fixed_count()]) #define CONFIGURABLE_SHADOW_CPU(cpu, ctr) (cpu_datap(cpu)->cpu_kpc_shadow[(ctr) + kpc_fixed_count()]) /** * Callback for notification when PMCs are acquired/released by a task. The * argument is equal to TRUE if the Power Manager (PM) can use its reserved PMCs. * Otherwise, the argument is equal to FALSE. */ typedef void (*kpc_pm_handler_t)(boolean_t); struct cpu_data; extern boolean_t kpc_register_cpu(struct cpu_data *cpu_data); extern void kpc_unregister_cpu(struct cpu_data *cpu_data); extern bool kpc_supported; /* bootstrap */ extern void kpc_init(void); /* Architecture specific initialisation */ extern void kpc_arch_init(void); /* Get the bitmask of available classes */ extern uint32_t kpc_get_classes(void); /* Get the bitmask of currently running counter classes */ extern uint32_t kpc_get_running(void); /* Get the version of KPC that's being run */ extern int kpc_get_pmu_version(void); /* Set the bitmask of currently running counter classes. Specify * classes = 0 to stop counters */ extern int kpc_set_running(uint32_t classes); /* Read CPU counters */ extern int kpc_get_cpu_counters(boolean_t all_cpus, uint32_t classes, int *curcpu, uint64_t *buf); /* Read shadow counters */ extern int kpc_get_shadow_counters( boolean_t all_cpus, uint32_t classes, int *curcpu, uint64_t *buf ); /* Read current thread's counter accumulations */ extern int kpc_get_curthread_counters(uint32_t *inoutcount, uint64_t *buf); /* Given a config, how many counters and config registers there are */ extern uint32_t kpc_get_counter_count(uint32_t classes); extern uint32_t kpc_get_config_count(uint32_t classes); /* enable/disable thread counting */ extern uint32_t kpc_get_thread_counting(void); extern int kpc_set_thread_counting(uint32_t classes); /* get and set config registers */ extern int kpc_get_config(uint32_t classes, kpc_config_t *current_config); extern int kpc_set_config(uint32_t classes, kpc_config_t *new_config); /* get and set PMI period */ extern int kpc_get_period(uint32_t classes, uint64_t *period); extern int kpc_set_period(uint32_t classes, uint64_t *period); /* get and set kperf actionid */ extern int kpc_get_actionid(uint32_t classes, uint32_t *actionid); extern int kpc_set_actionid(uint32_t classes, uint32_t *actionid); /* hooks on thread create and delete */ extern void kpc_thread_create(thread_t thread); extern void kpc_thread_destroy(thread_t thread); /* allocate a buffer big enough for all counters */ extern uint64_t *kpc_counterbuf_alloc(void); extern void kpc_counterbuf_free(uint64_t*); extern uint32_t kpc_get_counterbuf_size(void); /* whether we're currently accounting into threads */ extern int kpc_threads_counting; /* AST callback for KPC */ extern void kpc_thread_ast_handler( thread_t thread ); #ifdef MACH_KERNEL_PRIVATE /* context switch callback for KPC */ extern boolean_t kpc_off_cpu_active; extern void kpc_off_cpu_internal(thread_t thread); extern void kpc_off_cpu_update(void); static inline void kpc_off_cpu(thread_t thread) { if (__improbable(kpc_off_cpu_active)) { kpc_off_cpu_internal(thread); } } #endif /* defined(MACH_KERNEL_PRIVATE) */ /* acquire/release the counters used by the Power Manager */ extern int kpc_force_all_ctrs( task_t task, int val ); extern int kpc_get_force_all_ctrs( void ); /* arch-specific routine for acquire/release the counters used by the Power Manager */ extern int kpc_force_all_ctrs_arch( task_t task, int val ); extern int kpc_set_sw_inc( uint32_t mask ); /* disable/enable whitelist of allowed events */ extern int kpc_get_whitelist_disabled( void ); extern int kpc_disable_whitelist( int val ); /* * Register the Power Manager as a PMCs user. * * This is a deprecated function used by old Power Managers, new Power Managers * should use the @em kpc_reserve_pm_counters() function. This function actually * calls @em kpc_reserve_pm_counters() with the following arguments: * - handler = handler * - pmc_mask = 0x83 * - custom_config = TRUE * * See @em kpc_reserve_pm_counters() for more details about the return value. */ extern boolean_t kpc_register_pm_handler(void (*handler)(boolean_t)); /* * Register the Power Manager as a PMCs user. * * @param handler * Notification callback to use when PMCs are acquired/released by a task. * Power management must acknowledge the change using kpc_pm_acknowledge. * * @param pmc_mask * Bitmask of the configurable PMCs used by the Power Manager. The number of bits * set must less or equal than the number of configurable counters * available on the SoC. * * @param custom_config * If custom_config=TRUE, the legacy sharing mode is enabled, otherwise the * Modern Sharing mode is enabled. These modes are explained in more details in * the kperf documentation. * * @return * FALSE if a task has acquired all the PMCs, otherwise TRUE and the Power * Manager can start using the reserved PMCs. */ extern boolean_t kpc_reserve_pm_counters(uint64_t pmc_mask, kpc_pm_handler_t handler, boolean_t custom_config); /* * Unregister the Power Manager as a PMCs user, and release the previously * reserved counters. */ extern void kpc_release_pm_counters(void); /* * Acknowledge the callback that PMCs are available to power management. * * @param available_to_pm Whether the counters were made available to power * management in the callback. Pass in whatever was passed into the handler * function. After this point, power management is able to use POWER_CLASS * counters. */ extern void kpc_pm_acknowledge(boolean_t available_to_pm); /* * Is the PMU used by both the power manager and userspace? * * This is true when the power manager has been registered. It disables certain * counter configurations (like RAWPMU) that are incompatible with sharing * counters. */ extern boolean_t kpc_multiple_clients(void); /* * Is kpc controlling the fixed counters? * * This returns false when the power manager has requested custom configuration * control. */ extern boolean_t kpc_controls_fixed_counters(void); /* * Is kpc controlling a specific PMC ? */ extern boolean_t kpc_controls_counter(uint32_t ctr); extern void kpc_idle(void); extern void kpc_idle_exit(void); /* * KPC PRIVATE */ extern uint32_t kpc_actionid[KPC_MAX_COUNTERS]; /* handler for mp operations */ struct kpc_config_remote { uint32_t classes; kpc_config_t *configv; uint64_t pmc_mask; }; /* handler for mp operations */ struct kpc_running_remote { uint32_t classes; /* classes to run */ uint64_t cfg_target_mask; /* configurable counters selected */ uint64_t cfg_state_mask; /* configurable counters new state */ }; /* handler for mp operations */ struct kpc_get_counters_remote { uint32_t classes; uint32_t nb_counters; uint32_t buf_stride; uint64_t *buf; }; int kpc_get_all_cpus_counters(uint32_t classes, int *curcpu, uint64_t *buf); int kpc_get_curcpu_counters(uint32_t classes, int *curcpu, uint64_t *buf); int kpc_get_fixed_counters(uint64_t *counterv); int kpc_get_configurable_counters(uint64_t *counterv, uint64_t pmc_mask); boolean_t kpc_is_running_fixed(void); boolean_t kpc_is_running_configurable(uint64_t pmc_mask); uint32_t kpc_fixed_count(void); uint32_t kpc_configurable_count(void); uint32_t kpc_fixed_config_count(void); uint32_t kpc_configurable_config_count(uint64_t pmc_mask); uint32_t kpc_rawpmu_config_count(void); int kpc_get_fixed_config(kpc_config_t *configv); int kpc_get_configurable_config(kpc_config_t *configv, uint64_t pmc_mask); int kpc_get_rawpmu_config(kpc_config_t *configv); uint64_t kpc_fixed_max(void); uint64_t kpc_configurable_max(void); int kpc_set_config_arch(struct kpc_config_remote *mp_config); int kpc_set_period_arch(struct kpc_config_remote *mp_config); __options_decl(kperf_kpc_flags_t, uint16_t, { KPC_KERNEL_PC = 0x01, // the PC is a kernel address KPC_KERNEL_COUNTING = 0x02, // the counter counts while running in the kernel KPC_USER_COUNTING = 0x04, // the counter counts while running in user space KPC_CAPTURED_PC = 0x08, // the PC was captured by hardware }); void kpc_sample_kperf(uint32_t actionid, uint32_t counter, uint64_t config, uint64_t count, uintptr_t pc, kperf_kpc_flags_t flags); int kpc_set_running_arch(struct kpc_running_remote *mp_config); /* * Helpers */ /* count the number of bits set */ extern uint8_t kpc_popcount(uint64_t value); /* for a set of classes, retrieve the configurable PMCs mask */ extern uint64_t kpc_get_configurable_pmc_mask(uint32_t classes); /* Interface for kexts to publish a kpc interface */ struct kpc_driver { uint32_t (*get_classes)(void); uint32_t (*get_running)(void); int (*set_running)(uint32_t classes); int (*get_cpu_counters)(boolean_t all_cpus, uint32_t classes, int *curcpu, uint64_t *buf); int (*get_curthread_counters)(uint32_t *inoutcount, uint64_t *buf); uint32_t (*get_counter_count)(uint32_t classes); uint32_t (*get_config_count)(uint32_t classes); int (*get_config)(uint32_t classes, kpc_config_t *current_config); int (*set_config)(uint32_t classes, kpc_config_t *new_config); int (*get_period)(uint32_t classes, uint64_t *period); int (*set_period)(uint32_t classes, uint64_t *period); }; __END_DECLS #endif /* !definde(KERN_KPC_H) */ |