2 * Copyright (c) 2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include <kern/kalloc.h>
25 #include <kern/kern_types.h>
26 #include <kern/locks.h>
27 #include <kern/misc_protos.h>
28 #include <kern/task.h>
29 #include <kern/thread.h>
30 #include <kern/zalloc.h>
31 #include <machine/machine_cpu.h>
35 #include <libkern/OSAtomic.h>
37 #if defined(__i386__) || defined(__x86_64__)
43 /* various debug logging enable */
46 typedef uint8_t pmc_state_event_t
;
48 #define PMC_STATE_EVENT_START 0
49 #define PMC_STATE_EVENT_STOP 1
50 #define PMC_STATE_EVENT_FREE 2
51 #define PMC_STATE_EVENT_INTERRUPT 3
52 #define PMC_STATE_EVENT_END_OF_INTERRUPT 4
53 #define PMC_STATE_EVENT_CONTEXT_IN 5
54 #define PMC_STATE_EVENT_CONTEXT_OUT 6
55 #define PMC_STATE_EVENT_LOAD_FINISHED 7
56 #define PMC_STATE_EVENT_STORE_FINISHED 8
58 /* PMC spin timeouts */
59 #define PMC_SPIN_THRESHOLD 10 /* Number of spins to allow before checking mach_absolute_time() */
60 #define PMC_SPIN_TIMEOUT_US 10 /* Time in microseconds before the spin causes an assert */
62 uint64_t pmc_spin_timeout_count
= 0; /* Number of times where a PMC spin loop causes a timeout */
65 # include <pexpert/pexpert.h>
66 # define COUNTER_DEBUG(...) \
68 kprintf("[%s:%s][%u] ", __FILE__, __PRETTY_FUNCTION__, cpu_number()); \
69 kprintf(__VA_ARGS__); \
72 # define PRINT_PERF_MON(x) \
74 kprintf("perfmon: %p (obj: %p refCt: %u switchable: %u)\n", \
75 x, x->object, x->useCount, \
76 (x->methods.flags & PERFMON_FLAG_SUPPORTS_CONTEXT_SWITCHING) ? \
80 static const char const * pmc_state_state_name(pmc_state_t state
) {
81 switch (PMC_STATE_STATE(state
)) {
82 case PMC_STATE_STATE_INVALID
:
84 case PMC_STATE_STATE_STOP
:
86 case PMC_STATE_STATE_CAN_RUN
:
88 case PMC_STATE_STATE_LOAD
:
90 case PMC_STATE_STATE_RUN
:
92 case PMC_STATE_STATE_STORE
:
94 case PMC_STATE_STATE_INTERRUPT
:
96 case PMC_STATE_STATE_DEALLOC
:
103 static const char const * pmc_state_event_name(pmc_state_event_t event
) {
105 case PMC_STATE_EVENT_START
:
107 case PMC_STATE_EVENT_STOP
:
109 case PMC_STATE_EVENT_FREE
:
111 case PMC_STATE_EVENT_INTERRUPT
:
113 case PMC_STATE_EVENT_END_OF_INTERRUPT
:
114 return "END OF INTERRUPT";
115 case PMC_STATE_EVENT_CONTEXT_IN
:
117 case PMC_STATE_EVENT_CONTEXT_OUT
:
118 return "CONTEXT OUT";
119 case PMC_STATE_EVENT_LOAD_FINISHED
:
120 return "LOAD_FINISHED";
121 case PMC_STATE_EVENT_STORE_FINISHED
:
122 return "STORE_FINISHED";
128 # define PMC_STATE_FORMAT "<%s, %u, %s%s%s>"
129 # define PMC_STATE_ARGS(x) pmc_state_state_name(x), PMC_STATE_CONTEXT_COUNT(x), ((PMC_STATE_FLAGS(x) & PMC_STATE_FLAGS_INTERRUPTING) ? "I" : ""), \
130 ((PMC_STATE_FLAGS(x) & PMC_STATE_FLAGS_STOPPING) ? "S" : ""), ((PMC_STATE_FLAGS(x) & PMC_STATE_FLAGS_DEALLOCING) ? "D" : "")
132 # define COUNTER_DEBUG(...)
133 # define PRINT_PERF_MON(x)
134 # define PMC_STATE_FORMAT
135 # define PMC_STATE_ARGS(x)
139 * pmc_config is the data behind a pmc_config_t.
140 * @member object A pointer to an instance of IOPerformanceCounterConfiguration
141 * @member method A pointer to a method to call to handle PMI.
142 * @member interrupt_after_value Cause a PMI after the counter counts this many
144 * @member refCon Passed to the @method method as the refCon argument.
147 pmc_config_object_t object
;
148 volatile pmc_interrupt_method_t method
;
149 uint64_t interrupt_after_value
;
156 * Two allocation zones - Perf zone small and Perf zone big.
157 * Each zone has associated maximums, defined below.
158 * The small zone is the max of the smallest allocation objects (all sizes on
160 * perf_monitor_t - 48 bytes
161 * perf_monitor_methods_t - 28 bytes
162 * pmc_reservation_t - 48 bytes
163 * pmc_config_t - 32 bytes
164 * perf_small_zone unit size is (on K64) 48 bytes
165 * perf_small_zone max count must be max number of perf monitors, plus (max
166 * number of reservations * 2). The "*2" is because each reservation has a
167 * pmc_config_t within.
169 * Big zone is max of the larger allocation units
171 * pmc_methods_t - 116 bytes
172 * perf_big_zone unit size is (on K64) 144 bytes
173 * perf_big_zone max count is the max number of PMCs we support.
176 static zone_t perf_small_zone
= NULL
;
177 #define MAX_PERF_SMALLS (256 + 8196 + 8196)
178 #define PERF_SMALL_UNIT_SZ (MAX(MAX(sizeof(struct perf_monitor), \
179 sizeof(struct pmc_reservation)), sizeof(struct pmc_config)))
181 static zone_t perf_big_zone
= NULL
;
182 #define MAX_PERF_BIGS (1024)
183 #define PERF_BIG_UNIT_SZ (sizeof(struct pmc))
186 * Locks and Lock groups
188 static lck_grp_t
*pmc_lock_grp
= LCK_GRP_NULL
;
189 static lck_grp_attr_t
*pmc_lock_grp_attr
;
190 static lck_attr_t
*pmc_lock_attr
;
192 /* PMC tracking queue locks */
194 static lck_mtx_t cpu_monitor_queue_mutex
; /* protects per-cpu queues at initialisation time */
195 static lck_spin_t perf_monitor_queue_spin
; /* protects adding and removing from queue */
196 static lck_spin_t perf_counters_queue_spin
; /* protects adding and removing from queue */
198 /* Reservation tracking queues lock */
199 static lck_spin_t reservations_spin
;
204 * Keeps track of registered perf monitors and perf counters
207 static queue_head_t
**cpu_monitor_queues
= NULL
;
209 static queue_head_t
*perf_monitors_queue
= NULL
;
210 static volatile uint32_t perf_monitors_count
= 0U;
212 static queue_head_t
*perf_counters_queue
= NULL
;
213 static volatile uint32_t perf_counters_count
= 0U;
218 * Keeps track of all system, task, and thread-level reservations (both active and
221 * We track them all here (rather than in their respective task or thread only)
222 * so that we can inspect our tracking data directly (rather than peeking at
223 * every task and thread) to determine if/when a new reservation would
224 * constitute a conflict.
227 static queue_head_t
*system_reservations
= NULL
;
228 static volatile uint32_t system_reservation_count
= 0U;
230 static queue_head_t
*task_reservations
= NULL
;
231 static volatile uint32_t task_reservation_count
= 0U;
233 static queue_head_t
*thread_reservations
= NULL
;
234 static volatile uint32_t thread_reservation_count
= 0U;
236 #if XNU_KERNEL_PRIVATE
239 * init_pmc_locks creates and initializes all the locks and lock groups and lock
240 * attributes required for the pmc sub-system.
242 static void init_pmc_locks(void) {
243 pmc_lock_attr
= lck_attr_alloc_init();
244 assert(pmc_lock_attr
);
246 pmc_lock_grp_attr
= lck_grp_attr_alloc_init();
247 assert(pmc_lock_grp_attr
);
249 pmc_lock_grp
= lck_grp_alloc_init("pmc", pmc_lock_grp_attr
);
250 assert(pmc_lock_grp
);
252 lck_spin_init(&perf_monitor_queue_spin
, pmc_lock_grp
, pmc_lock_attr
);
253 lck_spin_init(&perf_counters_queue_spin
, pmc_lock_grp
, pmc_lock_attr
);
255 lck_spin_init(&reservations_spin
, pmc_lock_grp
, pmc_lock_attr
);
257 lck_mtx_init(&cpu_monitor_queue_mutex
, pmc_lock_grp
, pmc_lock_attr
);
261 * init_pmc_zones initializes the allocation zones used by the pmc subsystem
263 static void init_pmc_zones(void) {
264 perf_small_zone
= zinit(PERF_SMALL_UNIT_SZ
,
265 MAX_PERF_SMALLS
* PERF_SMALL_UNIT_SZ
, MAX_PERF_SMALLS
,
268 assert(perf_small_zone
);
270 perf_big_zone
= zinit(PERF_BIG_UNIT_SZ
,
271 MAX_PERF_BIGS
* PERF_BIG_UNIT_SZ
, MAX_PERF_BIGS
,
274 assert(perf_big_zone
);
278 * init_pmc_queues allocates and initializes the tracking queues for
279 * registering and reserving individual pmcs and perf monitors.
281 static void init_pmc_queues(void) {
283 perf_monitors_queue
= (queue_head_t
*)kalloc(sizeof(queue_head_t
));
284 assert(perf_monitors_queue
);
286 queue_init(perf_monitors_queue
);
288 perf_counters_queue
= (queue_head_t
*)kalloc(sizeof(queue_head_t
));
289 assert(perf_counters_queue
);
291 queue_init(perf_counters_queue
);
293 system_reservations
= (queue_head_t
*)kalloc(sizeof(queue_t
));
294 assert(system_reservations
);
296 queue_init(system_reservations
);
298 task_reservations
= (queue_head_t
*)kalloc(sizeof(queue_head_t
));
299 assert(task_reservations
);
301 queue_init(task_reservations
);
303 thread_reservations
= (queue_head_t
*)kalloc(sizeof(queue_head_t
));
304 assert(thread_reservations
);
306 queue_init(thread_reservations
);
310 * pmc_bootstrap brings up all the necessary infrastructure required to use the
314 void pmc_bootstrap(void) {
315 /* build our alloc zones */
318 /* build the locks */
321 /* build our tracking queues */
325 #endif /* XNU_KERNEL_PRIVATE */
328 * Perf Monitor Internals
331 static perf_monitor_t
perf_monitor_alloc(void) {
332 /* perf monitors come from the perf small zone */
333 return (perf_monitor_t
)zalloc(perf_small_zone
);
336 static void perf_monitor_free(void *pm
) {
337 zfree(perf_small_zone
, pm
);
340 static void perf_monitor_init(perf_monitor_t pm
, int cpu
) {
345 bzero(&(pm
->methods
), sizeof(perf_monitor_methods_t
));
347 pm
->useCount
= 1; /* initial retain count of 1, for caller */
349 pm
->reservedCounters
= 0;
353 pm
->link
.next
= pm
->link
.prev
= (queue_entry_t
)NULL
;
354 pm
->cpu_link
.next
= pm
->cpu_link
.prev
= (queue_entry_t
)NULL
;
358 * perf_monitor_dequeue removes the given perf_monitor_t from the
359 * perf_monitor_queue, thereby unregistering it with the system.
361 static void perf_monitor_dequeue(perf_monitor_t pm
) {
362 lck_spin_lock(&perf_monitor_queue_spin
);
364 if (pm
->methods
.flags
& PERFMON_FLAG_REQUIRES_IDLE_NOTIFICATIONS
) {
365 /* If this flag is set, the monitor is already validated to be
366 * accessible from a single cpu only.
368 queue_remove(cpu_monitor_queues
[pm
->cpu
], pm
, perf_monitor_t
, cpu_link
);
372 * remove the @pm object from the @perf_monitor_queue queue (it is of type
373 * <perf_monitor_t> and has a field called @link that is the queue_link_t
375 queue_remove(perf_monitors_queue
, pm
, perf_monitor_t
, link
);
377 perf_monitors_count
--;
379 lck_spin_unlock(&perf_monitor_queue_spin
);
383 * perf_monitor_enqueue adds the given perf_monitor_t to the perf_monitor_queue,
384 * thereby registering it for use with the system.
386 static void perf_monitor_enqueue(perf_monitor_t pm
) {
388 lck_mtx_lock(&cpu_monitor_queue_mutex
);
389 lck_spin_lock(&perf_monitor_queue_spin
);
392 /* Deferred initialisation; saves memory and permits ml_get_max_cpus()
393 * to block until cpu initialisation is complete.
395 if (!cpu_monitor_queues
) {
397 queue_head_t
**queues
;
400 lck_spin_unlock(&perf_monitor_queue_spin
);
402 max_cpus
= ml_get_max_cpus();
404 queues
= (queue_head_t
**)kalloc(sizeof(queue_head_t
*) * max_cpus
);
406 for (i
= 0; i
< max_cpus
; i
++) {
407 queue_head_t
*queue
= (queue_head_t
*)kalloc(sizeof(queue_head_t
));
413 lck_spin_lock(&perf_monitor_queue_spin
);
415 cpu_monitor_queues
= queues
;
418 queue_enter(cpu_monitor_queues
[pm
->cpu
], pm
, perf_monitor_t
, cpu_link
);
421 queue_enter(perf_monitors_queue
, pm
, perf_monitor_t
, link
);
422 perf_monitors_count
++;
424 lck_spin_unlock(&perf_monitor_queue_spin
);
425 lck_mtx_unlock(&cpu_monitor_queue_mutex
);
429 * perf_monitor_reference increments the reference count for the given
432 static void perf_monitor_reference(perf_monitor_t pm
) {
435 OSIncrementAtomic(&(pm
->useCount
));
439 * perf_monitor_deallocate decrements the reference count for the given
440 * perf_monitor_t. If the reference count hits 0, the object is released back
441 * to the perf_small_zone via a call to perf_monitor_free().
443 static void perf_monitor_deallocate(perf_monitor_t pm
) {
446 /* If we just removed the last reference count */
447 if(1 == OSDecrementAtomic(&(pm
->useCount
))) {
448 /* Free the object */
449 perf_monitor_free(pm
);
454 * perf_monitor_find attempts to find a perf_monitor_t that corresponds to the
455 * given C++ object pointer that was used when registering with the subsystem.
457 * If found, the method returns the perf_monitor_t with an extra reference
458 * placed on the object (or NULL if not
461 * NOTE: Caller must use perf_monitor_deallocate to remove the extra reference after
462 * calling perf_monitor_find.
464 static perf_monitor_t
perf_monitor_find(perf_monitor_object_t monitor
) {
466 perf_monitor_t element
= NULL
;
467 perf_monitor_t found
= NULL
;
469 lck_spin_lock(&perf_monitor_queue_spin
);
471 queue_iterate(perf_monitors_queue
, element
, perf_monitor_t
, link
) {
472 if(element
->object
== monitor
) {
473 perf_monitor_reference(element
);
479 lck_spin_unlock(&perf_monitor_queue_spin
);
485 * perf_monitor_add_pmc adds a newly registered PMC to the perf monitor it is
489 static void perf_monitor_add_pmc(perf_monitor_t pm
, pmc_t pmc __unused
) {
493 /* Today, we merely add a reference count now that a new pmc is attached */
494 perf_monitor_reference(pm
);
498 * perf_monitor_remove_pmc removes a newly *un*registered PMC from the perf
499 * monitor it is associated with.
501 static void perf_monitor_remove_pmc(perf_monitor_t pm
, pmc_t pmc __unused
) {
505 /* Today, we merely remove a reference count now that the pmc is detached */
506 perf_monitor_deallocate(pm
);
510 * Perf Counter internals
513 static pmc_t
pmc_alloc(void) {
514 return (pmc_t
)zalloc(perf_big_zone
);
517 static void pmc_free(void *pmc
) {
518 zfree(perf_big_zone
, pmc
);
522 * pmc_init initializes a newly allocated pmc_t
524 static void pmc_init(pmc_t pmc
) {
530 bzero(&pmc
->methods
, sizeof(pmc_methods_t
));
532 /* One reference for the caller */
537 * pmc_reference increments the reference count of the given pmc_t
539 static void pmc_reference(pmc_t pmc
) {
542 OSIncrementAtomic(&(pmc
->useCount
));
546 * pmc_deallocate decrements the reference count of the given pmc_t. If the
547 * reference count hits zero, the given pmc_t is deallocated and released back
548 * to the allocation zone.
550 static void pmc_deallocate(pmc_t pmc
) {
553 /* If we just removed the last reference count */
554 if(1 == OSDecrementAtomic(&(pmc
->useCount
))) {
561 * pmc_dequeue removes the given, newly *un*registered pmc from the
562 * perf_counters_queue.
564 static void pmc_dequeue(pmc_t pmc
) {
565 lck_spin_lock(&perf_counters_queue_spin
);
567 queue_remove(perf_counters_queue
, pmc
, pmc_t
, link
);
569 perf_counters_count
--;
571 lck_spin_unlock(&perf_counters_queue_spin
);
575 * pmc_enqueue adds the given, newly registered pmc to the perf_counters_queue
577 static void pmc_enqueue(pmc_t pmc
) {
578 lck_spin_lock(&perf_counters_queue_spin
);
580 queue_enter(perf_counters_queue
, pmc
, pmc_t
, link
);
582 perf_counters_count
++;
584 lck_spin_unlock(&perf_counters_queue_spin
);
588 * pmc_find attempts to locate a pmc_t that was registered with the given
589 * pmc_object_t pointer. If found, it returns the pmc_t with an extra reference
590 * which must be dropped by the caller by calling pmc_deallocate().
592 static pmc_t
pmc_find(pmc_object_t object
) {
595 lck_spin_lock(&perf_counters_queue_spin
);
597 pmc_t element
= NULL
;
600 queue_iterate(perf_counters_queue
, element
, pmc_t
, link
) {
601 if(element
->object
== object
) {
602 pmc_reference(element
);
608 lck_spin_unlock(&perf_counters_queue_spin
);
617 /* Allocate a pmc_config_t */
618 static pmc_config_t
pmc_config_alloc(pmc_t pmc __unused
) {
619 return (pmc_config_t
)zalloc(perf_small_zone
);
622 /* Free a pmc_config_t, and underlying pmc_config_object_t (if needed) */
623 static void pmc_config_free(pmc_t pmc
, pmc_config_t config
) {
628 pmc
->methods
.free_config(pmc
->object
, config
->object
);
629 config
->object
= NULL
;
632 zfree(perf_small_zone
, config
);
635 static kern_return_t
pmc_open(pmc_t pmc
) {
638 assert(pmc
->open_object
);
640 return pmc
->methods
.open(pmc
->object
, pmc
->open_object
);
643 static kern_return_t
pmc_close(pmc_t pmc
) {
646 assert(pmc
->open_object
);
648 return pmc
->methods
.close(pmc
->object
, pmc
->open_object
);
652 * Reservation Internals
655 static kern_return_t
pmc_internal_reservation_set_pmc(pmc_reservation_t resv
, pmc_t pmc
);
656 static void pmc_internal_reservation_store(pmc_reservation_t reservation
);
657 static void pmc_internal_reservation_load(pmc_reservation_t reservation
);
659 static pmc_reservation_t
reservation_alloc(void) {
660 /* pmc reservations come from the perf small zone */
661 return (pmc_reservation_t
)zalloc(perf_small_zone
);
665 * reservation_free deallocates and releases all resources associated with the
666 * given pmc_reservation_t. This includes freeing the config used to create the
667 * reservation, decrementing the reference count for the pmc used to create the
668 * reservation, and deallocating the reservation's memory.
670 static void reservation_free(pmc_reservation_t resv
) {
675 pmc_free_config(resv
->pmc
, resv
->config
);
681 (void)pmc_internal_reservation_set_pmc(resv
, NULL
);
683 /* Free reservation */
684 zfree(perf_small_zone
, resv
);
688 * reservation_init initializes a newly created reservation.
690 static void reservation_init(pmc_reservation_t resv
) {
698 resv
->state
= PMC_STATE(PMC_STATE_STATE_STOP
, 0, 0);
699 resv
->active_last_context_in
= 0U;
702 * Since this member is a union, we only need to set either the task
705 resv
->task
= TASK_NULL
;
709 * pmc_internal_reservation_set_pmc sets the pmc associated with the reservation object. If
710 * there was one set already, it is deallocated (reference is dropped) before
711 * the new one is set. This methods increases the reference count of the given
714 * NOTE: It is okay to pass NULL as the pmc_t - this will have the effect of
715 * dropping the reference on any previously set pmc, and setting the reservation
716 * to having no pmc set.
718 static kern_return_t
pmc_internal_reservation_set_pmc(pmc_reservation_t resv
, pmc_t pmc
) {
722 (void)pmc_close(resv
->pmc
);
723 pmc_deallocate(resv
->pmc
);
730 pmc_reference(resv
->pmc
);
731 if(KERN_SUCCESS
!= pmc_open(resv
->pmc
)) {
732 pmc_deallocate(resv
->pmc
);
743 * Used to place reservation into one of the system, task, and thread queues
744 * Assumes the queue's spin lock is already held.
746 static void pmc_internal_reservation_enqueue(queue_t queue
, pmc_reservation_t resv
) {
750 queue_enter(queue
, resv
, pmc_reservation_t
, link
);
753 static void pmc_internal_reservation_dequeue(queue_t queue
, pmc_reservation_t resv
) {
757 queue_remove(queue
, resv
, pmc_reservation_t
, link
);
760 /* Returns TRUE if the reservation applies to the current execution context */
761 static boolean_t
pmc_internal_reservation_matches_context(pmc_reservation_t resv
) {
762 boolean_t ret
= FALSE
;
765 if(PMC_FLAG_IS_SYSTEM_SCOPE(resv
->flags
)) {
767 } else if(PMC_FLAG_IS_TASK_SCOPE(resv
->flags
)) {
768 if(current_task() == resv
->task
) {
771 } else if(PMC_FLAG_IS_THREAD_SCOPE(resv
->flags
)) {
772 if(current_thread() == resv
->thread
) {
781 * pmc_accessible_core_count returns the number of logical cores that can access
782 * a given @pmc. 0 means every core in the system.
784 static uint32_t pmc_accessible_core_count(pmc_t pmc
) {
787 uint32_t *cores
= NULL
;
790 if(KERN_SUCCESS
!= pmc
->methods
.accessible_cores(pmc
->object
,
795 return (uint32_t)coreCt
;
798 /* spin lock for the queue must already be held */
800 * This method will inspect the task/thread of the reservation to see if it
801 * matches the new incoming one (for thread/task reservations only). Will only
802 * return TRUE if the task/thread matches.
804 static boolean_t
pmc_internal_reservation_queue_contains_pmc(queue_t queue
, pmc_reservation_t resv
) {
808 boolean_t ret
= FALSE
;
809 pmc_reservation_t tmp
= NULL
;
811 queue_iterate(queue
, tmp
, pmc_reservation_t
, link
) {
812 if(tmp
->pmc
== resv
->pmc
) {
813 /* PMC matches - make sure scope matches first */
814 switch(PMC_FLAG_SCOPE(tmp
->flags
)) {
815 case PMC_FLAG_SCOPE_SYSTEM
:
817 * Found a reservation in system queue with same pmc - always a
822 case PMC_FLAG_SCOPE_THREAD
:
824 * Found one in thread queue with the same PMC as the
825 * argument. Only a conflict if argument scope isn't
826 * thread or system, or the threads match.
828 ret
= (PMC_FLAG_SCOPE(resv
->flags
) != PMC_FLAG_SCOPE_THREAD
) ||
829 (tmp
->thread
== resv
->thread
);
833 * so far, no conflict - check that the pmc that is
834 * being reserved isn't accessible from more than
835 * one core, if it is, we need to say it's already
838 if(1 != pmc_accessible_core_count(tmp
->pmc
)) {
843 case PMC_FLAG_SCOPE_TASK
:
845 * Follow similar semantics for task scope.
848 ret
= (PMC_FLAG_SCOPE(resv
->flags
) != PMC_FLAG_SCOPE_TASK
) ||
849 (tmp
->task
== resv
->task
);
852 * so far, no conflict - check that the pmc that is
853 * being reserved isn't accessible from more than
854 * one core, if it is, we need to say it's already
857 if(1 != pmc_accessible_core_count(tmp
->pmc
)) {
873 * pmc_internal_reservation_validate_for_pmc returns TRUE if the given reservation can be
874 * added to its target queue without creating conflicts (target queue is
875 * determined by the reservation's scope flags). Further, this method returns
876 * FALSE if any level contains a reservation for a PMC that can be accessed from
877 * more than just 1 core, and the given reservation also wants the same PMC.
879 static boolean_t
pmc_internal_reservation_validate_for_pmc(pmc_reservation_t resv
) {
881 boolean_t ret
= TRUE
;
883 if(pmc_internal_reservation_queue_contains_pmc(system_reservations
, resv
) ||
884 pmc_internal_reservation_queue_contains_pmc(task_reservations
, resv
) ||
885 pmc_internal_reservation_queue_contains_pmc(thread_reservations
, resv
)) {
892 static void pmc_internal_update_thread_flag(thread_t thread
, boolean_t newFlag
) {
895 /* See if this thread needs it's PMC flag set */
896 pmc_reservation_t tmp
= NULL
;
900 * If the parent task just dropped its reservation, iterate the thread
901 * reservations to see if we need to keep the pmc flag set for the given
904 lck_spin_lock(&reservations_spin
);
906 queue_iterate(thread_reservations
, tmp
, pmc_reservation_t
, link
) {
907 if(tmp
->thread
== thread
) {
913 lck_spin_unlock(&reservations_spin
);
917 OSBitOrAtomic(THREAD_PMC_FLAG
, &thread
->t_chud
);
919 OSBitAndAtomic(~(THREAD_PMC_FLAG
), &thread
->t_chud
);
924 * This operation is (worst case) O(N*M) where N is number of threads in the
925 * given task, and M is the number of thread reservations in our system.
927 static void pmc_internal_update_task_flag(task_t task
, boolean_t newFlag
) {
929 thread_t thread
= NULL
;
932 OSBitOrAtomic(TASK_PMC_FLAG
, &task
->t_chud
);
934 OSBitAndAtomic(~(TASK_PMC_FLAG
), &task
->t_chud
);
939 queue_iterate(&task
->threads
, thread
, thread_t
, task_threads
) {
940 /* propagate the task's mask down to each thread */
941 pmc_internal_update_thread_flag(thread
, newFlag
);
948 * pmc_internal_reservation_add adds a reservation to the global tracking queues after
949 * ensuring there are no reservation conflicts. To do this, it takes all the
950 * spin locks for all the queue (to ensure no other core goes and adds a
951 * reservation for the same pmc to a queue that has already been checked).
953 static boolean_t
pmc_internal_reservation_add(pmc_reservation_t resv
) {
956 boolean_t ret
= FALSE
;
958 /* always lock all three in the same order */
959 lck_spin_lock(&reservations_spin
);
961 /* Check if the reservation can be added without conflicts */
962 if(pmc_internal_reservation_validate_for_pmc(resv
)) {
964 /* add reservation to appropriate scope */
965 switch(PMC_FLAG_SCOPE(resv
->flags
)) {
966 case PMC_FLAG_SCOPE_SYSTEM
:
967 /* Simply add it to the system queue */
968 pmc_internal_reservation_enqueue(system_reservations
, resv
);
969 system_reservation_count
++;
971 lck_spin_unlock(&reservations_spin
);
975 case PMC_FLAG_SCOPE_TASK
:
978 /* Not only do we enqueue it in our local queue for tracking */
979 pmc_internal_reservation_enqueue(task_reservations
, resv
);
980 task_reservation_count
++;
982 lck_spin_unlock(&reservations_spin
);
984 /* update the task mask, and propagate it to existing threads */
985 pmc_internal_update_task_flag(resv
->task
, TRUE
);
988 /* Thread-switched counter */
989 case PMC_FLAG_SCOPE_THREAD
:
990 assert(resv
->thread
);
993 * Works the same as a task-switched counter, only at
997 pmc_internal_reservation_enqueue(thread_reservations
, resv
);
998 thread_reservation_count
++;
1000 lck_spin_unlock(&reservations_spin
);
1002 pmc_internal_update_thread_flag(resv
->thread
, TRUE
);
1008 lck_spin_unlock(&reservations_spin
);
1014 static void pmc_internal_reservation_broadcast(pmc_reservation_t reservation
, void (*action_func
)(void *)) {
1018 /* Get the list of accessible cores */
1019 if (KERN_SUCCESS
== pmc_get_accessible_core_list(reservation
->pmc
, &cores
, &core_cnt
)) {
1020 boolean_t intrs_enabled
= ml_set_interrupts_enabled(FALSE
);
1022 /* Fast case: the PMC is only accessible from one core and we happen to be on it */
1023 if (core_cnt
== 1 && cores
[0] == (uint32_t)cpu_number()) {
1024 action_func(reservation
);
1026 /* Call action_func on every accessible core */
1027 #if defined(__i386__) || defined(__x86_64__)
1031 /* Build a mask for the accessible cores */
1033 for (ii
= 0; ii
< core_cnt
; ii
++) {
1034 mask
|= cpu_to_cpumask(cores
[ii
]);
1037 /* core_cnt = 0 really means all cpus */
1040 mp_cpus_call(mask
, ASYNC
, action_func
, reservation
);
1042 #error pmc_reservation_interrupt needs an inter-processor method invocation mechanism for this architecture
1046 ml_set_interrupts_enabled(intrs_enabled
);
1052 * pmc_internal_reservation_remove removes the given reservation from the appropriate
1053 * reservation queue according to its scope.
1055 * NOTE: The scope flag must have been set for this method to function.
1057 static void pmc_internal_reservation_remove(pmc_reservation_t resv
) {
1061 * Due to the way the macros are written, we can't just blindly queue-remove
1062 * the reservation without knowing which queue it's in. We figure this out
1063 * using the reservation's scope flags.
1066 /* Lock the global spin lock */
1067 lck_spin_lock(&reservations_spin
);
1069 switch(PMC_FLAG_SCOPE(resv
->flags
)) {
1071 case PMC_FLAG_SCOPE_SYSTEM
:
1072 pmc_internal_reservation_dequeue(system_reservations
, resv
);
1073 system_reservation_count
--;
1075 lck_spin_unlock(&reservations_spin
);
1079 case PMC_FLAG_SCOPE_TASK
:
1080 /* remove from the global queue */
1081 pmc_internal_reservation_dequeue(task_reservations
, resv
);
1082 task_reservation_count
--;
1084 /* unlock the global */
1085 lck_spin_unlock(&reservations_spin
);
1087 /* Recalculate task's counter mask */
1088 pmc_internal_update_task_flag(resv
->task
, FALSE
);
1092 case PMC_FLAG_SCOPE_THREAD
:
1093 pmc_internal_reservation_dequeue(thread_reservations
, resv
);
1094 thread_reservation_count
--;
1096 lck_spin_unlock(&reservations_spin
);
1098 /* recalculate the thread's counter mask */
1099 pmc_internal_update_thread_flag(resv
->thread
, FALSE
);
1105 /* Reservation State Machine
1107 * The PMC subsystem uses a 3-tuple of state information packed into a 32-bit quantity and a
1108 * set of 9 events to provide MP-safe bookkeeping and control flow. The 3-tuple is comprised
1109 * of a state, a count of active contexts, and a set of modifier flags. A state machine defines
1110 * the possible transitions at each event point given the current 3-tuple. Atomicity is handled
1111 * by reading the current 3-tuple, applying the transformations indicated by the state machine
1112 * and then attempting to OSCompareAndSwap the transformed value. If the OSCompareAndSwap fails,
1113 * the process is repeated until either the OSCompareAndSwap succeeds or not valid transitions are
1116 * The state machine is described using tuple notation for the current state and a related notation
1117 * for describing the transformations. For concisness, the flag and state names are abbreviated as
1135 * The tuple notation is formed from the following pattern:
1137 * tuple = < state, active-context-count, flags >
1138 * state = S | CR | L | R | ST | I | D
1139 * active-context-count = 0 | >0 | 1 | >1
1140 * flags = flags flag | blank
1143 * The transform notation is similar, but only describes the modifications made to the current state.
1144 * The notation is formed from the following pattern:
1146 * transform = < state, active-context-count, flags >
1147 * state = S | CR | L | R | ST | I | D
1148 * active-context-count = + | - | blank
1149 * flags = flags flag | flags !flag | blank
1152 * And now for the state machine:
1153 * State Start Stop Free Interrupt End Interrupt Context In Context Out Load Finished Store Finished
1154 * <CR, 0, > <S, , > <D, , > <L, +, >
1156 * <D, 1, D> < , -, !D>
1157 * <D, >1, D> < , -, >
1158 * <I, 0, D> <D, , !D>
1159 * <I, 0, S> < , , !S> < , , !SD> <S, , !S>
1160 * <I, 0, > < , , S> < , , D> <CR, , >
1161 * <L, 1, D> <ST, -, >
1162 * <L, 1, ID> <ST, -, >
1163 * <L, 1, IS> < , , !SD> <ST, -, >
1164 * <L, 1, S> < , , !S> < , , !SD> <ST, -, >
1165 * <L, 1, > < , , S> < , , D> < , , IS> < , +, > <R, , >
1166 * <L, >1, D> < , -, > <R, -, >
1167 * <L, >1, ID> < , -, > <R, -, >
1168 * <L, >1, IS> < , , !SD> < , -, > <R, -, >
1169 * <L, >1, S> < , , !S> < , , !SD> < , -, > <R, -, >
1170 * <L, >1, > < , , S> < , , D> < , , IS> < , +, > < , -, > <R, , >
1171 * <R, 1, D> <ST, -, >
1172 * <R, 1, ID> <ST, -, >
1173 * <R, 1, IS> < , , !SD> <ST, -, >
1174 * <R, 1, S> < , , !S> < , , !SD> <ST, -, >
1175 * <R, 1, > < , , S> < , , D> < , , IS> < , +, > <ST, -, >
1176 * <R, >1, D> < , -, >
1177 * <R, >1, ID> < , -, >
1178 * <R, >1, IS> < , , !SD> < , -, >
1179 * <R, >1, S> < , , !S> < , , !SD> < , -, >
1180 * <R, >1, > < , , S> < , , D> < , , IS> < , +, > < , -, >
1181 * <S, 0, > <CR, , > <D, , >
1182 * <S, 1, ID> <I, -, !I>
1183 * <S, 1, IS> < , , !SD> <I, -, !I>
1184 * <S, 1, S> < , , !S> <D, , !SD> < , -, !S>
1185 * <S, 1, > < , , S> <D, , D> <L, +, > <CR, -, >
1186 * <S, >1, ID> < , -, >
1187 * <S, >1, IS> < , , !SD> < , -, >
1188 * <S, >1, S> < , , !S> <D, , !SD> < , -, >
1189 * <S, >1, > < , , S> <D, , D> <L, +, > < , -, >
1190 * <ST, 0, D> <D, , !D>
1191 * <ST, 0, ID> <I, , !I>
1192 * <ST, 0, IS> < , , !SD> <I, , !I>
1193 * <ST, 0, S> < , , !S> < , , !SD> <S, , !S>
1194 * <ST, 0, > < , , S> < , , D> < , , IS> < , +, > <CR, , >
1195 * <ST, >0, D> < , -, > <D, , >
1196 * <ST, >0, ID> < , -, > <S, , >
1197 * <ST, >0, IS> < , , !SD> < , -, > <S, , >
1198 * <ST, >0, S> < , , !S> < , , !SD> < , -, > <S, , >
1199 * <ST, >0, > < , , S> < , , D> < , , IS> < , +, > < , -, > <L, , >
1202 static uint32_t pmc_internal_reservation_next_state(uint32_t current_state
, pmc_state_event_t event
) {
1203 uint32_t new_state
= PMC_STATE(PMC_STATE_STATE_INVALID
, 0, 0);
1206 case PMC_STATE_EVENT_START
:
1207 switch (current_state
& ~(PMC_STATE_CONTEXT_COUNT_MASK
)) {
1208 case PMC_STATE(PMC_STATE_STATE_INTERRUPT
, 0, PMC_STATE_FLAGS_STOPPING
):
1209 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_STOPPING
):
1210 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, PMC_STATE_FLAGS_STOPPING
):
1211 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, PMC_STATE_FLAGS_STOPPING
):
1212 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_STOPPING
):
1213 new_state
= PMC_STATE_MODIFY(current_state
, 0, 0, PMC_STATE_FLAGS_STOPPING
);
1215 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, 0):
1216 if (PMC_STATE_CONTEXT_COUNT(current_state
) == 0) {
1217 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_CAN_RUN
, 0, 0, 0);
1222 case PMC_STATE_EVENT_STOP
:
1223 switch (current_state
& ~(PMC_STATE_CONTEXT_COUNT_MASK
)) {
1224 case PMC_STATE(PMC_STATE_STATE_CAN_RUN
, 0, 0):
1225 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_STOP
, 0, 0, 0);
1227 case PMC_STATE(PMC_STATE_STATE_INTERRUPT
, 0, 0):
1228 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, 0):
1229 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, 0):
1230 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, 0):
1231 new_state
= PMC_STATE_MODIFY(current_state
, 0, PMC_STATE_FLAGS_STOPPING
, 0);
1233 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, 0):
1234 if (PMC_STATE_CONTEXT_COUNT(current_state
) > 0) {
1235 new_state
= PMC_STATE_MODIFY(current_state
, 0, PMC_STATE_FLAGS_STOPPING
, 0);
1240 case PMC_STATE_EVENT_FREE
:
1241 switch (current_state
& ~(PMC_STATE_CONTEXT_COUNT_MASK
)) {
1242 case PMC_STATE(PMC_STATE_STATE_CAN_RUN
, 0, 0):
1243 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_DEALLOC
, 0, 0, 0);
1245 case PMC_STATE(PMC_STATE_STATE_INTERRUPT
, 0, PMC_STATE_FLAGS_STOPPING
):
1246 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1247 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_STOPPING
):
1248 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1249 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, PMC_STATE_FLAGS_STOPPING
):
1250 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1251 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1252 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_STOPPING
):
1253 new_state
= PMC_STATE_MODIFY(current_state
, 0, PMC_STATE_FLAGS_DEALLOCING
, PMC_STATE_FLAGS_STOPPING
);
1255 case PMC_STATE(PMC_STATE_STATE_INTERRUPT
, 0, 0):
1256 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, 0):
1257 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, 0):
1258 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, 0):
1259 new_state
= PMC_STATE_MODIFY(current_state
, 0, PMC_STATE_FLAGS_DEALLOCING
, 0);
1261 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, PMC_STATE_FLAGS_STOPPING
):
1262 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_DEALLOC
, 0, PMC_STATE_FLAGS_DEALLOCING
, PMC_STATE_FLAGS_STOPPING
);
1264 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, 0):
1265 if (PMC_STATE_CONTEXT_COUNT(current_state
) > 0) {
1266 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_DEALLOC
, 0, PMC_STATE_FLAGS_DEALLOCING
, 0);
1268 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_DEALLOC
, 0, 0, 0);
1273 case PMC_STATE_EVENT_INTERRUPT
:
1274 switch (current_state
& ~(PMC_STATE_CONTEXT_COUNT_MASK
)) {
1275 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, 0):
1276 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, 0):
1277 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, 0):
1278 new_state
= PMC_STATE_MODIFY(current_state
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
, 0);
1282 case PMC_STATE_EVENT_END_OF_INTERRUPT
:
1283 switch (current_state
& ~(PMC_STATE_CONTEXT_COUNT_MASK
)) {
1284 case PMC_STATE(PMC_STATE_STATE_INTERRUPT
, 0, PMC_STATE_FLAGS_DEALLOCING
):
1285 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_DEALLOC
, 0, 0, PMC_STATE_FLAGS_DEALLOCING
);
1287 case PMC_STATE(PMC_STATE_STATE_INTERRUPT
, 0, PMC_STATE_FLAGS_STOPPING
):
1288 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_STOP
, 0, 0, PMC_STATE_FLAGS_STOPPING
);
1290 case PMC_STATE(PMC_STATE_STATE_INTERRUPT
, 0, 0):
1291 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_CAN_RUN
, 0, 0, 0);
1295 case PMC_STATE_EVENT_CONTEXT_IN
:
1296 switch (current_state
& ~(PMC_STATE_CONTEXT_COUNT_MASK
)) {
1297 case PMC_STATE(PMC_STATE_STATE_CAN_RUN
, 0, 0):
1298 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_LOAD
, 1, 0, 0);
1300 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, 0):
1301 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, 0):
1302 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, 0):
1303 new_state
= PMC_STATE_MODIFY(current_state
, 1, 0, 0);
1305 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, 0):
1306 if (PMC_STATE_CONTEXT_COUNT(current_state
) > 0) {
1307 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_LOAD
, 1, 0, 0);
1312 case PMC_STATE_EVENT_CONTEXT_OUT
:
1313 switch (current_state
& ~(PMC_STATE_CONTEXT_COUNT_MASK
)) {
1314 case PMC_STATE(PMC_STATE_STATE_DEALLOC
, 0, PMC_STATE_FLAGS_DEALLOCING
):
1315 if (PMC_STATE_CONTEXT_COUNT(current_state
) > 1) {
1316 new_state
= PMC_STATE_MODIFY(current_state
, -1, 0, PMC_STATE_FLAGS_DEALLOCING
);
1318 new_state
= PMC_STATE_MODIFY(current_state
, -1, 0, 0);
1321 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_DEALLOCING
):
1322 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_DEALLOCING
):
1323 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1324 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_STOPPING
):
1325 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, 0):
1326 if (PMC_STATE_CONTEXT_COUNT(current_state
) > 1) {
1327 new_state
= PMC_STATE_MODIFY(current_state
, -1, 0, 0);
1330 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, PMC_STATE_FLAGS_DEALLOCING
):
1331 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_DEALLOCING
):
1332 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1333 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, PMC_STATE_FLAGS_STOPPING
):
1334 case PMC_STATE(PMC_STATE_STATE_RUN
, 0, 0):
1335 if (PMC_STATE_CONTEXT_COUNT(current_state
) == 1) {
1336 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_STORE
, -1, 0, 0);
1338 new_state
= PMC_STATE_MODIFY(current_state
, -1, 0, 0);
1341 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_DEALLOCING
):
1342 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1343 if (PMC_STATE_CONTEXT_COUNT(current_state
) == 1) {
1344 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_INTERRUPT
, -1, 0, PMC_STATE_FLAGS_INTERRUPTING
);
1346 new_state
= PMC_STATE_MODIFY(current_state
, -1, 0, 0);
1349 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, PMC_STATE_FLAGS_STOPPING
):
1350 if (PMC_STATE_CONTEXT_COUNT(current_state
) == 1) {
1351 new_state
= PMC_STATE_MODIFY(current_state
, -1, 0, PMC_STATE_FLAGS_STOPPING
);
1353 new_state
= PMC_STATE_MODIFY(current_state
, -1, 0, 0);
1356 case PMC_STATE(PMC_STATE_STATE_STOP
, 0, 0):
1357 if (PMC_STATE_CONTEXT_COUNT(current_state
) > 0) {
1358 if (PMC_STATE_CONTEXT_COUNT(current_state
) == 1) {
1359 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_CAN_RUN
, -1, 0, 0);
1361 new_state
= PMC_STATE_MODIFY(current_state
, -1, 0, 0);
1365 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_DEALLOCING
):
1366 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_DEALLOCING
):
1367 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1368 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_STOPPING
):
1369 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, 0):
1370 if (PMC_STATE_CONTEXT_COUNT(current_state
) > 0) {
1371 new_state
= PMC_STATE_MODIFY(current_state
, -1, 0, 0);
1376 case PMC_STATE_EVENT_LOAD_FINISHED
:
1377 switch (current_state
& ~(PMC_STATE_CONTEXT_COUNT_MASK
)) {
1378 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_DEALLOCING
):
1379 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_DEALLOCING
):
1380 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1381 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, PMC_STATE_FLAGS_STOPPING
):
1382 if (PMC_STATE_CONTEXT_COUNT(current_state
) > 1) {
1383 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_RUN
, -1, 0, 0);
1385 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_STORE
, -1, 0, 0);
1388 case PMC_STATE(PMC_STATE_STATE_LOAD
, 0, 0):
1389 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_RUN
, 0, 0, 0);
1393 case PMC_STATE_EVENT_STORE_FINISHED
:
1394 switch (current_state
& ~(PMC_STATE_CONTEXT_COUNT_MASK
)) {
1395 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_DEALLOCING
):
1396 if (PMC_STATE_CONTEXT_COUNT(current_state
) == 0) {
1397 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_DEALLOC
, 0, 0, PMC_STATE_FLAGS_DEALLOCING
);
1399 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_DEALLOC
, 0, 0, 0);
1402 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_DEALLOCING
):
1403 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_INTERRUPTING
| PMC_STATE_FLAGS_STOPPING
):
1404 if (PMC_STATE_CONTEXT_COUNT(current_state
) == 0) {
1405 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_INTERRUPT
, 0, 0, PMC_STATE_FLAGS_INTERRUPTING
);
1407 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_STOP
, 0, 0, 0);
1410 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, PMC_STATE_FLAGS_STOPPING
):
1411 if (PMC_STATE_CONTEXT_COUNT(current_state
) == 0) {
1412 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_STOP
, 0, 0, PMC_STATE_FLAGS_STOPPING
);
1414 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_STOP
, 0, 0, 0);
1417 case PMC_STATE(PMC_STATE_STATE_STORE
, 0, 0):
1418 if (PMC_STATE_CONTEXT_COUNT(current_state
) == 0) {
1419 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_CAN_RUN
, 0, 0, 0);
1421 new_state
= PMC_STATE_MOVE(current_state
, PMC_STATE_STATE_LOAD
, 0, 0, 0);
1431 static uint32_t pmc_internal_reservation_move_for_event(pmc_reservation_t reservation
, pmc_state_event_t event
, pmc_state_t
*old_state_out
) {
1432 pmc_state_t oldState
;
1433 pmc_state_t newState
;
1435 assert(reservation
);
1437 /* Determine what state change, if any, we need to do. Keep trying until either we succeed doing a transition
1438 * or the there is no valid move.
1441 oldState
= reservation
->state
;
1442 newState
= pmc_internal_reservation_next_state(oldState
, event
);
1443 } while (newState
!= PMC_STATE_INVALID
&& !OSCompareAndSwap(oldState
, newState
, &(reservation
->state
)));
1445 if (newState
!= PMC_STATE_INVALID
) {
1446 COUNTER_DEBUG("Moved reservation %p from state "PMC_STATE_FORMAT
" to state "PMC_STATE_FORMAT
" for event %s\n", reservation
, PMC_STATE_ARGS(oldState
), PMC_STATE_ARGS(newState
), pmc_state_event_name(event
));
1448 COUNTER_DEBUG("No valid moves for reservation %p in state "PMC_STATE_FORMAT
" for event %s\n", reservation
, PMC_STATE_ARGS(oldState
), pmc_state_event_name(event
));
1451 if (old_state_out
!= NULL
) {
1452 *old_state_out
= oldState
;
1458 static void pmc_internal_reservation_context_out(pmc_reservation_t reservation
) {
1459 assert(reservation
);
1460 pmc_state_t newState
;
1461 pmc_state_t oldState
;
1463 /* Clear that the this reservation was active when this cpu did its last context in */
1464 OSBitAndAtomic(~(1U << cpu_number()), &(reservation
->active_last_context_in
));
1466 /* Move the state machine */
1467 if (PMC_STATE_INVALID
== (newState
= pmc_internal_reservation_move_for_event(reservation
, PMC_STATE_EVENT_CONTEXT_OUT
, &oldState
))) {
1471 /* Do any actions required based on the state change */
1472 if (PMC_STATE_STATE(newState
) == PMC_STATE_STATE_STORE
&& PMC_STATE_STATE(oldState
) != PMC_STATE_STATE_STORE
) {
1473 /* Just moved into STORE, so store the reservation. */
1474 pmc_internal_reservation_store(reservation
);
1475 } else if (PMC_STATE_STATE(newState
) == PMC_STATE_STATE_DEALLOC
&& PMC_STATE_CONTEXT_COUNT(newState
) == 0 && PMC_STATE_FLAGS(newState
) == 0) {
1476 /* Wakeup any thread blocking for this reservation to hit <DEALLOC, 0, > */
1477 thread_wakeup((event_t
)reservation
);
1482 static void pmc_internal_reservation_context_in(pmc_reservation_t reservation
) {
1483 assert(reservation
);
1484 pmc_state_t oldState
;
1485 pmc_state_t newState
;
1487 /* Move the state machine */
1488 if (PMC_STATE_INVALID
== (newState
= pmc_internal_reservation_move_for_event(reservation
, PMC_STATE_EVENT_CONTEXT_IN
, &oldState
))) {
1492 /* Mark that the reservation was active when this cpu did its last context in */
1493 OSBitOrAtomic(1U << cpu_number(), &(reservation
->active_last_context_in
));
1495 /* Do any actions required based on the state change */
1496 if (PMC_STATE_STATE(newState
) == PMC_STATE_STATE_LOAD
&& PMC_STATE_STATE(oldState
) != PMC_STATE_STATE_LOAD
) {
1497 /* Just moved into LOAD, so load the reservation. */
1498 pmc_internal_reservation_load(reservation
);
1503 static void pmc_internal_reservation_store(pmc_reservation_t reservation
) {
1504 assert(reservation
);
1505 assert(PMC_STATE_STATE(reservation
->state
) == PMC_STATE_STATE_STORE
);
1507 assert(reservation
->pmc
);
1508 assert(reservation
->config
);
1510 pmc_state_t newState
;
1511 kern_return_t ret
= KERN_SUCCESS
;
1513 pmc_t store_pmc
= reservation
->pmc
;
1514 pmc_object_t store_pmc_obj
= store_pmc
->object
;
1515 perf_monitor_t store_pm
= store_pmc
->monitor
;
1518 * Instruct the Perf Monitor that contains this counter to turn
1519 * off the global disable for this counter.
1521 ret
= store_pm
->methods
.disable_counters(store_pm
->object
, &store_pmc_obj
, 1);
1522 if(KERN_SUCCESS
!= ret
) {
1523 COUNTER_DEBUG(" [error] disable_counters: 0x%x\n", ret
);
1527 /* Instruct the counter to disable itself */
1528 ret
= store_pmc
->methods
.disable(store_pmc_obj
);
1529 if(KERN_SUCCESS
!= ret
) {
1530 COUNTER_DEBUG(" [error] disable: 0x%x\n", ret
);
1533 /* store the counter value into the reservation's stored count */
1534 ret
= store_pmc
->methods
.get_count(store_pmc_obj
, &reservation
->value
);
1535 if(KERN_SUCCESS
!= ret
) {
1536 COUNTER_DEBUG(" [error] get_count: 0x%x\n", ret
);
1540 /* Advance the state machine now that the STORE is finished */
1541 if (PMC_STATE_INVALID
== (newState
= pmc_internal_reservation_move_for_event(reservation
, PMC_STATE_EVENT_STORE_FINISHED
, NULL
))) {
1545 /* Do any actions required based on the state change */
1546 if (PMC_STATE_STATE(newState
) == PMC_STATE_STATE_LOAD
) {
1547 /* Just moved into LOAD, so load the reservation. */
1548 pmc_internal_reservation_load(reservation
);
1549 } else if (PMC_STATE_STATE(newState
) == PMC_STATE_STATE_DEALLOC
&& PMC_STATE_CONTEXT_COUNT(newState
) == 0 && PMC_STATE_FLAGS(newState
) == 0) {
1550 /* Wakeup any thread blocking for this reservation to hit <DEALLOC, 0, > */
1551 thread_wakeup((event_t
)reservation
);
1556 static void pmc_internal_reservation_load(pmc_reservation_t reservation
) {
1557 assert(reservation
);
1558 assert(PMC_STATE_STATE(reservation
->state
) == PMC_STATE_STATE_LOAD
);
1560 pmc_state_t newState
;
1561 kern_return_t ret
= KERN_SUCCESS
;
1563 assert(reservation
->pmc
);
1564 assert(reservation
->config
);
1566 pmc_t load_pmc
= reservation
->pmc
;
1567 pmc_object_t load_pmc_obj
= load_pmc
->object
;
1568 perf_monitor_t load_pm
= load_pmc
->monitor
;
1570 /* Set the control register up with the stored configuration */
1571 ret
= load_pmc
->methods
.set_config(load_pmc_obj
, reservation
->config
->object
);
1572 if(KERN_SUCCESS
!= ret
) {
1573 COUNTER_DEBUG(" [error] set_config: 0x%x\n", ret
);
1577 /* load the counter value */
1578 ret
= load_pmc
->methods
.set_count(load_pmc_obj
, reservation
->value
);
1579 if(KERN_SUCCESS
!= ret
) {
1580 COUNTER_DEBUG(" [error] set_count: 0x%x\n", ret
);
1584 /* Locally enable the counter */
1585 ret
= load_pmc
->methods
.enable(load_pmc_obj
);
1586 if(KERN_SUCCESS
!= ret
) {
1587 COUNTER_DEBUG(" [error] enable: 0x%x\n", ret
);
1592 * Instruct the Perf Monitor containing the pmc to enable the
1595 ret
= load_pm
->methods
.enable_counters(load_pm
->object
, &load_pmc_obj
, 1);
1596 if(KERN_SUCCESS
!= ret
) {
1597 COUNTER_DEBUG(" [error] enable_counters: 0x%x\n", ret
);
1598 /* not on the hardware. */
1602 /* Advance the state machine now that the STORE is finished */
1603 if (PMC_STATE_INVALID
== (newState
= pmc_internal_reservation_move_for_event(reservation
, PMC_STATE_EVENT_LOAD_FINISHED
, NULL
))) {
1607 /* Do any actions required based on the state change */
1608 if (PMC_STATE_STATE(newState
) == PMC_STATE_STATE_STORE
) {
1609 /* Just moved into STORE, so store the reservation. */
1610 pmc_internal_reservation_store(reservation
);
1616 * pmc_accessible_from_core will return TRUE if the given @pmc is directly
1617 * (e.g., hardware) readable from the given logical core.
1619 * NOTE: This method is interrupt safe.
1621 static inline boolean_t
pmc_accessible_from_core(pmc_t pmc
, uint32_t logicalCore
) {
1622 boolean_t ret
= FALSE
;
1626 ret
= pmc
->methods
.accessible_from_core(pmc
->object
, logicalCore
);
1631 static void pmc_internal_reservation_start_cpu(void * arg
) {
1632 pmc_reservation_t reservation
= (pmc_reservation_t
)arg
;
1634 assert(reservation
);
1637 if (pmc_internal_reservation_matches_context(reservation
)) {
1638 /* We are in context, but the reservation may have already had the context_in method run. Attempt
1639 * to set this cpu's bit in the active_last_context_in mask. If we set it, call context_in.
1641 uint32_t oldMask
= OSBitOrAtomic(1U << cpu_number(), &(reservation
->active_last_context_in
));
1643 if ((oldMask
& (1U << cpu_number())) == 0) {
1644 COUNTER_DEBUG("Starting already in-context reservation %p for cpu %d\n", reservation
, cpu_number());
1646 pmc_internal_reservation_context_in(reservation
);
1651 static void pmc_internal_reservation_stop_cpu(void * arg
) {
1652 pmc_reservation_t reservation
= (pmc_reservation_t
)arg
;
1654 assert(reservation
);
1657 if (pmc_internal_reservation_matches_context(reservation
)) {
1658 COUNTER_DEBUG("Stopping in-context reservation %p for cpu %d\n", reservation
, cpu_number());
1660 pmc_internal_reservation_context_out(reservation
);
1665 * pmc_reservation_interrupt is called when a PMC reservation which was setup
1666 * with an interrupt threshold counts the requested number of events. When the
1667 * underlying counter hits the threshold, an interrupt is generated, and this
1668 * method is called. This method marks the reservation as stopped, and passes
1669 * control off to the user-registered callback method, along with the
1670 * reservation (so that the user can, for example, write a 0 to the counter, and
1671 * restart the reservation).
1672 * This method assumes the reservation has a valid pmc_config_t within.
1674 * @param target The pmc_reservation_t that caused the interrupt.
1675 * @param refCon User specified reference constant.
1677 static void pmc_reservation_interrupt(void *target
, void *refCon
) {
1678 pmc_reservation_t reservation
= (pmc_reservation_t
)target
;
1679 pmc_state_t newState
;
1683 assert(reservation
);
1685 /* Move the state machine */
1686 if (PMC_STATE_INVALID
== pmc_internal_reservation_move_for_event(reservation
, PMC_STATE_EVENT_INTERRUPT
, NULL
)) {
1690 /* A valid state move has been made, but won't be picked up until a context switch occurs. To cause matching
1691 * contexts that are currently running to update, we do an inter-processor message to run pmc_internal_reservation_stop_cpu
1692 * on every cpu that can access the PMC.
1694 pmc_internal_reservation_broadcast(reservation
, pmc_internal_reservation_stop_cpu
);
1696 /* Spin waiting for the state to turn to INTERRUPT */
1697 nanoseconds_to_absolutetime(PMC_SPIN_TIMEOUT_US
* 1000, &timeout
);
1698 timeout
+= mach_absolute_time();
1700 while (PMC_STATE_STATE(reservation
->state
) != PMC_STATE_STATE_INTERRUPT
) {
1701 /* Assert if this takes longer than PMC_SPIN_TIMEOUT_US */
1702 if (++spins
> PMC_SPIN_THRESHOLD
) {
1703 if (mach_absolute_time() > timeout
) {
1704 pmc_spin_timeout_count
++;
1712 assert(reservation
->config
);
1713 assert(reservation
->config
->method
);
1715 /* Call the registered callback handler */
1717 uint64_t start
= mach_absolute_time();
1720 (void)reservation
->config
->method(reservation
, refCon
);
1723 uint64_t end
= mach_absolute_time();
1724 if((end
- start
) > 5000ULL) {
1725 kprintf("%s - user method %p took %llu ns\n", __FUNCTION__
,
1726 reservation
->config
->method
, (end
- start
));
1730 /* Move the state machine */
1731 if (PMC_STATE_INVALID
== (newState
= pmc_internal_reservation_move_for_event(reservation
, PMC_STATE_EVENT_END_OF_INTERRUPT
, NULL
))) {
1735 /* Do any post-move actions necessary */
1736 if (PMC_STATE_STATE(newState
) == PMC_STATE_STATE_CAN_RUN
) {
1737 pmc_internal_reservation_broadcast(reservation
, pmc_internal_reservation_start_cpu
);
1738 } else if (PMC_STATE_STATE(newState
) == PMC_STATE_STATE_DEALLOC
&& PMC_STATE_CONTEXT_COUNT(newState
) == 0 && PMC_STATE_FLAGS(newState
) == 0) {
1739 /* Wakeup any thread blocking for this reservation to hit <DEALLOC, 0, > */
1740 thread_wakeup((event_t
)reservation
);
1745 * Apple-private KPI for Apple kext's (IOProfileFamily) only
1750 #pragma mark IOProfileFamily private KPI
1754 * perf_monitor_register registers a new Performance Monitor, and its associated
1755 * callback methods. The given perf_monitor_object_t is the first argument to
1756 * each callback when they are called.
1758 kern_return_t
perf_monitor_register(perf_monitor_object_t monitor
,
1759 perf_monitor_methods_t
*methods
) {
1762 COUNTER_DEBUG("registering perf monitor %p\n", monitor
);
1764 if(!monitor
|| !methods
) {
1765 return KERN_INVALID_ARGUMENT
;
1768 /* Protect against out-of-date driver kexts */
1769 if(MACH_PERFMON_METHODS_VERSION
!= methods
->perf_monitor_methods_version
) {
1770 return KERN_INVALID_ARGUMENT
;
1773 /* If the monitor requires idle notifications, ensure that it is
1774 * accessible from a single core only.
1776 if (methods
->flags
& PERFMON_FLAG_REQUIRES_IDLE_NOTIFICATIONS
) {
1780 if (KERN_SUCCESS
== methods
->accessible_cores(monitor
, &cores
, &core_cnt
)) {
1782 * Guard against disabled cores - monitors will always match and
1783 * attempt registration, irrespective of 'cpus=x' boot-arg.
1785 if ((core_cnt
== 1) && (cores
[0] < (uint32_t)ml_get_max_cpus())) {
1788 return KERN_INVALID_ARGUMENT
;
1793 /* All methods are required */
1794 if(!methods
->accessible_cores
|
1795 !methods
->enable_counters
|| !methods
->disable_counters
||
1796 !methods
->on_idle
|| !methods
->on_idle_exit
) {
1797 return KERN_INVALID_ARGUMENT
;
1800 /* prevent dupes. */
1801 perf_monitor_t dupe
= perf_monitor_find(monitor
);
1803 COUNTER_DEBUG("Duplicate registration for %p\n", monitor
);
1804 perf_monitor_deallocate(dupe
);
1805 return KERN_FAILURE
;
1808 perf_monitor_t pm
= perf_monitor_alloc();
1810 return KERN_RESOURCE_SHORTAGE
;
1813 /* initialize the object */
1814 perf_monitor_init(pm
, cpu
);
1816 /* copy in the registration info */
1817 pm
->object
= monitor
;
1818 memcpy(&(pm
->methods
), methods
, sizeof(perf_monitor_methods_t
));
1820 /* place it in the tracking queues */
1821 perf_monitor_enqueue(pm
);
1826 return KERN_SUCCESS
;
1830 * perf_monitor_unregister unregisters a previously registered Perf Monitor,
1831 * looking it up by reference pointer (the same that was used in
1832 * perf_monitor_register()).
1834 kern_return_t
perf_monitor_unregister(perf_monitor_object_t monitor
) {
1835 kern_return_t ret
= KERN_FAILURE
;
1837 COUNTER_DEBUG("unregistering perf monitor %p\n", monitor
);
1840 return KERN_INVALID_ARGUMENT
;
1843 perf_monitor_t pm
= perf_monitor_find(monitor
);
1845 /* Remove it from the queues. */
1846 perf_monitor_dequeue(pm
);
1848 /* drop extra retain from find */
1849 perf_monitor_deallocate(pm
);
1851 /* and release the object */
1852 perf_monitor_deallocate(pm
);
1856 COUNTER_DEBUG("could not find a registered pm that matches!\n");
1863 * pmc_register registers a new PMC for use with the pmc subsystem. Each PMC is
1864 * associated with a Perf Monitor. Perf Monitors are looked up by the reference
1865 * pointer that was used to previously register them.
1867 * PMCs are registered with a reference pointer (@pmc_object), and a set of
1868 * callback methods. When the given callback methods are called from xnu, the
1869 * first argument will always be the reference pointer used to register the PMC.
1871 * NOTE: @monitor must have been successfully registered via
1872 * perf_monitor_register before this method will succeed.
1874 kern_return_t
pmc_register(perf_monitor_object_t monitor
, pmc_object_t pmc_object
,
1875 pmc_methods_t
*methods
, void *object
) {
1877 COUNTER_DEBUG("%p %p\n", monitor
, pmc_object
);
1879 if(!monitor
|| !pmc_object
|| !methods
|| !object
) {
1880 return KERN_INVALID_ARGUMENT
;
1883 /* Prevent version mismatches */
1884 if(MACH_PMC_METHODS_VERSION
!= methods
->pmc_methods_version
) {
1885 COUNTER_DEBUG("version mismatch\n");
1886 return KERN_INVALID_ARGUMENT
;
1889 /* All methods are required. */
1890 if(!methods
->create_config
||
1891 !methods
->free_config
||
1892 !methods
->config_set_value
||
1893 !methods
->config_set_threshold
||
1894 !methods
->config_set_handler
||
1895 !methods
->set_config
||
1896 !methods
->get_monitor
||
1897 !methods
->get_name
||
1898 !methods
->accessible_from_core
||
1899 !methods
->accessible_cores
||
1900 !methods
->get_count
||
1901 !methods
->set_count
||
1902 !methods
->disable
||
1906 return KERN_INVALID_ARGUMENT
;
1909 /* make sure this perf monitor object is already registered */
1911 * NOTE: this adds a reference to the parent, so we'll have to drop it in
1912 * any failure code paths from here on out.
1914 perf_monitor_t pm
= perf_monitor_find(monitor
);
1916 COUNTER_DEBUG("Could not find perf monitor for %p\n", monitor
);
1917 return KERN_INVALID_ARGUMENT
;
1920 /* make a new pmc */
1921 pmc_t pmc
= pmc_alloc();
1923 /* drop the extra reference from perf_monitor_find() */
1924 perf_monitor_deallocate(pm
);
1925 return KERN_RESOURCE_SHORTAGE
;
1931 pmc
->object
= pmc_object
;
1932 pmc
->open_object
= object
;
1934 /* copy the callbacks in */
1935 memcpy(&(pmc
->methods
), methods
, sizeof(pmc_methods_t
));
1939 perf_monitor_add_pmc(pmc
->monitor
, pmc
);
1941 /* enqueue it in our tracking queue */
1944 /* drop extra reference from perf_monitor_find() */
1945 perf_monitor_deallocate(pm
);
1947 return KERN_SUCCESS
;
1951 * pmc_unregister unregisters a previously registered PMC, looking it up by
1952 * reference point to *both* the Perf Monitor it was created with, and the PMC's
1953 * reference pointer itself.
1955 kern_return_t
pmc_unregister(perf_monitor_object_t monitor
, pmc_object_t pmc_object
) {
1956 COUNTER_DEBUG("%p %p\n", monitor
, pmc_object
);
1958 if(!monitor
|| !pmc_object
) {
1959 return KERN_INVALID_ARGUMENT
;
1962 pmc_t pmc
= pmc_find(pmc_object
);
1964 COUNTER_DEBUG("Could not find a matching pmc.\n");
1965 return KERN_FAILURE
;
1968 /* remove it from the global queue */
1971 perf_monitor_remove_pmc(pmc
->monitor
, pmc
);
1973 /* remove extra reference count from pmc_find() */
1974 pmc_deallocate(pmc
);
1976 /* dealloc the pmc */
1977 pmc_deallocate(pmc
);
1979 return KERN_SUCCESS
;
1982 static void perf_monitor_reservation_add(perf_monitor_t monitor
) {
1984 OSIncrementAtomic(&(monitor
->reservedCounters
));
1987 static void perf_monitor_reservation_remove(perf_monitor_t monitor
) {
1989 OSDecrementAtomic(&(monitor
->reservedCounters
));
1998 * Begin in-kernel and in-kext KPI methods
2002 * pmc_create_config creates a new configuration area from a given @pmc.
2004 * NOTE: This method is not interrupt safe.
2006 kern_return_t
pmc_create_config(pmc_t pmc
, pmc_config_t
*config
) {
2007 pmc_config_t tmp
= NULL
;
2009 if(!pmc
|| !config
) {
2010 return KERN_INVALID_ARGUMENT
;
2015 tmp
= pmc_config_alloc(pmc
);
2017 tmp
->object
= pmc
->methods
.create_config(pmc
->object
);
2020 pmc_config_free(pmc
, tmp
);
2023 tmp
->interrupt_after_value
= 0ULL;
2029 pmc_deallocate(pmc
);
2032 return KERN_RESOURCE_SHORTAGE
;
2037 return KERN_SUCCESS
;
2041 * pmc_free_config frees a configuration area created from a given @pmc
2043 * NOTE: This method is not interrupt safe.
2045 void pmc_free_config(pmc_t pmc
, pmc_config_t config
) {
2051 pmc_config_free(pmc
, config
);
2053 pmc_deallocate(pmc
);
2057 * pmc_config_set_value sets up configuration area key-value pairs. These pairs
2058 * are to be either pre-known, or looked up via CoreProfile.framework.
2060 * NOTE: This method is not interrupt safe.
2062 kern_return_t
pmc_config_set_value(pmc_t pmc
, pmc_config_t config
,
2063 uint8_t id
, uint64_t value
) {
2065 kern_return_t ret
= KERN_INVALID_ARGUMENT
;
2067 if(!pmc
|| !config
) {
2073 ret
= pmc
->methods
.config_set_value(config
->object
, id
, value
);
2075 pmc_deallocate(pmc
);
2081 * pmc_config_set_interrupt_threshold modifies a config object, instructing
2082 * the pmc that it should generate a call to the given pmc_interrupt_method_t
2083 * after the counter counts @threshold events.
2085 * PMC Threshold handler methods will have the pmc_reservation_t that generated the interrupt
2086 * as the first argument when the interrupt handler is invoked, and the given
2087 * @refCon (which may be NULL) as the second.
2089 * See pmc_interrupt_method_t.
2091 * NOTE: This method is not interrupt safe.
2093 kern_return_t
pmc_config_set_interrupt_threshold(pmc_t pmc
, pmc_config_t config
,
2094 uint64_t threshold
, pmc_interrupt_method_t method
, void *refCon
) {
2095 kern_return_t ret
= KERN_INVALID_ARGUMENT
;
2097 if(!config
|| !pmc
) {
2108 * We have a minor annoyance to side-step here. The driver layer expects
2109 * the config to never change once a reservation has been taken out with
2110 * it. However, in order to have the PMI method have the reservation as
2111 * the first argument (in order to allow the user-method to, for
2112 * example, write a 0 to it, and restart it), we need to create the
2113 * pmc_reservation_t before setting it up in the config object.
2114 * We overcome this by caching the method in the pmc_config_t stand-in,
2115 * and mutating the pmc_config_object_t just before returning a
2116 * reservation (in pmc_reserve() and friends, below).
2119 /* might as well stash this away too. */
2120 config
->interrupt_after_value
= threshold
;
2121 config
->method
= method
;
2122 config
->refCon
= refCon
;
2128 pmc_deallocate(pmc
);
2134 * pmc_get_pmc_list returns an allocated list of pmc_t's, as well as the number
2135 * of pmc_t's returned. Callers should free this list with a call to
2136 * pmc_free_pmc_list().
2138 * NOTE: This method is not interrupt safe.
2140 kern_return_t
pmc_get_pmc_list(pmc_t
**pmcs
, size_t *pmcCount
) {
2141 pmc_t
*array
= NULL
;
2146 /* Copy down (to the stack) the count of perf counters */
2147 vm_size_t size
= perf_counters_count
;
2149 /* Allocate that sized chunk */
2150 array
= (pmc_t
*)kalloc(sizeof(pmc_t
) * size
);
2152 return KERN_RESOURCE_SHORTAGE
;
2155 /* Take the spin lock */
2156 lck_spin_lock(&perf_counters_queue_spin
);
2158 /* verify the size didn't change while we were allocating */
2159 if(size
!= perf_counters_count
) {
2161 * queue size has changed between alloc and now - go back and
2162 * make another pass.
2166 lck_spin_unlock(&perf_counters_queue_spin
);
2168 /* free the block */
2169 kfree(array
, sizeof(pmc_t
) * size
);
2173 /* if we get here, and array is NULL, we try again. */
2176 /* copy the bits out */
2177 queue_iterate(perf_counters_queue
, pmc
, pmc_t
, link
) {
2178 /* copy out the pointer */
2179 array
[count
++] = pmc
;
2182 lck_spin_unlock(&perf_counters_queue_spin
);
2184 /* return the list and the size */
2188 return KERN_SUCCESS
;
2192 * pmc_free_pmc_list frees an array of pmc_t that has been returned from
2195 * NOTE: This method is not interrupt safe.
2197 void pmc_free_pmc_list(pmc_t
*pmcs
, size_t pmcCount
) {
2198 if(pmcs
&& pmcCount
) {
2199 COUNTER_DEBUG("pmcs: %p pmcCount: %lu\n", pmcs
, pmcCount
);
2201 kfree(pmcs
, pmcCount
* sizeof(pmc_t
));
2205 kern_return_t
pmc_find_by_name(const char *name
, pmc_t
**pmcs
, size_t *pmcCount
) {
2206 kern_return_t ret
= KERN_INVALID_ARGUMENT
;
2208 if(!name
|| !pmcs
|| !pmcCount
) {
2215 if(KERN_SUCCESS
== (ret
= pmc_get_pmc_list(&list
, &count
))) {
2216 size_t matchCount
= 0UL, ii
= 0UL, swapPtr
= 0UL;
2217 size_t len
= strlen(name
);
2219 for(ii
= 0UL; ii
< count
; ii
++) {
2220 const char *pmcName
= pmc_get_name(list
[ii
]);
2222 if(strlen(pmcName
) < len
) {
2224 * If the pmc name is shorter than the requested match, it's no
2225 * match, as we're looking for the most specific match(es).
2230 if(0 == strncmp(name
, pmcName
, len
)) {
2231 pmc_t temp
= list
[ii
];
2233 // move matches to the head of the array.
2234 list
[ii
] = list
[swapPtr
];
2235 list
[swapPtr
] = temp
;
2238 // keep a count of the matches
2245 * If we have matches, they are all at the head of the array, so
2246 * just allocate enough space for @matchCount pmc_t's, and copy the
2247 * head of the array to the new allocation. Then free the old
2251 pmc_t
*result
= (pmc_t
*)kalloc(sizeof(pmc_t
) * matchCount
);
2254 memcpy(result
, list
, sizeof(pmc_t
) * matchCount
);
2259 pmc_free_pmc_list(list
, count
);
2264 return KERN_RESOURCE_SHORTAGE
;
2268 *pmcCount
= matchCount
;
2279 * pmc_get_name returns a pointer (not copied) to the human-readable name of the
2282 * NOTE: Driver authors must take care to not allocate during this method, as
2283 * this method *IS* interrupt safe.
2285 const char *pmc_get_name(pmc_t pmc
) {
2288 const char *name
= pmc
->methods
.get_name(pmc
->object
);
2294 * pmc_get_accessible_core_list returns a pointer to an array of logical core
2295 * numbers (as well as the size of that array) that represent the local cores
2296 * (hardware threads) from which the given @pmc can be accessed directly.
2298 * NOTE: This method is interrupt safe.
2300 kern_return_t
pmc_get_accessible_core_list(pmc_t pmc
, uint32_t **logicalCores
,
2301 size_t *logicalCoreCt
) {
2303 kern_return_t ret
= KERN_INVALID_ARGUMENT
;
2305 if(!pmc
|| !logicalCores
|| !logicalCoreCt
) {
2309 ret
= pmc
->methods
.accessible_cores(pmc
->object
, logicalCores
, logicalCoreCt
);
2314 static boolean_t
pmc_reservation_setup_pmi(pmc_reservation_t resv
, pmc_config_t config
) {
2318 assert(config
->object
);
2320 /* If there's no PMI to setup, return success */
2321 if(config
->interrupt_after_value
&& config
->method
) {
2323 /* set the threshold */
2324 kern_return_t ret
= resv
->pmc
->methods
.config_set_threshold(config
->object
,
2325 config
->interrupt_after_value
);
2327 if(KERN_SUCCESS
!= ret
) {
2329 * This is the most useful error message here, as this only happens
2330 * as a result of pmc_reserve*()
2332 COUNTER_DEBUG("Failed to set threshold for pmc %p\n", resv
->pmc
);
2336 if(KERN_SUCCESS
!= resv
->pmc
->methods
.config_set_handler(config
->object
,
2337 (void *)resv
, &pmc_reservation_interrupt
, config
->refCon
)) {
2339 COUNTER_DEBUG("Failed to set handler for pmc %p\n", resv
->pmc
);
2348 * pmc_reserve will attempt to reserve the given @pmc, with a given
2349 * configuration object, for counting system-wide. This method will fail with
2350 * KERN_FAILURE if the given pmc is already reserved at any scope.
2352 * This method consumes the given configuration object if it returns
2353 * KERN_SUCCESS. Any other return value indicates the caller
2354 * must free the config object via pmc_free_config().
2356 * NOTE: This method is NOT interrupt safe.
2358 kern_return_t
pmc_reserve(pmc_t pmc
, pmc_config_t config
,
2359 pmc_reservation_t
*reservation
) {
2361 if(!pmc
|| !config
|| !reservation
) {
2362 return KERN_INVALID_ARGUMENT
;
2365 pmc_reservation_t resv
= reservation_alloc();
2367 return KERN_RESOURCE_SHORTAGE
;
2370 reservation_init(resv
);
2372 resv
->flags
|= PMC_FLAG_SCOPE_SYSTEM
;
2373 resv
->config
= config
;
2375 if(KERN_SUCCESS
!= pmc_internal_reservation_set_pmc(resv
, pmc
)) {
2376 resv
->config
= NULL
;
2377 return KERN_FAILURE
;
2380 /* enqueue reservation in proper place */
2381 if(!pmc_internal_reservation_add(resv
) || !pmc_reservation_setup_pmi(resv
, config
)) {
2382 /* Prevent free of config object */
2383 resv
->config
= NULL
;
2385 reservation_free(resv
);
2386 return KERN_FAILURE
;
2389 perf_monitor_reservation_add(pmc
->monitor
);
2391 *reservation
= resv
;
2393 return KERN_SUCCESS
;
2397 * pmc_reserve_task will attempt to reserve the given @pmc with a given
2398 * configuration object, for counting when the given @task is running on any
2399 * logical core that can directly access the given @pmc. This method will fail
2400 * with KERN_FAILURE if the given pmc is already reserved at either system or
2403 * This method consumes the given configuration object if it returns
2404 * KERN_SUCCESS. Any other return value indicates the caller
2405 * must free the config object via pmc_free_config().
2407 * NOTE: You can reserve the same pmc for N different tasks concurrently.
2408 * NOTE: This method is NOT interrupt safe.
2410 kern_return_t
pmc_reserve_task(pmc_t pmc
, pmc_config_t config
,
2411 task_t task
, pmc_reservation_t
*reservation
) {
2413 if(!pmc
|| !config
|| !reservation
|| !task
) {
2414 return KERN_INVALID_ARGUMENT
;
2417 if (!(pmc
->monitor
->methods
.flags
& PERFMON_FLAG_SUPPORTS_CONTEXT_SWITCHING
)) {
2418 COUNTER_DEBUG("pmc %p cannot be context switched!\n", pmc
);
2419 return KERN_INVALID_ARGUMENT
;
2422 pmc_reservation_t resv
= reservation_alloc();
2424 return KERN_RESOURCE_SHORTAGE
;
2427 reservation_init(resv
);
2429 resv
->flags
|= PMC_FLAG_SCOPE_TASK
;
2432 resv
->config
= config
;
2434 if(KERN_SUCCESS
!= pmc_internal_reservation_set_pmc(resv
, pmc
)) {
2435 resv
->config
= NULL
;
2436 return KERN_FAILURE
;
2439 /* enqueue reservation in proper place */
2440 if(!pmc_internal_reservation_add(resv
) || !pmc_reservation_setup_pmi(resv
, config
)) {
2441 /* Prevent free of config object */
2442 resv
->config
= NULL
;
2444 reservation_free(resv
);
2445 return KERN_FAILURE
;
2448 perf_monitor_reservation_add(pmc
->monitor
);
2450 *reservation
= resv
;
2452 return KERN_SUCCESS
;
2456 * pmc_reserve_thread will attempt to reserve the given @pmc with a given
2457 * configuration object, for counting when the given @thread is running on any
2458 * logical core that can directly access the given @pmc. This method will fail
2459 * with KERN_FAILURE if the given pmc is already reserved at either system or
2462 * This method consumes the given configuration object if it returns
2463 * KERN_SUCCESS. Any other return value indicates the caller
2464 * must free the config object via pmc_free_config().
2466 * NOTE: You can reserve the same pmc for N different threads concurrently.
2467 * NOTE: This method is NOT interrupt safe.
2469 kern_return_t
pmc_reserve_thread(pmc_t pmc
, pmc_config_t config
,
2470 thread_t thread
, pmc_reservation_t
*reservation
) {
2471 if(!pmc
|| !config
|| !reservation
|| !thread
) {
2472 return KERN_INVALID_ARGUMENT
;
2475 if (!(pmc
->monitor
->methods
.flags
& PERFMON_FLAG_SUPPORTS_CONTEXT_SWITCHING
)) {
2476 COUNTER_DEBUG("pmc %p cannot be context switched!\n", pmc
);
2477 return KERN_INVALID_ARGUMENT
;
2480 pmc_reservation_t resv
= reservation_alloc();
2482 return KERN_RESOURCE_SHORTAGE
;
2485 reservation_init(resv
);
2487 resv
->flags
|= PMC_FLAG_SCOPE_THREAD
;
2488 resv
->thread
= thread
;
2490 resv
->config
= config
;
2492 if(KERN_SUCCESS
!= pmc_internal_reservation_set_pmc(resv
, pmc
)) {
2493 resv
->config
= NULL
;
2494 return KERN_FAILURE
;
2497 /* enqueue reservation in proper place */
2498 if(!pmc_internal_reservation_add(resv
) || !pmc_reservation_setup_pmi(resv
, config
)) {
2499 /* Prevent free of config object */
2500 resv
->config
= NULL
;
2502 reservation_free(resv
);
2503 return KERN_FAILURE
;
2506 perf_monitor_reservation_add(pmc
->monitor
);
2508 *reservation
= resv
;
2510 return KERN_SUCCESS
;
2514 * pmc_reservation_start instructs the given reservation to start counting as
2517 * NOTE: This method is interrupt safe.
2519 kern_return_t
pmc_reservation_start(pmc_reservation_t reservation
) {
2520 pmc_state_t newState
;
2523 return KERN_INVALID_ARGUMENT
;
2526 /* Move the state machine */
2527 if (PMC_STATE_INVALID
== (newState
= pmc_internal_reservation_move_for_event(reservation
, PMC_STATE_EVENT_START
, NULL
))) {
2528 return KERN_FAILURE
;
2531 /* If we are currently in an interrupt, don't bother to broadcast since it won't do anything now and the interrupt will
2532 * broadcast right before it leaves
2534 if (PMC_STATE_STATE(newState
) != PMC_STATE_STATE_INTERRUPT
) {
2535 /* A valid state move has been made, but won't be picked up until a context switch occurs. To cause matching
2536 * contexts that are currently running to update, we do an inter-processor message to run pmc_internal_reservation_start_cpu
2537 * on every cpu that can access the PMC.
2539 pmc_internal_reservation_broadcast(reservation
, pmc_internal_reservation_start_cpu
);
2542 return KERN_SUCCESS
;
2546 * pmc_reservation_stop instructs the given reservation to stop counting as
2547 * soon as possible. When this method returns, the pmc will be marked as stopping
2548 * and subsequent calls to pmc_reservation_start will succeed. This does not mean
2549 * that the pmc hardware has _actually_ stopped running. Assuming no other changes
2550 * to the reservation state, the pmc hardware _will_ stop shortly.
2553 kern_return_t
pmc_reservation_stop(pmc_reservation_t reservation
) {
2554 pmc_state_t newState
;
2557 return KERN_INVALID_ARGUMENT
;
2560 /* Move the state machine */
2561 if (PMC_STATE_INVALID
== (newState
= pmc_internal_reservation_move_for_event(reservation
, PMC_STATE_EVENT_STOP
, NULL
))) {
2562 return KERN_FAILURE
;
2565 /* If we are currently in an interrupt, don't bother to broadcast since it won't do anything now and the interrupt will
2566 * broadcast right before it leaves. Similarly, if we just moved directly to STOP, don't bother broadcasting.
2568 if (PMC_STATE_STATE(newState
) != PMC_STATE_STATE_INTERRUPT
&& PMC_STATE_STATE(newState
) != PMC_STATE_STATE_STOP
) {
2569 /* A valid state move has been made, but won't be picked up until a context switch occurs. To cause matching
2570 * contexts that are currently running to update, we do an inter-processor message to run pmc_internal_reservation_stop_cpu
2571 * on every cpu that can access the PMC.
2574 pmc_internal_reservation_broadcast(reservation
, pmc_internal_reservation_stop_cpu
);
2577 return KERN_SUCCESS
;
2581 * pmc_reservation_read will read the event count associated with a reservation.
2582 * If the caller is current executing in a context that both a) matches the
2583 * reservation's context, and b) can access the reservation's pmc directly, the
2584 * value will be read from hardware. Otherwise, this returns the reservation's
2587 * NOTE: This method is interrupt safe.
2588 * NOTE: When not on the interrupt stack, this method may block.
2590 kern_return_t
pmc_reservation_read(pmc_reservation_t reservation
, uint64_t *value
) {
2591 kern_return_t ret
= KERN_FAILURE
;
2595 if(!reservation
|| !value
) {
2596 return KERN_INVALID_ARGUMENT
;
2599 nanoseconds_to_absolutetime(PMC_SPIN_TIMEOUT_US
* 1000, &timeout
);
2600 timeout
+= mach_absolute_time();
2603 uint32_t state
= reservation
->state
;
2605 if((PMC_STATE_STATE(state
) == PMC_STATE_STATE_RUN
)) {
2606 /* Attempt read from hardware via drivers. */
2608 assert(reservation
->pmc
);
2610 ret
= reservation
->pmc
->methods
.get_count(reservation
->pmc
->object
, value
);
2613 } else if ((PMC_STATE_STATE(state
) == PMC_STATE_STATE_STORE
) ||
2614 (PMC_STATE_STATE(state
) == PMC_STATE_STATE_LOAD
)) {
2616 /* Assert if this takes longer than PMC_SPIN_TIMEOUT_US */
2617 if (++spins
> PMC_SPIN_THRESHOLD
) {
2618 if (mach_absolute_time() > timeout
) {
2619 pmc_spin_timeout_count
++;
2630 /* If the direct hardware read failed (for whatever reason) */
2631 if(KERN_SUCCESS
!= ret
) {
2632 /* Read stored value */
2633 *value
= reservation
->value
;
2636 return KERN_SUCCESS
;
2640 * pmc_reservation_write will write the event count associated with a reservation.
2641 * If the caller is current executing in a context that both a) matches the
2642 * reservation's context, and b) can access the reservation's pmc directly, the
2643 * value will be written to hardware. Otherwise, this writes the reservation's
2646 * NOTE: This method is interrupt safe.
2647 * NOTE: When not on the interrupt stack, this method may block.
2649 kern_return_t
pmc_reservation_write(pmc_reservation_t reservation
, uint64_t value
) {
2650 kern_return_t ret
= KERN_FAILURE
;
2655 return KERN_INVALID_ARGUMENT
;
2658 nanoseconds_to_absolutetime(PMC_SPIN_TIMEOUT_US
* 1000, &timeout
);
2659 timeout
+= mach_absolute_time();
2662 uint32_t state
= reservation
->state
;
2664 if((PMC_STATE_STATE(state
) == PMC_STATE_STATE_RUN
)) {
2665 /* Write to hardware via drivers. */
2666 assert(reservation
->pmc
);
2668 ret
= reservation
->pmc
->methods
.set_count(reservation
->pmc
->object
, value
);
2670 } else if ((PMC_STATE_STATE(state
) == PMC_STATE_STATE_STORE
) ||
2671 (PMC_STATE_STATE(state
) == PMC_STATE_STATE_LOAD
)) {
2673 /* Assert if this takes longer than PMC_SPIN_TIMEOUT_US */
2674 if (++spins
> PMC_SPIN_THRESHOLD
) {
2675 if (mach_absolute_time() > timeout
) {
2676 pmc_spin_timeout_count
++;
2687 if(KERN_SUCCESS
!= ret
) {
2688 /* Write stored value */
2689 reservation
->value
= value
;
2692 return KERN_SUCCESS
;
2696 * pmc_reservation_free releases a reservation and all associated resources.
2698 * NOTE: This method is NOT interrupt safe.
2700 kern_return_t
pmc_reservation_free(pmc_reservation_t reservation
) {
2701 pmc_state_t newState
;
2704 return KERN_INVALID_ARGUMENT
;
2707 perf_monitor_reservation_remove(reservation
->pmc
->monitor
);
2709 /* Move the state machine */
2710 if (PMC_STATE_INVALID
== (newState
= pmc_internal_reservation_move_for_event(reservation
, PMC_STATE_EVENT_FREE
, NULL
))) {
2711 return KERN_FAILURE
;
2714 /* If we didn't move directly to DEALLOC, help things along */
2715 if (PMC_STATE_STATE(newState
) != PMC_STATE_STATE_DEALLOC
) {
2716 /* A valid state move has been made, but won't be picked up until a context switch occurs. To cause matching
2717 * contexts that are currently running to update, we do an inter-processor message to run pmc_internal_reservation_stop_cpu
2718 * on every cpu that can access the PMC.
2720 pmc_internal_reservation_broadcast(reservation
, pmc_internal_reservation_stop_cpu
);
2723 /* Block until the reservation hits the <DEALLOC, 0, > state */
2724 while (!(PMC_STATE_STATE(reservation
->state
) == PMC_STATE_STATE_DEALLOC
&& PMC_STATE_CONTEXT_COUNT(reservation
->state
) == 0 && PMC_STATE_FLAGS(reservation
->state
) == 0)) {
2725 assert_wait((event_t
)reservation
, THREAD_UNINT
);
2726 thread_block(THREAD_CONTINUE_NULL
);
2729 /* remove from queues */
2730 pmc_internal_reservation_remove(reservation
);
2732 /* free reservation */
2733 reservation_free(reservation
);
2735 return KERN_SUCCESS
;
2739 * pmc_idle notifies eligible monitors of impending per-CPU idle, and can be used to save state.
2741 boolean_t
pmc_idle(void) {
2742 perf_monitor_t monitor
= NULL
;
2743 queue_head_t
*cpu_queue
;
2745 lck_spin_lock(&perf_monitor_queue_spin
);
2747 if (cpu_monitor_queues
) {
2748 cpu_queue
= cpu_monitor_queues
[cpu_number()];
2750 queue_iterate(cpu_queue
, monitor
, perf_monitor_t
, cpu_link
) {
2751 perf_monitor_methods_t
*methods
= &(monitor
->methods
);
2752 if ((methods
->flags
& PERFMON_FLAG_ALWAYS_ACTIVE
) || (monitor
->reservedCounters
)) {
2753 methods
->on_idle(monitor
->object
);
2758 lck_spin_unlock(&perf_monitor_queue_spin
);
2764 * pmc_idle_exit notifies eligible monitors of wake from idle; it can be used to restore state.
2766 boolean_t
pmc_idle_exit(void) {
2767 perf_monitor_t monitor
= NULL
;
2768 queue_head_t
*cpu_queue
;
2770 lck_spin_lock(&perf_monitor_queue_spin
);
2772 if (cpu_monitor_queues
) {
2773 cpu_queue
= cpu_monitor_queues
[cpu_number()];
2775 queue_iterate(cpu_queue
, monitor
, perf_monitor_t
, cpu_link
) {
2776 perf_monitor_methods_t
*methods
= &(monitor
->methods
);
2777 if ((methods
->flags
& PERFMON_FLAG_ALWAYS_ACTIVE
) || (monitor
->reservedCounters
)) {
2778 methods
->on_idle_exit(monitor
->object
);
2783 lck_spin_unlock(&perf_monitor_queue_spin
);
2789 * pmc_context_switch performs all context switching necessary to save all pmc
2790 * state associated with @oldThread (and the task to which @oldThread belongs),
2791 * as well as to restore all pmc state associated with @newThread (and the task
2792 * to which @newThread belongs).
2794 * NOTE: This method IS interrupt safe.
2796 boolean_t
pmc_context_switch(thread_t oldThread
, thread_t newThread
) {
2797 pmc_reservation_t resv
= NULL
;
2798 uint32_t cpuNum
= cpu_number();
2800 lck_spin_lock(&reservations_spin
);
2802 /* Save pmc states */
2803 if (thread_reservation_count
) {
2804 queue_iterate(thread_reservations
, resv
, pmc_reservation_t
, link
) {
2805 if ((oldThread
== resv
->thread
) && pmc_accessible_from_core(resv
->pmc
, cpuNum
)) {
2806 (void)pmc_internal_reservation_context_out(resv
);
2811 if (task_reservation_count
) {
2812 queue_iterate(task_reservations
, resv
, pmc_reservation_t
, link
) {
2813 if ((resv
->task
== oldThread
->task
) && pmc_accessible_from_core(resv
->pmc
, cpuNum
)) {
2814 (void)pmc_internal_reservation_context_out(resv
);
2820 if (thread_reservation_count
) {
2821 queue_iterate(thread_reservations
, resv
, pmc_reservation_t
, link
) {
2822 if ((resv
->thread
== newThread
) && pmc_accessible_from_core(resv
->pmc
, cpuNum
)) {
2823 (void)pmc_internal_reservation_context_in(resv
);
2828 if (task_reservation_count
) {
2829 queue_iterate(task_reservations
, resv
, pmc_reservation_t
, link
) {
2830 if ((resv
->task
== newThread
->task
) && pmc_accessible_from_core(resv
->pmc
, cpuNum
)) {
2831 (void)pmc_internal_reservation_context_in(resv
);
2836 lck_spin_unlock(&reservations_spin
);
2841 #else /* !CONFIG_COUNTERS */
2845 #pragma mark Dummy functions
2849 * In the case that someone has chosen not to include the PMC KPI in some
2850 * configuration, we still have exports for kexts, so we'll need to define stub
2851 * methods that return failures.
2853 kern_return_t
perf_monitor_register(perf_monitor_object_t monitor __unused
,
2854 perf_monitor_methods_t
*methods __unused
) {
2855 return KERN_FAILURE
;
2858 kern_return_t
perf_monitor_unregister(perf_monitor_object_t monitor __unused
) {
2859 return KERN_FAILURE
;
2862 kern_return_t
pmc_register(perf_monitor_object_t monitor __unused
,
2863 pmc_object_t pmc __unused
, pmc_methods_t
*methods __unused
, void *object __unused
) {
2864 return KERN_FAILURE
;
2867 kern_return_t
pmc_unregister(perf_monitor_object_t monitor __unused
,
2868 pmc_object_t pmc __unused
) {
2869 return KERN_FAILURE
;
2872 kern_return_t
pmc_create_config(pmc_t pmc __unused
,
2873 pmc_config_t
*config __unused
) {
2874 return KERN_FAILURE
;
2877 void pmc_free_config(pmc_t pmc __unused
, pmc_config_t config __unused
) {
2880 kern_return_t
pmc_config_set_value(pmc_t pmc __unused
,
2881 pmc_config_t config __unused
, uint8_t id __unused
,
2882 uint64_t value __unused
) {
2883 return KERN_FAILURE
;
2886 kern_return_t
pmc_config_set_interrupt_threshold(pmc_t pmc __unused
,
2887 pmc_config_t config __unused
, uint64_t threshold __unused
,
2888 pmc_interrupt_method_t method __unused
, void *refCon __unused
) {
2889 return KERN_FAILURE
;
2892 kern_return_t
pmc_get_pmc_list(pmc_t
**pmcs __unused
, size_t *pmcCount __unused
) {
2893 return KERN_FAILURE
;
2896 void pmc_free_pmc_list(pmc_t
*pmcs __unused
, size_t pmcCount __unused
) {
2899 kern_return_t
pmc_find_by_name(const char *name __unused
, pmc_t
**pmcs __unused
,
2900 size_t *pmcCount __unused
) {
2901 return KERN_FAILURE
;
2904 const char *pmc_get_name(pmc_t pmc __unused
) {
2908 kern_return_t
pmc_get_accessible_core_list(pmc_t pmc __unused
,
2909 uint32_t **logicalCores __unused
, size_t *logicalCoreCt __unused
) {
2910 return KERN_FAILURE
;
2913 kern_return_t
pmc_reserve(pmc_t pmc __unused
,
2914 pmc_config_t config __unused
, pmc_reservation_t
*reservation __unused
) {
2915 return KERN_FAILURE
;
2918 kern_return_t
pmc_reserve_task(pmc_t pmc __unused
,
2919 pmc_config_t config __unused
, task_t task __unused
,
2920 pmc_reservation_t
*reservation __unused
) {
2921 return KERN_FAILURE
;
2924 kern_return_t
pmc_reserve_thread(pmc_t pmc __unused
,
2925 pmc_config_t config __unused
, thread_t thread __unused
,
2926 pmc_reservation_t
*reservation __unused
) {
2927 return KERN_FAILURE
;
2930 kern_return_t
pmc_reservation_start(pmc_reservation_t reservation __unused
) {
2931 return KERN_FAILURE
;
2934 kern_return_t
pmc_reservation_stop(pmc_reservation_t reservation __unused
) {
2935 return KERN_FAILURE
;
2938 kern_return_t
pmc_reservation_read(pmc_reservation_t reservation __unused
,
2939 uint64_t *value __unused
) {
2940 return KERN_FAILURE
;
2943 kern_return_t
pmc_reservation_write(pmc_reservation_t reservation __unused
,
2944 uint64_t value __unused
) {
2945 return KERN_FAILURE
;
2948 kern_return_t
pmc_reservation_free(pmc_reservation_t reservation __unused
) {
2949 return KERN_FAILURE
;
2953 #endif /* !CONFIG_COUNTERS */