2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <kern/assert.h>
30 #include <kern/monotonic.h>
31 #include <kern/thread.h>
32 #include <machine/atomic.h>
33 #include <machine/monotonic.h>
34 #include <mach/mach_traps.h>
35 #include <stdatomic.h>
36 #include <sys/errno.h>
38 bool mt_debug
= false;
39 _Atomic
uint64_t mt_pmis
= 0;
40 _Atomic
uint64_t mt_retrograde
= 0;
42 #define MT_KDBG_INSTRS_CYCLES(CODE) \
43 KDBG_EVENTID(DBG_MONOTONIC, DBG_MT_INSTRS_CYCLES, CODE)
45 #define MT_KDBG_IC_CPU_CSWITCH MT_KDBG_INSTRS_CYCLES(1)
48 * Updating the thread counters takes place in the context switch path, so it
49 * cannot introduce too much overhead. Thus, updating takes no locks, instead
50 * updating a generation count to an odd value to indicate that it's in the
51 * critical section and that readers should wait until the generation count
52 * returns to an even value.
54 * Reading the counters also needs to not see any "torn" states of the counters,
55 * where a few of the counters are from a previous state and the rest are from
56 * the current state. For this reason, the reader redrives the entire read
57 * operation if it sees mismatching generation counts at the beginning and end
65 * Write the fixed counter values for the thread `thread` into `counts_out`.
67 * This function does not include the accumulated counter values since the
68 * thread's last context switch or quantum expiration.
71 mt_fixed_thread_counts(thread_t thread
, uint64_t *counts_out
)
73 uint64_t start_gen
, end_gen
;
74 uint64_t spins
= 0, retries
= 0;
75 uint64_t counts
[MT_CORE_NFIXED
];
78 * Try to read a thread's counter values by ensuring its gen count is
79 * even. If it's odd, it means that a thread is trying to update its
82 * Spin until the gen count is even.
85 start_gen
= atomic_load_explicit(&thread
->t_monotonic
.mth_gen
,
86 memory_order_acquire
);
90 if (spins
> MAXSPINS
) {
96 for (int i
= 0; i
< MT_CORE_NFIXED
; i
++) {
97 counts
[i
] = thread
->t_monotonic
.mth_counts
[i
];
101 * After reading the counters, check the gen count again. If it is
102 * different from the value that we started with, the thread raced
103 * writing its counters with us reading them. We need to redrive the
106 * Go back to check if the value we just read was even and try to read
109 end_gen
= atomic_load_explicit(&thread
->t_monotonic
.mth_gen
,
110 memory_order_acquire
);
111 if (end_gen
!= start_gen
) {
113 if (retries
> MAXRETRIES
) {
121 * Only after getting a consistent snapshot of the counters should we
122 * write them into the provided buffer.
124 for (int i
= 0; i
< MT_CORE_NFIXED
; i
++) {
125 counts_out
[i
] = counts
[i
];
130 static void mt_fixed_counts_internal(uint64_t *counts
, uint64_t *counts_since
);
133 mt_update_thread(thread_t thread
)
135 if (!mt_core_supported
) {
139 assert(ml_get_interrupts_enabled() == FALSE
);
141 uint64_t counts
[MT_CORE_NFIXED
], counts_since
[MT_CORE_NFIXED
];
142 mt_fixed_counts_internal(counts
, counts_since
);
145 * Enter the update cycle by incrementing the gen count to be odd --
146 * this tells any readers to spin on the gen count, waiting for it to go
149 __assert_only
uint64_t enter_gen
= atomic_fetch_add_explicit(
150 &thread
->t_monotonic
.mth_gen
, 1, memory_order_release
);
152 * Should not have pre-empted a modification to the counts.
154 assert((enter_gen
& 1) == 0);
156 for (int i
= 0; i
< MT_CORE_NFIXED
; i
++) {
157 thread
->t_monotonic
.mth_counts
[i
] += counts_since
[i
];
161 * Exit the update by making the gen count even again. Readers check
162 * the gen count for equality, and will redrive the reads if the values
163 * before and after reading don't match.
165 __assert_only
uint64_t exit_gen
= atomic_fetch_add_explicit(
166 &thread
->t_monotonic
.mth_gen
, 1, memory_order_release
);
168 * Make sure no other writers came through behind us.
170 assert(exit_gen
== (enter_gen
+ 1));
176 mt_sched_update(thread_t thread
)
178 bool updated
= mt_update_thread(thread
);
183 if (kdebug_debugid_explicitly_enabled(MT_KDBG_IC_CPU_CSWITCH
)) {
184 struct mt_cpu
*mtc
= mt_cur_cpu();
186 KDBG_RELEASE(MT_KDBG_IC_CPU_CSWITCH
,
187 #ifdef MT_CORE_INSTRS
188 mtc
->mtc_counts
[MT_CORE_INSTRS
],
189 #else /* defined(MT_CORE_INSTRS) */
191 #endif /* !defined(MT_CORE_INSTRS) */
192 mtc
->mtc_counts
[MT_CORE_CYCLES
]);
197 mt_fixed_task_counts(task_t task
, uint64_t *counts_out
)
199 assert(task
!= TASK_NULL
);
200 assert(counts_out
!= NULL
);
202 if (!mt_core_supported
) {
203 memset(counts_out
, 0, sizeof(*counts_out
) * MT_CORE_NFIXED
);
209 uint64_t counts
[MT_CORE_NFIXED
] = { 0 };
210 for (int i
= 0; i
< MT_CORE_NFIXED
; i
++) {
211 counts
[i
] = task
->task_monotonic
.mtk_counts
[i
];
214 uint64_t thread_counts
[MT_CORE_NFIXED
] = { 0 };
215 thread_t thread
= THREAD_NULL
;
216 thread_t curthread
= current_thread();
217 bool needs_current
= false;
219 queue_iterate(&task
->threads
, thread
, thread_t
, task_threads
) {
221 * Get the current thread's counters after doing this
222 * processing, without holding the task lock.
224 if (thread
== curthread
) {
225 needs_current
= true;
228 r
= mt_fixed_thread_counts(thread
, thread_counts
);
234 for (int i
= 0; i
< MT_CORE_NFIXED
; i
++) {
235 counts
[i
] += thread_counts
[i
];
242 mt_cur_thread_fixed_counts(thread_counts
);
245 for (int i
= 0; i
< MT_CORE_NFIXED
; i
++) {
247 counts
[i
] += thread_counts
[i
];
249 counts_out
[i
] = counts
[i
];
259 mt_mtc_update_count(struct mt_cpu
*mtc
, unsigned int ctr
)
261 uint64_t snap
= mt_core_snap(ctr
);
262 if (snap
< mtc
->mtc_snaps
[ctr
]) {
264 kprintf("monotonic: cpu %d: thread %#llx: "
265 "retrograde counter %u value: %llu, last read = %llu\n",
266 cpu_number(), thread_tid(current_thread()), ctr
, snap
,
267 mtc
->mtc_snaps
[ctr
]);
269 (void)atomic_fetch_add_explicit(&mt_retrograde
, 1,
270 memory_order_relaxed
);
271 mtc
->mtc_snaps
[ctr
] = snap
;
275 uint64_t count
= snap
- mtc
->mtc_snaps
[ctr
];
276 mtc
->mtc_snaps
[ctr
] = snap
;
282 mt_cpu_update_count(cpu_data_t
*cpu
, unsigned int ctr
)
284 return mt_mtc_update_count(&cpu
->cpu_monotonic
, ctr
);
288 mt_fixed_counts_internal(uint64_t *counts
, uint64_t *counts_since
)
290 assert(ml_get_interrupts_enabled() == FALSE
);
292 struct mt_cpu
*mtc
= mt_cur_cpu();
295 mt_mtc_update_fixed_counts(mtc
, counts
, counts_since
);
299 mt_mtc_update_fixed_counts(struct mt_cpu
*mtc
, uint64_t *counts
,
300 uint64_t *counts_since
)
302 if (!mt_core_supported
) {
306 for (int i
= 0; i
< MT_CORE_NFIXED
; i
++) {
310 last_delta
= mt_mtc_update_count(mtc
, i
);
311 count
= mtc
->mtc_counts
[i
] + last_delta
;
317 assert(counts
!= NULL
);
318 counts_since
[i
] = count
- mtc
->mtc_counts_last
[i
];
319 mtc
->mtc_counts_last
[i
] = count
;
322 mtc
->mtc_counts
[i
] = count
;
327 mt_update_fixed_counts(void)
329 assert(ml_get_interrupts_enabled() == FALSE
);
331 #if defined(__x86_64__)
332 __builtin_ia32_lfence();
333 #elif defined(__arm__) || defined(__arm64__)
334 __builtin_arm_isb(ISB_SY
);
335 #endif /* !defined(__x86_64__) && (defined(__arm__) || defined(__arm64__)) */
337 mt_fixed_counts_internal(NULL
, NULL
);
341 mt_fixed_counts(uint64_t *counts
)
343 #if defined(__x86_64__)
344 __builtin_ia32_lfence();
345 #elif defined(__arm__) || defined(__arm64__)
346 __builtin_arm_isb(ISB_SY
);
347 #endif /* !defined(__x86_64__) && (defined(__arm__) || defined(__arm64__)) */
349 int intrs_en
= ml_set_interrupts_enabled(FALSE
);
350 mt_fixed_counts_internal(counts
, NULL
);
351 ml_set_interrupts_enabled(intrs_en
);
355 mt_cur_thread_fixed_counts(uint64_t *counts
)
357 if (!mt_core_supported
) {
358 memset(counts
, 0, sizeof(*counts
) * MT_CORE_NFIXED
);
362 thread_t curthread
= current_thread();
363 int intrs_en
= ml_set_interrupts_enabled(FALSE
);
364 (void)mt_update_thread(curthread
);
365 for (int i
= 0; i
< MT_CORE_NFIXED
; i
++) {
366 counts
[i
] = curthread
->t_monotonic
.mth_counts
[i
];
368 ml_set_interrupts_enabled(intrs_en
);
372 mt_cur_task_fixed_counts(uint64_t *counts
)
374 task_t curtask
= current_task();
376 mt_fixed_task_counts(curtask
, counts
);
379 /* FIXME these should only update the counter that is being accessed */
382 mt_cur_thread_instrs(void)
384 #ifdef MT_CORE_INSTRS
385 thread_t curthread
= current_thread();
389 if (!mt_core_supported
) {
393 intrs_en
= ml_set_interrupts_enabled(FALSE
);
394 (void)mt_update_thread(curthread
);
395 count
= curthread
->t_monotonic
.mth_counts
[MT_CORE_INSTRS
];
396 ml_set_interrupts_enabled(intrs_en
);
399 #else /* defined(MT_CORE_INSTRS) */
401 #endif /* !defined(MT_CORE_INSTRS) */
405 mt_cur_thread_cycles(void)
407 thread_t curthread
= current_thread();
411 if (!mt_core_supported
) {
415 intrs_en
= ml_set_interrupts_enabled(FALSE
);
416 (void)mt_update_thread(curthread
);
417 count
= curthread
->t_monotonic
.mth_counts
[MT_CORE_CYCLES
];
418 ml_set_interrupts_enabled(intrs_en
);
424 mt_cur_cpu_instrs(void)
426 #ifdef MT_CORE_INSTRS
427 uint64_t counts
[MT_CORE_NFIXED
];
429 if (!mt_core_supported
) {
433 mt_fixed_counts(counts
);
434 return counts
[MT_CORE_INSTRS
];
435 #else /* defined(MT_CORE_INSTRS) */
437 #endif /* !defined(MT_CORE_INSTRS) */
441 mt_cur_cpu_cycles(void)
443 uint64_t counts
[MT_CORE_NFIXED
];
445 if (!mt_core_supported
) {
449 mt_fixed_counts(counts
);
450 return counts
[MT_CORE_CYCLES
];
454 mt_update_task(task_t task
, thread_t thread
)
456 task_lock_assert_owned(task
);
458 if (!mt_core_supported
) {
462 for (int i
= 0; i
< MT_CORE_NFIXED
; i
++) {
463 task
->task_monotonic
.mtk_counts
[i
] += thread
->t_monotonic
.mth_counts
[i
];
468 mt_terminate_update(task_t task
, thread_t thread
)
470 mt_update_task(task
, thread
);
474 mt_perfcontrol(uint64_t *instrs
, uint64_t *cycles
)
476 if (!mt_core_supported
) {
482 struct mt_cpu
*mtc
= mt_cur_cpu();
485 * The performance controller queries the hardware directly, so provide the
486 * last snapshot we took for the core. This is the value from when we
487 * updated the thread counts.
490 #ifdef MT_CORE_INSTRS
491 *instrs
= mtc
->mtc_snaps
[MT_CORE_INSTRS
];
492 #else /* defined(MT_CORE_INSTRS) */
494 #endif /* !defined(MT_CORE_INSTRS) */
496 *cycles
= mtc
->mtc_snaps
[MT_CORE_CYCLES
];
500 mt_stackshot_thread(thread_t thread
, uint64_t *instrs
, uint64_t *cycles
)
502 assert(mt_core_supported
);
504 #ifdef MT_CORE_INSTRS
505 *instrs
= thread
->t_monotonic
.mth_counts
[MT_CORE_INSTRS
];
506 #else /* defined(MT_CORE_INSTRS) */
508 #endif /* !defined(MT_CORE_INSTRS) */
510 *cycles
= thread
->t_monotonic
.mth_counts
[MT_CORE_CYCLES
];
514 mt_stackshot_task(task_t task
, uint64_t *instrs
, uint64_t *cycles
)
516 assert(mt_core_supported
);
518 #ifdef MT_CORE_INSTRS
519 *instrs
= task
->task_monotonic
.mtk_counts
[MT_CORE_INSTRS
];
520 #else /* defined(MT_CORE_INSTRS) */
522 #endif /* !defined(MT_CORE_INSTRS) */
524 *cycles
= task
->task_monotonic
.mtk_counts
[MT_CORE_CYCLES
];
528 * Maintain reset values for the fixed instruction and cycle counters so
529 * clients can be notified after a given number of those events occur. This is
530 * only used by microstackshot.
533 bool mt_microstackshots
= false;
534 unsigned int mt_microstackshot_ctr
= 0;
535 mt_pmi_fn mt_microstackshot_pmi_handler
= NULL
;
536 void *mt_microstackshot_ctx
= NULL
;
537 uint64_t mt_core_reset_values
[MT_CORE_NFIXED
] = { 0 };
539 #define MT_MIN_FIXED_PERIOD (10 * 1000 * 1000)
542 mt_microstackshot_start(unsigned int ctr
, uint64_t period
, mt_pmi_fn handler
,
545 assert(ctr
< MT_CORE_NFIXED
);
547 if (period
< MT_MIN_FIXED_PERIOD
) {
550 if (mt_microstackshots
) {
554 mt_microstackshot_ctr
= ctr
;
555 mt_microstackshot_pmi_handler
= handler
;
556 mt_microstackshot_ctx
= ctx
;
558 int error
= mt_microstackshot_start_arch(period
);
560 mt_microstackshot_ctr
= 0;
561 mt_microstackshot_pmi_handler
= NULL
;
562 mt_microstackshot_ctx
= NULL
;
566 mt_microstackshots
= true;
572 mt_microstackshot_stop(void)
574 mt_microstackshots
= false;
575 memset(mt_core_reset_values
, 0, sizeof(mt_core_reset_values
));