1/* 2 * Copyright (c) 2009 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#ifndef _MACH_PMC_H_ 25#define _MACH_PMC_H_ 26 27#ifdef __cplusplus 28extern "C" { 29#endif 30 31#include <stdint.h> 32#include <kern/queue.h> 33#include <mach/boolean.h> 34#include <mach/mach_time.h> 35#include <mach/mach_types.h> 36 37#include <libkern/version.h> 38 39/**************************************************************************** 40 * The four main object types 41 * 42 * 1. Performance monitors (perf_monitor_t) - represent the hardware that 43 * encapsulates a set of performance counters 44 * 2. Performance Counters (pmc_t) - represents each individual counter 45 * 3. Performance Counter Configs (pmc_config_t) - represents the settings 46 * applied to a performance counter (e.g., what to count) 47 * 4. Performance Counter Reservations (pmc_reservation_t) - represents a config along 48 * with it's saved counter value, and the context underwhich it will count. 49 * 50 ****************************************************************************/ 51 52/* 53 * The following objects are in-kernel stand-ins for objects that will be implemented 54 * in the driver kexts. They are generally instances of C++ objects. We make opaque 55 * handles for each distinct type for a little bit of type safety when used from the 56 * kernel layer. These objects are not to be introspected by the kernel at any time, 57 * only used as arguments in the registered driver methods. 58 */ 59 60// IOPerformanceMonitor instances 61typedef void * perf_monitor_object_t; 62 63// IOPerformanceCounter instances 64typedef void * pmc_object_t; 65 66// IOPerformanceCounterConfig instances 67typedef void * pmc_config_object_t; 68 69// END Kext-implemented objects 70 71// Forward declations 72struct pmc_reservation; 73typedef struct pmc_reservation *pmc_reservation_t; 74 75struct pmc_config; 76typedef struct pmc_config *pmc_config_t; 77 78/**************************************************************************** 79 * Method types for performance monitor driver registration 80 * 81 * Driver registration happens with no intervention from the driver writers - 82 * it is handled automatically by the IOProfileFamily kext. Registration 83 * happens whenever any IOPerformanceMonitor subclass attaches to the registry. 84 * Failure to successfully register with the kernel will prevent successful attachment 85 * to the IORegistry (this way only usable PMCs and Perf Monitors will be shown.) 86 ****************************************************************************/ 87 88typedef kern_return_t (*perfmon_get_accessible_cores_method_t)(pmc_object_t pmc, uint32_t **cores, size_t *coreCt); 89 90/*!typedef 91 * @abstract A pointer to a method that enables a set of counters. 92 * @discussion Implementations of this method type must be safe to call at interrupt context. 93 * @param pmcs An array of pmc_object_t instances (non-NULL). 94 * @param pmcCount The number of elements in the @pmcs array. 95 * @result KERN_SUCCESS upon successful global enable of the given counters (may return IOKit error codes). 96 */ 97typedef kern_return_t (*perfmon_enable_counters_method_t)(perf_monitor_object_t pm, pmc_object_t *pmcs, uint32_t pmcCount); 98 99/*!typedef 100 * @abstract A pointer to a method that disables a set of counters. 101 * @discussion Implementations of this method type must be safe to call at interrupt context. 102 * See <link>perfmon_enable_counters_method_t</link> 103 * @result See <link>perfmon_enable_counters_method_t</link> 104 */ 105typedef kern_return_t (*perfmon_disable_counters_method_t)(perf_monitor_object_t pm, pmc_object_t *pmcs, uint32_t pmcCount); 106 107typedef void (*perfmon_on_idle_method_t)(perf_monitor_object_t pm); 108typedef void (*perfmon_on_idle_exit_method_t)(perf_monitor_object_t pm); 109 110#define MACH_PERFMON_METHODS_VERSION 1 111 112#define PERFMON_FLAG_SUPPORTS_CONTEXT_SWITCHING 0x1 113#define PERFMON_FLAG_REQUIRES_IDLE_NOTIFICATIONS 0x2 114#define PERFMON_FLAG_ALWAYS_ACTIVE 0x4 115 116/*!struct perf_monitor_methods 117 * @abstract A set of method pointers to be used when interacting with a performance monitor object 118 * @discussion This structure is the set of driver-implemented callback methods to be used when 119 * interacting with a new performance monitor from the kernel. 120 */ 121typedef struct perf_monitor_methods { 122 uint32_t perf_monitor_methods_version; // Always set to MACH_PERFMON_METHODS_VERSION when writing driver kexts 123 124 uint32_t flags; 125 126 perfmon_get_accessible_cores_method_t accessible_cores; 127 128 perfmon_enable_counters_method_t enable_counters; 129 perfmon_disable_counters_method_t disable_counters; 130 131 perfmon_on_idle_method_t on_idle; 132 perfmon_on_idle_exit_method_t on_idle_exit; 133} perf_monitor_methods_t; 134 135/**************************************************************************** 136 * Method types for performance counter registration 137 * 138 * Registration of individual Performance Counters happens after the 139 * encapsulating Performance Monitor has been registered. This, too, happens 140 * with no intervention of driver-writers. It happens automatically whenever 141 * any IOPerformanceCounter subclass attaches to IORegistry. Failure to register 142 * with the kernel will prevent the IOPerformanceCounter instance from attaching 143 * to IORegistry. 144 ****************************************************************************/ 145 146/*!typedef 147 * @abstract A pointer to a method that creates a configuration object for a counter 148 * @discussion Configuration objects create and hold the hardware representation for a set of driver-defined key-value pairs. 149 * Corresponds to IOPerformanceCounter::createConfiguration() method. 150 * @param pmc A valid pmc object 151 * @result NULL on failure, or a pmc_config_t on success. 152 */ 153typedef pmc_config_object_t (*pmc_create_config_method_t)(pmc_object_t pmc); 154 155/*!typedef 156 * @abstract A pointer to a method to free a configuration object for a pmc 157 * @discussion Method should free a pmc config object created with a pmc_create_config_method_t above 158 * @param pmc The pmc object used to create the config 159 * @param config The config object to release 160 */ 161typedef void (*pmc_free_config_method_t)(pmc_object_t pmc, pmc_config_object_t config); 162 163/*!typedef 164 * @abstract A pointer to a method to set a key-value pair on a config object. 165 * @discussion Configuration objects take key-value pairs for setting various bits in the pmc configs 166 * Corresponds to IOPerformanceCounterConfiguration::setValueForId() method. 167 * @param config Pointer to config object. 168 * @param id 8-bit integer ID (determined by the driver). 169 * @param value 64-bit integer value (interpretted by the driver). 170 * @result KERN_SUCCESS on success, KERN_FAILURE on bad value, KERN_INVALID_ARGUMENT on bad id 171 */ 172typedef kern_return_t (*pmc_config_set_value_method_t)(pmc_config_object_t config, uint8_t id, uint64_t value); 173 174/*!typedef 175 * @abstract A pointer to a method that will be called when a Performance Counter causes a PMI interrupt 176 * @discussion Implementations of this method type must be safe to call at interrupt context. 177 * @param target The pmc_reservation_t that caused the interrupt 178 * @param refCon Any value as defined by the end-user who called <link>pmc_config_set_interrupt_threshold</link> 179 */ 180typedef void (*pmc_interrupt_method_t)(void *target, void *refCon); 181 182/*!typedef 183 * @abstract A pointer to a method that will set the counter PMI threshold. 184 * @param config A configuration object 185 * @param threshold The number of events after which to cause an interrupt 186 * callback. 187 */ 188typedef kern_return_t (*pmc_config_set_interrupt_threshold_method_t)(pmc_config_object_t config, uint64_t threshold); 189 190/*!typedef 191 * @abstract A pointer to a method that will set the method to be called when the counter threshold is reached. 192 * @param config A configuration object. 193 * @param target A reference pointer used as the first argument to the callback method. 194 * @param method A pointer to the method to be called. 195 * @param refCon A reference pointer to be used as the second argument to the callback method (may be NULL). 196 */ 197typedef kern_return_t (*pmc_config_set_interrupt_threshold_handler_method_t)(pmc_config_object_t config, void *target, pmc_interrupt_method_t method, void *refCon); 198 199/*!typedef 200 * @abstract A pointer to a method that will configure a pmc's control registers according to the given configuration object. 201 * @discussion Implementations of this method type must be safe to call at interrupt context. 202 * @param pmc The pmc reference object. 203 * @param config A configuration object. 204 */ 205typedef kern_return_t (*pmc_set_config_method_t)(pmc_object_t pmc, pmc_config_object_t config); 206 207/*!typedef 208 * @abstract A pointer to a method that returns the Performance Monitor Object for a counter 209 * @discussion A pointer to a method that returns the Performance Monitor Object for a counter. 210 * Implementations of this method type must be safe to call at interrupt context. 211 * Corresponds to IOPerformanceCounter::getMonitor() method. 212 * @param pmc A valid pmc object 213 * @result NULL on failure, or a perf_monitor_object_t on success. 214 */ 215typedef perf_monitor_object_t (*pmc_get_monitor_method_t)(pmc_object_t pmc); 216 217/*!typedef 218 * @abstract A pointer to a method that returns the registered name of the PMC. 219 * @discussion A pointer to a method that returns the registered name of the PMC. 220 * Corresponds to IOPerformanceCounter::getRegisteredName() method. 221 * 222 * NOTE: Driver authors must not allocate or copy the string during this method: 223 * it may be called from interrupt context or with spin locks held. 224 * 225 * @param pmc A valid pmc object. 226 * @result NULL on failure, or a pointer to the registered name of the pmc. 227 */ 228typedef const char *(*pmc_get_name_method_t)(pmc_object_t pmc); 229 230/*!typedef 231 * @abstract A pointer to a method that returns if a pmc is accessible from a given logical core. 232 * @discussion A pointer to a method that returns if a pmc is accessible from a given logical core. 233 * Implementations of this method type must be safe to call at interrupt context. 234 * @param pmc A valid pmc object. 235 * @param core The logical core number. 236 * @result TRUE if the pmc can be read in the execution context of the given logical core, FALSE otherwise. 237 */ 238typedef boolean_t (*pmc_is_accessible_from_logical_core_method_t)(pmc_object_t pmc, uint32_t core); 239 240/*!typedef 241 * @abstract A pointer to a method that returns an array of the logical cores from which a PMC can be accessed. 242 * @discussion A pointer to a method that returns an array of the logical cores from which a PMC can be accessed. 243 * Resulting array of cores should not be released by xnu. 244 * Implementations of this method type must be safe to call at interrupt context. 245 * @param pmc A valid pmc object 246 * @param cores A value-returned array of logical cores that can access the given PMC. 247 * @param coreCt A value-return count of the number of entries in the @cores array. 248 * @result KERN_SUCCESS on success, KERN_FAILURE otherwise. 249 */ 250typedef kern_return_t (*pmc_get_accessible_cores_method_t)(pmc_object_t pmc, uint32_t **cores, size_t *coreCt); 251 252/*!typedef 253 * @abstract A pointer to a method that attempts to read the count from the given counter hardware. 254 * @discussion Implementations of this method type must be safe to call from interrupt context. * @param pmc The counter from which to read 255 * @param value Storage for the counter's hardware value. 256 */ 257typedef kern_return_t (*pmc_get_count_method_t)(pmc_object_t pmc, uint64_t *value); 258 259/*!typedef 260 * @abstract A pointer to a method that attempts to write the count to the given counter hardware. 261 * @discussion Implementations of this method type must be safe to call from interrupt context. 262 * @param pmc The counter to which to write. 263 * @param value The value to write to the hardware. 264 */ 265typedef kern_return_t (*pmc_set_count_method_t)(pmc_object_t pmc, uint64_t value); 266 267 268/*!typedef 269 * @abstract A pointer to a method that disables the counter hardware for a given PMC. 270 * @discussion A pointer to a method that disables the counter hardware for 271 * a given PMC. 272 * Implementations of this method type must be safe to call at interrupt context. 273 * @param pmc A valid pmc object. 274 * @result KERN_SUCCESS on successful disable 275 */ 276typedef kern_return_t (*pmc_disable_method_t)(pmc_object_t pmc); 277 278/*!typedef 279 * @abstract A pointer to a method that enables the counter hardware for a given PMC. 280 * @discussion A pointer to a method that enables the counter hardware for a given PMC. 281 * Implementations of this method type must be safe to call at interrupt context. 282 * @param pmc A valid pmc object. 283 * @result KERN_SUCCESS on successful enable 284 */ 285typedef kern_return_t (*pmc_enable_method_t)(pmc_object_t pmc); 286 287typedef kern_return_t (*pmc_open_method_t)(pmc_object_t pmc, void *object); 288typedef kern_return_t (*pmc_close_method_t)(pmc_object_t pmc, void *object); 289 290#define MACH_PMC_METHODS_VERSION 0 291 292/*! 293 * @struct pmc_methods 294 * @abstract Performance Counter Registration methods. 295 * @discussion This structure represents a set of driver-implemented methods to be used by the kernel 296 * when interacting with the associated performance counter. Since a Performance Monitor may 297 * implement any number of distinct types of Performance Counters, each counter registers with 298 * its own set of callback methods. 299 */ 300typedef struct pmc_methods { 301 uint32_t pmc_methods_version; // Always set to MACH_PMC_METHODS_VERSION in your driver. 302 303 // All methods are required. 304 pmc_create_config_method_t create_config; 305 pmc_free_config_method_t free_config; 306 pmc_config_set_value_method_t config_set_value; 307 pmc_config_set_interrupt_threshold_method_t config_set_threshold; 308 pmc_config_set_interrupt_threshold_handler_method_t config_set_handler; 309 pmc_set_config_method_t set_config; 310 311 pmc_get_monitor_method_t get_monitor; 312 pmc_get_name_method_t get_name; 313 pmc_is_accessible_from_logical_core_method_t accessible_from_core; 314 pmc_get_accessible_cores_method_t accessible_cores; 315 pmc_get_count_method_t get_count; 316 pmc_set_count_method_t set_count; 317 pmc_disable_method_t disable; 318 pmc_enable_method_t enable; 319 pmc_open_method_t open; 320 pmc_close_method_t close; 321} pmc_methods_t; 322 323/* 324 * Kext interface Methods 325 * 326 * These methods would be exported to apple-internal kexts, but not to 3rd-party kexts, and 327 * definitely not to user space. 328 * 329 * All Performance Monitor and Performance Counter registration (accomplished via the following methods) 330 * is handled automatically via IOProfileFamily's base classes. However, we'd need to export these 331 * methods to apple-private KPI so that IOProfileFamily can call these methods when new objects attach 332 * to the IORegistry. 333 * 334 */ 335 336/*!fn 337 * @abstract Registers a new performance monitor driver and its associated pointers. 338 * @discussion Kexts that implement performance monitor drivers will call this method with a 339 * filled-in perf_monitor_methods_t structure (with version set to MACH_PERFMON_METHODS_VERSION). 340 * The PMC interface will then register the new driver internally. 341 * @param monitor A handle to the performance monitor driver instance you are registering. Must not be NULL. 342 * @param methods A filled-in perf_monitor_methods_t structure with version set to MACH_PERFMON_METHODS_VERSION. 343 * @result KERN_SUCCESS if the new driver was successfully registered, KERN_INVALID_VALUE if the 344 * version of the passed-in perf_monitor_methods_t structure does not match that which is expected, 345 * KERN_RESOURCE_SHORTAGE if the kernel lacks the resources to register another performance monitor 346 * driver, KERN_INVALID_ARGUMENT if one or both of the arguments is null 347 */ 348 349/* Prevent older AppleProfileFamily kexts from loading on newer kernels. 350 * Alas, C doesn't necessarily have a cleaner way to do the version number concatenation 351 */ 352#define PERF_REG_NAME1(a, b) a ## b 353#define PERF_REG_NAME(a, b) PERF_REG_NAME1(a, b) 354#define perf_monitor_register PERF_REG_NAME(perf_monitor_register_, 12/*VERSION_MAJOR*/) 355 356kern_return_t perf_monitor_register(perf_monitor_object_t monitor, perf_monitor_methods_t *methods); 357 358/*!fn 359 * @abstract Unregisters a performance monitor driver and frees space associated with its pointers. 360 * @discussion Kexts that implement performance monitor drivers will call this method just before they unload 361 * to cause the performance monitor they implement to be removed from the kernel's PMC system. 362 * @param monitor A handle to a performance monitor driver instance that was previously registered with <link>perf_monitor_register</link> 363 * @result KERN_SUCCESS if the new driver was successfully unregistered, KERN_INVALID_VALUE if the 364 * passed-in perf_monitor_object_t does not match any registered performance monitor, KERN_INVALID_ARGUMENT if 365 * the argument is null, KERN_FAILURE if the performance monitor is currently in use. 366 */ 367kern_return_t perf_monitor_unregister(perf_monitor_object_t monitor); 368 369/*!fn 370 * @abstract Register a new Performance Counter, and attach it to the given Performance Monitor 371 * @discussion This method takes a Performance Monitor driver instance that was previously registered 372 * with <link>perf_monitor_register</link>, and attaches an instance of a Performance Counter 373 * that will be accessed with the given set of pmc methods. 374 * @param monitor A handle to a Performance Monitor that was previously registered. 375 * @param pmc A handle to the Performance Counter instance to be attached to the monitor object 376 * @param methods A filled-in pmc_methods_t structure with version set to MACH_PMC_METHODS_VERSION 377 * @param object an Object to be used during the open() and close() methods. Must be a subclass of IOService, cannot be NULL. 378 * @result KERN_SUCCESS if the new counter was successfully registered and attached, KERN_INVALID_VALUE if the 379 * version of the passed-in pmc_methods_t structure does not match that which is expected, 380 * KERN_RESOURCE_SHORTAGE if the kernel lacks the resources to register another performance counter 381 * instance, KERN_INVALID_ARGUMENT if any of the arguments is null 382 */ 383kern_return_t pmc_register(perf_monitor_object_t monitor, pmc_object_t pmc, 384 pmc_methods_t *methods, void *object); 385 386/*!fn 387 * @abstract Unregisters a Performance Counter 388 * @discussion Does the reverse of <link>pmc_register</link>. 389 * @param monitor The registered Performance Monitor from which to remove a pmc. 390 * @param pmc The Performance Counter to unregister. 391 * @result KERN_SUCCESS if the counter was successfully unregistered, KERN_INVALID_VALUE if the 392 * passed-in pmc_object_t does not match any registered performance counter, KERN_INVALID_ARGUMENT if 393 * any argument is null, KERN_FAILURE if the performance counter is currently in use. 394 */ 395kern_return_t pmc_unregister(perf_monitor_object_t monitor, pmc_object_t pmc); 396 397/* 398 * Here begins the interface in-kernel and in-kext users will use to interact with PMCs and 399 * Performance Monitors. 400 * 401 * Basic usage is as follows: find your target counter, create a config for it, setup the config, 402 * reserve the counter using that config in a given execution context (system, or 1 task, or 1 thread), 403 * start the counter via the reservation object, stop the counter, and read the counter value similarly from the 404 * reservation object. When done, release the reservation object. 405 */ 406 407/*!struct perf_monitor 408 * @abstract In-kernel object to track a driver-implemented performance monitor. 409 */ 410typedef struct perf_monitor { 411 /* 412 * A reference-pointer used as the first argument to all callback methods 413 * (to seamlessly work with C++ objects). This is the same value that was 414 * used in the perf_monitor_register() method. 415 */ 416 perf_monitor_object_t object; 417 418 // Copy of the pointers used to interact with the above instance 419 perf_monitor_methods_t methods; 420 421 // reference counted 422 uint32_t useCount; 423 424 uint32_t reservedCounters; 425 426 // A value of -1 here indicates independence from a particular core 427 int cpu; 428 429 // links to other perf monitors 430 queue_chain_t link; 431 queue_chain_t cpu_link; 432}*perf_monitor_t; 433 434/*!struct pmc 435 * @abstract In-kernel object to track an individual driver-implemented performance counter 436 */ 437typedef struct pmc { 438 /* 439 * A reference-pointer used as the first argument to all callback methods 440 * (to seamlessly work with C++ objects). This is the same value that was 441 * used in the pmc_register() method. 442 */ 443 pmc_object_t object; 444 445 /* Copy of the pointers used to interact with the above instance */ 446 pmc_methods_t methods; 447 448 /* Object to be used during open/close methods */ 449 void *open_object; 450 451 /* reference counted */ 452 uint32_t useCount; 453 454 /* link to parent */ 455 perf_monitor_t monitor; 456 457 /* link to other PMCs */ 458 queue_chain_t link; 459}*pmc_t; 460 461// Scope flags (highest order bits) 462#define PMC_FLAG_SCOPE_SYSTEM 0x80000000U 463#define PMC_FLAG_SCOPE_TASK 0x40000000U 464#define PMC_FLAG_SCOPE_THREAD 0x20000000U 465#define PMC_SCOPE_MASK 0xE0000000U 466 467#define PMC_FLAG_IS_SYSTEM_SCOPE(x) \ 468 ((x & PMC_FLAG_SCOPE_SYSTEM) == PMC_FLAG_SCOPE_SYSTEM) 469 470#define PMC_FLAG_IS_TASK_SCOPE(x) \ 471 ((x & PMC_FLAG_SCOPE_TASK) == PMC_FLAG_SCOPE_TASK) 472 473#define PMC_FLAG_IS_THREAD_SCOPE(x) \ 474 ((x & PMC_FLAG_SCOPE_THREAD) == PMC_FLAG_SCOPE_THREAD) 475 476#define PMC_FLAG_SCOPE(x) (x & PMC_SCOPE_MASK) 477 478/* 479 * Reservation state 480 * 481 * The state of a reservation is actually a 3-tuple of the current state, an active context count, 482 * and a set of modifier flags. To avoid using locks, these are combined into a single uint32_t 483 * that can be modified with OSCompareAndSwap. 484 * 485 */ 486 487typedef uint32_t pmc_state_t; 488 489#define PMC_STATE_STATE_INVALID 0x00000000U 490#define PMC_STATE_STATE_STOP 0x10000000U 491#define PMC_STATE_STATE_CAN_RUN 0x20000000U 492#define PMC_STATE_STATE_LOAD 0x30000000U 493#define PMC_STATE_STATE_RUN 0x40000000U 494#define PMC_STATE_STATE_STORE 0x50000000U 495#define PMC_STATE_STATE_INTERRUPT 0x60000000U 496#define PMC_STATE_STATE_DEALLOC 0x70000000U 497 498#define PMC_STATE_STATE_MASK 0xF0000000U 499 500#define PMC_STATE_STATE(x) ((x) & PMC_STATE_STATE_MASK) 501#define PMC_STATE_STATE_SET(x, state) (((x) & ~(PMC_STATE_STATE_MASK)) | state) 502 503#define PMC_STATE_FLAGS_STOPPING 0x08000000U 504#define PMC_STATE_FLAGS_DEALLOCING 0x04000000U 505#define PMC_STATE_FLAGS_INTERRUPTING 0x02000000U 506 507#define PMC_STATE_FLAGS_MASK 0x0F000000U 508 509#define PMC_STATE_FLAGS(x) ((x) & PMC_STATE_FLAGS_MASK) 510#define PMC_STATE_FLAGS_MODIFY(x, set, clear) (((x) & ~(clear)) | set) 511 512#define PMC_STATE_CONTEXT_COUNT_MASK 0x0000FFFFU 513 514#define PMC_STATE_CONTEXT_COUNT(x) ((x) & PMC_STATE_CONTEXT_COUNT_MASK) 515#define PMC_STATE_CONTEXT_COUNT_MODIFY(x, mod) (((PMC_STATE_CONTEXT_COUNT(x) + (mod)) < PMC_STATE_CONTEXT_COUNT_MASK) ? (x) + (mod) : PMC_STATE_CONTEXT_COUNT_MASK) 516 517#define PMC_STATE(state, context_count, flags) (PMC_STATE_STATE(state) | PMC_STATE_FLAGS(flags) | PMC_STATE_CONTEXT_COUNT(context_count)) 518#define PMC_STATE_MODIFY(x, context_count_mod, flags_set, flags_clear) (PMC_STATE_FLAGS_MODIFY(PMC_STATE_CONTEXT_COUNT_MODIFY(x, context_count_mod), flags_set, flags_clear)) 519#define PMC_STATE_MOVE(x, state, context_count_mod, flags_set, flags_clear) (PMC_STATE_STATE_SET(PMC_STATE_MODIFY(x, context_count_mod, flags_set, flags_clear), state)) 520 521#define PMC_STATE_INVALID PMC_STATE(PMC_STATE_STATE_INVALID, 0, 0) 522 523/*!struct pmc_reservation 524 * @abstract In-kernel object to track an individual reservation 525 */ 526struct pmc_reservation { 527 pmc_t pmc; // Pointer to in-kernel pmc which is reserved 528 pmc_config_t config; // counter configuration 529 530 // stored counter value 531 uint64_t value; 532 533 // TODO: Add mach-port (user-export object?) 534 535 volatile uint32_t flags __attribute__((aligned(4))); 536 volatile pmc_state_t state __attribute__((aligned(4))); 537 volatile uint32_t active_last_context_in __attribute__((aligned(4))); 538 539 union { 540 task_t task; // not retained 541 thread_t thread; // not retained 542 }; 543 544 queue_chain_t link; 545}; 546 547// END Kernel-objects 548 549 550// Methods exported to kernel (and kext) consumers 551 552/*!fn 553 * @abstract Creates a new configuration object for the given pmc. 554 * @discussion This method is not interrupt safe. 555 * @param pmc The Perf Counter for which to create a configuration. 556 * @param config A value-return configuration object. 557 */ 558kern_return_t pmc_create_config(pmc_t pmc, pmc_config_t *config); 559 560/*!fn 561 * @abstract Releases a configuration object for the given pmc. 562 * @discussion This method is not interrupt safe. 563 * @param pmc The Perf Counter for which to release a configuration. 564 * @param config A configuration object to be released. 565 */ 566void pmc_free_config(pmc_t pmc, pmc_config_t config); 567 568/*!fn 569 * @abstract Setup the configuration 570 * @discussion Configurations for counter are architecture-neutral key-value pairs (8bit key, 64bit value). Meanings of the keys and values are defined 571 * by the driver-writer and are listed in XML form available for interrogation via the CoreProfile framework. This method is not interrupt safe. 572 * @result KERN_SUCCESS on success. 573 */ 574kern_return_t pmc_config_set_value(pmc_t pmc, pmc_config_t config, uint8_t id, uint64_t value); 575 576/*!fn 577 * @abstract Interrupt Threshold Setup 578 * @discussion In order to configure a PMC to use PMI (cause an interrupt after so-many events occur), use this method, and provide a function to be 579 * called after the interrupt occurs, along with a reference context. PMC Threshold handler methods will have the pmc that generated the interrupt as 580 * the first argument when the interrupt handler is invoked, and the given @refCon (which may be NULL) as the second. This method is not interrupt safe. 581 */ 582kern_return_t pmc_config_set_interrupt_threshold(pmc_t pmc, pmc_config_t config, uint64_t threshold, pmc_interrupt_method_t method, void *refCon); 583 584/*!fn 585 * @abstract Returns an allocated list of all pmc_t's known to the kernel. 586 * @discussion Callers should free the resultant list via <link>pmc_free_pmc_list</link>. This method is not interrupt safe. 587 * @param pmcs Storage for the resultant pmc_t array pointer. 588 * @param pmcCount Storage for the resultant count of pmc_t's. 589 */ 590kern_return_t pmc_get_pmc_list(pmc_t **pmcs, size_t *pmcCount); 591 592/*!fn 593 * @abstract Free a previously allocated list of pmcs. 594 * @discussion This method is not interrupt safe. 595 * @param pmcs PMC list to free. 596 * @param pmcCount Number of pmc_t's in list. 597 */ 598void pmc_free_pmc_list(pmc_t *pmcs, size_t pmcCount); 599 600/*!fn 601 * @abstract Finds pmcs by partial string matching. 602 * @discussion This method returns a list of pmcs (similar to <link>pmc_get_pmc_list</link>) whose names match the given string up to it's length. 603 * For example, searching for "ia32" would return pmcs "ia32gp0" and "ia32gp1". Results should be released by the caller using <link>pmc_free_pmc_list</link> 604 * @param name Partial string to search for. 605 * @param pmcs Storage for the resultant pmc_t array pointer. 606 * @param pmcCount Storage for the resultant count of pmc_t's. 607 */ 608kern_return_t pmc_find_by_name(const char *name, pmc_t **pmcs, size_t *pmcCount); 609 610/*!fn 611 * @abstract Returns a pointer to the human-readable name of the given pmc. 612 * @discussion The returned pointer is not a copy, and does not need to be freed. This method is interrupt safe. 613 * @param pmc The PMC whose name should be returned. 614 */ 615const char *pmc_get_name(pmc_t pmc); 616 617/*!fn 618 * @abstract Returns a list of logical cores from which the given pmc can be read from or written to. 619 * @discussion This method can return a NULL list with count of 0 -- this indicates any core can read the given pmc. This method does not allocate the list, 620 * therefore callers should take care not to mutate or free the resultant list. This method is interrupt safe. 621 * @param pmc The PMC for which to return the cores that can read/write it. 622 * @param logicalCores Storage for the pointer to the list. 623 * @param logicalCoreCt Value-return number of elements in the returned list. 0 indicates all cores can read/write the given pmc. 624 */ 625kern_return_t pmc_get_accessible_core_list(pmc_t pmc, uint32_t **logicalCores, size_t *logicalCoreCt); 626 627/* 628 * BEGIN PMC Reservations 629 * 630 * These are how you reserve a PMC, start and stop it counting, and read and write 631 * its value. 632 */ 633 634/*!fn 635 * @abstract Reserve a PMC for System-wide counting. 636 * @discussion This method will attempt to reserve the given pmc at system-scope. It will configure the given pmc to count the event indicated by the given 637 * configuration object. This method consumes the given configuration object if the return value is KERN_SUCCESS - any other return value indicates the caller 638 * should free the configuration object via <link>pmc_free_config</link>. This method is not interrupt safe. 639 * @param pmc The PMC to reserve. 640 * @param config The configuration object to use with the given pmc. 641 * @param reservation A value-return reservation object to be used in pmc_reservation_* methods. 642 * @result This method will return one of the following values: 643 * KERN_SUCCESS: The given pmc was successfully reserved in system-scope; the given config object has been consumed and should not be freed by the caller, 644 * KERN_FAILURE: The given pmc is already reserved in a conflicting scope, 645 * KERN_INVALID_ARGUMENT: All three arguments are required to be non-NULL, but at least one is NULL, 646 * KERN_RESOURCE_SHORTAGE: Could not allocate a new reservation object. 647 */ 648kern_return_t pmc_reserve(pmc_t pmc, pmc_config_t config, pmc_reservation_t *reservation); 649 650 651/*!fn 652 * @abstract Reserve a PMC for task-wide counting. 653 * @discussion This method will attempt to reserve the given pmc for task-wide counting. The resulting reservation will only count when the task is running 654 * on one of the logical cores that can read the given pmc. The semantics of this method are the same as <link>pmc_reserve</link> in all other respects. 655 * @param pmc The PMC to reserve 656 * @param config The configuration object to use. 657 * @param task The task for which to enable the counter. 658 * @param reservation A value-return reservation object. 659 * @result See <link>pmc_reserve</link> 660 */ 661kern_return_t pmc_reserve_task(pmc_t pmc, pmc_config_t config, task_t task, pmc_reservation_t *reservation); 662 663/*!fn 664 * @abstract Reserve a PMC for thread-wide counting. 665 * @discussion This method will attempt to reserve the given pmc for thread-wide counting. The resulting reservation will only count when the thread is 666 * running on one of the logical cores that can read the given pmc. The semantics of this method are the same as <link>pmc_reserve_task</link> in all other respects. 667 * @param pmc The PMC to reserve 668 * @param config The configuration object to use. 669 * @param thread The thread for which to enable the counter. 670 * @param reservation A value-return reservation object. 671 * @result See <link>pmc_reserve</link> 672 */ 673kern_return_t pmc_reserve_thread(pmc_t pmc, pmc_config_t config, thread_t thread, pmc_reservation_t *reservation); 674 675/*!fn 676 * @abstract Start counting 677 * @discussion This method instructs the given reservation to start counting as soon as possible. If the reservation is for a thread (or task) other than the 678 * current thread, or for a pmc that is not accessible from the current logical core, the reservation will start counting the next time the thread (or task) 679 * runs on a logical core than can access the pmc. This method is interrupt safe. If this method is called from outside of interrupt context, it may block. 680 * @param reservation The reservation to start counting 681 */ 682kern_return_t pmc_reservation_start(pmc_reservation_t reservation); 683 684/*!fn 685 * @abstract Stop counting 686 * @discussion This method instructs the given reservation to stop counting as soon as possible. If the reservation is for a thread (or task) other than the 687 * current thread, or for a pmc that is not accessible from the current logical core, the reservation will stop counting the next time the thread (or task) c 688 * eases to run on a logical core than can access the pmc. This method is interrupt safe. If called form outside of interrupt context, this method may block. 689 * @param reservation The reservation to stop counting 690 */ 691kern_return_t pmc_reservation_stop(pmc_reservation_t reservation); 692 693/*!fn 694 * @abstract Read the counter value 695 * @discussion This method will read the event count associated with the given reservation. If the pmc is currently on hardware, and the caller is currently ] 696 * executing in a context that both a) matches the reservation's context, and b) can access the reservation's pmc directly, the value will be read directly 697 * from the hardware. Otherwise, the value stored in the reservation is returned. This method is interrupt safe. If the caller is calling from outside of 698 * interrupt context, this method may block. 699 * @param reservation The reservation whose value to read. 700 * @param value Value-return event count 701 */ 702kern_return_t pmc_reservation_read(pmc_reservation_t reservation, uint64_t *value); 703 704/*!fn 705 * @abstract Write the counter value 706 * @discussion This method will write the event count associated with the given reservation. If the pmc is currently on hardware, and the caller is currently 707 * executing in a context that both a) matches the reservation's context, and b) can access the reservation's pmc directly, the value will be written directly 708 * to the hardware. Otherwise, the value stored in the reservation is overwritten. This method is interrupt safe. If the caller is calling from outside of 709 * interrupt context, this method may block. 710 * @param reservation The reservation to write. 711 * @param value The event count to write 712 */ 713kern_return_t pmc_reservation_write(pmc_reservation_t reservation, uint64_t value); 714 715/*!fn 716 * @abstract Free a reservation and all associated resources. 717 * @discussion This method will free the resources associated with the given reservation and release the associated PMC back to general availability. 718 * If the reservation is currently counting, it will be stopped prior to release. This method is not interrupt safe. 719 * @param reservation The reservation to free 720 */ 721kern_return_t pmc_reservation_free(pmc_reservation_t reservation); 722 723#if XNU_KERNEL_PRIVATE 724 725/*!fn 726 * @abstract Brings up all the necessary infrastructure required to use the pmc sub-system. 727 * @discussion For xnu-internal startup routines only. 728 */ 729void pmc_bootstrap(void); 730 731/*!fn 732 * @abstract Performs a pmc context switch. 733 * @discussion This method will save all PMCs reserved for oldThread (and the task associated with oldThread), as well as restore all PMCs reserved 734 * for newThread (and the task associated with newThread). This method is for xnu-internal context switching routines only. 735 */ 736boolean_t pmc_context_switch(thread_t oldThread, thread_t newThread); 737 738/*!fn 739 * @abstract Called on per-core idle. 740 * @discussion This method notifies registered performance monitors of impending cpu idle, and can be used to save counter state. 741 */ 742boolean_t pmc_idle(void); 743 744/*!fn 745 * @abstract Called on per-core wake from idle. 746 * @discussion This method notifies registered performance monitors of wake-up from the prior idle, and can be used to restore 747 * previously saved counter configuration. 748 */ 749boolean_t pmc_idle_exit(void); 750 751#if defined(THREAD_PMC_FLAG) 752/* Allow inclusion from outside of MACH_KERNEL_PRIVATE scope. */ 753 754/*!fn 755 * @abstract Returns true if thread has been marked for counting. 756 * @discussion Task-level reservations are propagated to child threads via thread_create_internal. Any mutation of task reservations forces a recalculate 757 * of t_chud (for the pmc flag) for all threads in that task. Consequently, we can simply check the current thread's flag against THREAD_PMC_FLAG. 758 */ 759static inline boolean_t pmc_thread_eligible(thread_t t) { 760 return (t != NULL) ? ((t->t_chud & THREAD_PMC_FLAG) ? TRUE : FALSE) : FALSE; 761} 762 763#endif /* THREAD_PMC_FLAG*/ 764 765#endif // XNU_KERNEL_PRIVATE 766 767#ifdef __cplusplus 768}; 769#endif 770 771#endif // _MACH_PMC_H_ 772 773