1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. 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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <kern/assert.h>
30 #include <kern/kpc.h>
31 #include <kern/monotonic.h>
32 #include <kern/thread.h>
33 #include <machine/atomic.h>
34 #include <machine/monotonic.h>
35 #include <mach/mach_traps.h>
36 #include <stdatomic.h>
37 #include <sys/errno.h>
38
39 bool mt_debug = false;
40 _Atomic uint64_t mt_pmis = 0;
41 _Atomic uint64_t mt_retrograde = 0;
42
43 #define MT_KDBG_INSTRS_CYCLES(CODE) \
44 KDBG_EVENTID(DBG_MONOTONIC, DBG_MT_INSTRS_CYCLES, CODE)
45
46 #define MT_KDBG_IC_CPU_CSWITCH MT_KDBG_INSTRS_CYCLES(1)
47
48 /*
49 * Updating the thread counters takes place in the context switch path, so it
50 * cannot introduce too much overhead. Thus, updating takes no locks, instead
51 * updating a generation count to an odd value to indicate that it's in the
52 * critical section and that readers should wait until the generation count
53 * returns to an even value.
54 *
55 * Reading the counters also needs to not see any "torn" states of the counters,
56 * where a few of the counters are from a previous state and the rest are from
57 * the current state. For this reason, the reader redrives the entire read
58 * operation if it sees mismatching generation counts at the beginning and end
59 * of reading.
60 */
61
62 #define MAXSPINS 100
63 #define MAXRETRIES 10
64
65 /*
66 * Write the fixed counter values for the thread `thread` into `counts_out`.
67 *
68 * This function does not include the accumulated counter values since the
69 * thread's last context switch or quantum expiration.
70 */
71 int
mt_fixed_thread_counts(thread_t thread,uint64_t * counts_out)72 mt_fixed_thread_counts(thread_t thread, uint64_t *counts_out)
73 {
74 uint64_t start_gen, end_gen;
75 uint64_t spins = 0, retries = 0;
76 uint64_t counts[MT_CORE_NFIXED];
77
78 /*
79 * Try to read a thread's counter values by ensuring its gen count is
80 * even. If it's odd, it means that a thread is trying to update its
81 * counters.
82 *
83 * Spin until the gen count is even.
84 */
85 spin:
86 start_gen = atomic_load_explicit(&thread->t_monotonic.mth_gen,
87 memory_order_acquire);
88 retry:
89 if (start_gen & 1) {
90 spins++;
91 if (spins > MAXSPINS) {
92 return EBUSY;
93 }
94 goto spin;
95 }
96
97 for (int i = 0; i < MT_CORE_NFIXED; i++) {
98 counts[i] = thread->t_monotonic.mth_counts[i];
99 }
100
101 /*
102 * After reading the counters, check the gen count again. If it is
103 * different from the value that we started with, the thread raced
104 * writing its counters with us reading them. We need to redrive the
105 * entire operation.
106 *
107 * Go back to check if the value we just read was even and try to read
108 * again.
109 */
110 end_gen = atomic_load_explicit(&thread->t_monotonic.mth_gen,
111 memory_order_acquire);
112 if (end_gen != start_gen) {
113 retries++;
114 if (retries > MAXRETRIES) {
115 return EAGAIN;
116 }
117 start_gen = end_gen;
118 goto retry;
119 }
120
121 /*
122 * Only after getting a consistent snapshot of the counters should we
123 * write them into the provided buffer.
124 */
125 for (int i = 0; i < MT_CORE_NFIXED; i++) {
126 counts_out[i] = counts[i];
127 }
128 return 0;
129 }
130
131 static void mt_fixed_counts_internal(uint64_t *counts, uint64_t *counts_since);
132
133 bool
mt_update_thread(thread_t thread)134 mt_update_thread(thread_t thread)
135 {
136 if (!mt_core_supported) {
137 return false;
138 }
139
140 assert(ml_get_interrupts_enabled() == FALSE);
141
142 uint64_t counts[MT_CORE_NFIXED], counts_since[MT_CORE_NFIXED];
143 mt_fixed_counts_internal(counts, counts_since);
144
145 /*
146 * Enter the update cycle by incrementing the gen count to be odd --
147 * this tells any readers to spin on the gen count, waiting for it to go
148 * even.
149 */
150 __assert_only uint64_t enter_gen = atomic_fetch_add_explicit(
151 &thread->t_monotonic.mth_gen, 1, memory_order_release);
152 /*
153 * Should not have pre-empted a modification to the counts.
154 */
155 assert((enter_gen & 1) == 0);
156
157 for (int i = 0; i < MT_CORE_NFIXED; i++) {
158 thread->t_monotonic.mth_counts[i] += counts_since[i];
159 }
160
161 /*
162 * Exit the update by making the gen count even again. Readers check
163 * the gen count for equality, and will redrive the reads if the values
164 * before and after reading don't match.
165 */
166 __assert_only uint64_t exit_gen = atomic_fetch_add_explicit(
167 &thread->t_monotonic.mth_gen, 1, memory_order_release);
168 /*
169 * Make sure no other writers came through behind us.
170 */
171 assert(exit_gen == (enter_gen + 1));
172
173 return true;
174 }
175
176 void
mt_sched_update(thread_t thread)177 mt_sched_update(thread_t thread)
178 {
179 bool updated = mt_update_thread(thread);
180 if (!updated) {
181 return;
182 }
183
184 if (kdebug_debugid_explicitly_enabled(MT_KDBG_IC_CPU_CSWITCH)) {
185 struct mt_cpu *mtc = mt_cur_cpu();
186
187 KDBG_RELEASE(MT_KDBG_IC_CPU_CSWITCH,
188 #ifdef MT_CORE_INSTRS
189 mtc->mtc_counts[MT_CORE_INSTRS],
190 #else /* defined(MT_CORE_INSTRS) */
191 0,
192 #endif /* !defined(MT_CORE_INSTRS) */
193 mtc->mtc_counts[MT_CORE_CYCLES]);
194 }
195 }
196
197 int
mt_fixed_task_counts(task_t task,uint64_t * counts_out)198 mt_fixed_task_counts(task_t task, uint64_t *counts_out)
199 {
200 assert(task != TASK_NULL);
201 assert(counts_out != NULL);
202
203 if (!mt_core_supported) {
204 memset(counts_out, 0, sizeof(*counts_out) * MT_CORE_NFIXED);
205 return 1;
206 }
207
208 task_lock(task);
209
210 uint64_t counts[MT_CORE_NFIXED] = { 0 };
211 for (int i = 0; i < MT_CORE_NFIXED; i++) {
212 counts[i] = task->task_monotonic.mtk_counts[i];
213 }
214
215 uint64_t thread_counts[MT_CORE_NFIXED] = { 0 };
216 thread_t thread = THREAD_NULL;
217 thread_t curthread = current_thread();
218 bool needs_current = false;
219 int r = 0;
220 queue_iterate(&task->threads, thread, thread_t, task_threads) {
221 /*
222 * Get the current thread's counters after doing this
223 * processing, without holding the task lock.
224 */
225 if (thread == curthread) {
226 needs_current = true;
227 continue;
228 } else {
229 r = mt_fixed_thread_counts(thread, thread_counts);
230 if (r) {
231 goto error;
232 }
233 }
234
235 for (int i = 0; i < MT_CORE_NFIXED; i++) {
236 counts[i] += thread_counts[i];
237 }
238 }
239
240 task_unlock(task);
241
242 if (needs_current) {
243 mt_cur_thread_fixed_counts(thread_counts);
244 }
245
246 for (int i = 0; i < MT_CORE_NFIXED; i++) {
247 if (needs_current) {
248 counts[i] += thread_counts[i];
249 }
250 counts_out[i] = counts[i];
251 }
252 return 0;
253
254 error:
255 task_unlock(task);
256 return r;
257 }
258
259 uint64_t
mt_mtc_update_count(struct mt_cpu * mtc,unsigned int ctr)260 mt_mtc_update_count(struct mt_cpu *mtc, unsigned int ctr)
261 {
262 uint64_t snap = mt_core_snap(ctr);
263 if (snap < mtc->mtc_snaps[ctr]) {
264 if (mt_debug) {
265 kprintf("monotonic: cpu %d: thread %#llx: "
266 "retrograde counter %u value: %llu, last read = %llu\n",
267 cpu_number(), thread_tid(current_thread()), ctr, snap,
268 mtc->mtc_snaps[ctr]);
269 }
270 (void)atomic_fetch_add_explicit(&mt_retrograde, 1,
271 memory_order_relaxed);
272 mtc->mtc_snaps[ctr] = snap;
273 return 0;
274 }
275
276 uint64_t count = snap - mtc->mtc_snaps[ctr];
277 mtc->mtc_snaps[ctr] = snap;
278
279 return count;
280 }
281
282 uint64_t
mt_cpu_update_count(cpu_data_t * cpu,unsigned int ctr)283 mt_cpu_update_count(cpu_data_t *cpu, unsigned int ctr)
284 {
285 return mt_mtc_update_count(&cpu->cpu_monotonic, ctr);
286 }
287
288 static void
mt_fixed_counts_internal(uint64_t * counts,uint64_t * counts_since)289 mt_fixed_counts_internal(uint64_t *counts, uint64_t *counts_since)
290 {
291 assert(ml_get_interrupts_enabled() == FALSE);
292
293 struct mt_cpu *mtc = mt_cur_cpu();
294 assert(mtc != NULL);
295
296 mt_mtc_update_fixed_counts(mtc, counts, counts_since);
297 }
298
299 void
mt_mtc_update_fixed_counts(struct mt_cpu * mtc,uint64_t * counts,uint64_t * counts_since)300 mt_mtc_update_fixed_counts(struct mt_cpu *mtc, uint64_t *counts,
301 uint64_t *counts_since)
302 {
303 if (!mt_core_supported) {
304 return;
305 }
306
307 for (int i = 0; i < (int) kpc_fixed_count(); i++) {
308 uint64_t last_delta;
309 uint64_t count;
310
311 last_delta = mt_mtc_update_count(mtc, i);
312 count = mtc->mtc_counts[i] + last_delta;
313
314 if (counts) {
315 counts[i] = count;
316 }
317 if (counts_since) {
318 assert(counts != NULL);
319 counts_since[i] = count - mtc->mtc_counts_last[i];
320 mtc->mtc_counts_last[i] = count;
321 }
322
323 mtc->mtc_counts[i] = count;
324 }
325 }
326
327 void
mt_update_fixed_counts(void)328 mt_update_fixed_counts(void)
329 {
330 assert(ml_get_interrupts_enabled() == FALSE);
331
332 #if defined(__x86_64__)
333 __builtin_ia32_lfence();
334 #elif defined(__arm__) || defined(__arm64__)
335 __builtin_arm_isb(ISB_SY);
336 #endif /* !defined(__x86_64__) && (defined(__arm__) || defined(__arm64__)) */
337
338 mt_fixed_counts_internal(NULL, NULL);
339 }
340
341 void
mt_fixed_counts(uint64_t * counts)342 mt_fixed_counts(uint64_t *counts)
343 {
344 #if defined(__x86_64__)
345 __builtin_ia32_lfence();
346 #elif defined(__arm__) || defined(__arm64__)
347 __builtin_arm_isb(ISB_SY);
348 #endif /* !defined(__x86_64__) && (defined(__arm__) || defined(__arm64__)) */
349
350 int intrs_en = ml_set_interrupts_enabled(FALSE);
351 mt_fixed_counts_internal(counts, NULL);
352 ml_set_interrupts_enabled(intrs_en);
353 }
354
355 void
mt_cur_thread_fixed_counts(uint64_t * counts)356 mt_cur_thread_fixed_counts(uint64_t *counts)
357 {
358 if (!mt_core_supported) {
359 memset(counts, 0, sizeof(*counts) * MT_CORE_NFIXED);
360 return;
361 }
362
363 thread_t curthread = current_thread();
364 int intrs_en = ml_set_interrupts_enabled(FALSE);
365 (void)mt_update_thread(curthread);
366 for (int i = 0; i < MT_CORE_NFIXED; i++) {
367 counts[i] = curthread->t_monotonic.mth_counts[i];
368 }
369 ml_set_interrupts_enabled(intrs_en);
370 }
371
372 void
mt_cur_task_fixed_counts(uint64_t * counts)373 mt_cur_task_fixed_counts(uint64_t *counts)
374 {
375 task_t curtask = current_task();
376
377 mt_fixed_task_counts(curtask, counts);
378 }
379
380 /* FIXME these should only update the counter that is being accessed */
381
382 uint64_t
mt_cur_thread_instrs(void)383 mt_cur_thread_instrs(void)
384 {
385 #ifdef MT_CORE_INSTRS
386 thread_t curthread = current_thread();
387 boolean_t intrs_en;
388 uint64_t count;
389
390 if (!mt_core_supported) {
391 return 0;
392 }
393
394 intrs_en = ml_set_interrupts_enabled(FALSE);
395 (void)mt_update_thread(curthread);
396 count = curthread->t_monotonic.mth_counts[MT_CORE_INSTRS];
397 ml_set_interrupts_enabled(intrs_en);
398
399 return count;
400 #else /* defined(MT_CORE_INSTRS) */
401 return 0;
402 #endif /* !defined(MT_CORE_INSTRS) */
403 }
404
405 uint64_t
mt_cur_thread_cycles(void)406 mt_cur_thread_cycles(void)
407 {
408 thread_t curthread = current_thread();
409 boolean_t intrs_en;
410 uint64_t count;
411
412 if (!mt_core_supported) {
413 return 0;
414 }
415
416 intrs_en = ml_set_interrupts_enabled(FALSE);
417 (void)mt_update_thread(curthread);
418 count = curthread->t_monotonic.mth_counts[MT_CORE_CYCLES];
419 ml_set_interrupts_enabled(intrs_en);
420
421 return count;
422 }
423
424 uint64_t
mt_cur_cpu_instrs(void)425 mt_cur_cpu_instrs(void)
426 {
427 #ifdef MT_CORE_INSTRS
428 uint64_t counts[MT_CORE_NFIXED];
429
430 if (!mt_core_supported) {
431 return 0;
432 }
433
434 mt_fixed_counts(counts);
435 return counts[MT_CORE_INSTRS];
436 #else /* defined(MT_CORE_INSTRS) */
437 return 0;
438 #endif /* !defined(MT_CORE_INSTRS) */
439 }
440
441 uint64_t
mt_cur_cpu_cycles(void)442 mt_cur_cpu_cycles(void)
443 {
444 uint64_t counts[MT_CORE_NFIXED];
445
446 if (!mt_core_supported) {
447 return 0;
448 }
449
450 mt_fixed_counts(counts);
451 return counts[MT_CORE_CYCLES];
452 }
453
454 void
mt_cur_cpu_cycles_instrs_speculative(uint64_t * cycles,__unused uint64_t * instrs)455 mt_cur_cpu_cycles_instrs_speculative(uint64_t *cycles, __unused uint64_t *instrs)
456 {
457 uint64_t counts[MT_CORE_NFIXED];
458 struct mt_cpu *mtc = mt_cur_cpu();
459
460 assert(ml_get_interrupts_enabled() == FALSE);
461 assert(mtc != NULL);
462
463 mt_mtc_update_fixed_counts(mtc, counts, NULL);
464
465 *cycles = counts[MT_CORE_CYCLES];
466
467 #ifdef MT_CORE_INSTRS
468 *instrs = counts[MT_CORE_INSTRS];
469 #endif
470 }
471
472 void
mt_update_task(task_t task,thread_t thread)473 mt_update_task(task_t task, thread_t thread)
474 {
475 task_lock_assert_owned(task);
476
477 if (!mt_core_supported) {
478 return;
479 }
480
481 for (int i = 0; i < MT_CORE_NFIXED; i++) {
482 task->task_monotonic.mtk_counts[i] += thread->t_monotonic.mth_counts[i];
483 }
484 }
485
486 void
mt_terminate_update(task_t task,thread_t thread)487 mt_terminate_update(task_t task, thread_t thread)
488 {
489 mt_update_task(task, thread);
490 }
491
492 void
mt_perfcontrol(uint64_t * instrs,uint64_t * cycles)493 mt_perfcontrol(uint64_t *instrs, uint64_t *cycles)
494 {
495 if (!mt_core_supported) {
496 *instrs = 0;
497 *cycles = 0;
498 return;
499 }
500
501 struct mt_cpu *mtc = mt_cur_cpu();
502
503 /*
504 * The performance controller queries the hardware directly, so provide the
505 * last snapshot we took for the core. This is the value from when we
506 * updated the thread counts.
507 */
508
509 #ifdef MT_CORE_INSTRS
510 *instrs = mtc->mtc_snaps[MT_CORE_INSTRS];
511 #else /* defined(MT_CORE_INSTRS) */
512 *instrs = 0;
513 #endif /* !defined(MT_CORE_INSTRS) */
514
515 *cycles = mtc->mtc_snaps[MT_CORE_CYCLES];
516 }
517
518 bool
mt_acquire_counters(void)519 mt_acquire_counters(void)
520 {
521 if (kpc_get_force_all_ctrs()) {
522 return false;
523 }
524 kpc_force_all_ctrs(current_task(), 1);
525 return true;
526 }
527
528 bool
mt_owns_counters(void)529 mt_owns_counters(void)
530 {
531 return kpc_get_force_all_ctrs();
532 }
533
534 void
mt_release_counters(void)535 mt_release_counters(void)
536 {
537 if (kpc_get_force_all_ctrs()) {
538 kpc_force_all_ctrs(current_task(), 0);
539 }
540 }
541
542 void
mt_stackshot_thread(thread_t thread,uint64_t * instrs,uint64_t * cycles)543 mt_stackshot_thread(thread_t thread, uint64_t *instrs, uint64_t *cycles)
544 {
545 assert(mt_core_supported);
546
547 #ifdef MT_CORE_INSTRS
548 *instrs = thread->t_monotonic.mth_counts[MT_CORE_INSTRS];
549 #else /* defined(MT_CORE_INSTRS) */
550 *instrs = 0;
551 #endif /* !defined(MT_CORE_INSTRS) */
552
553 *cycles = thread->t_monotonic.mth_counts[MT_CORE_CYCLES];
554 }
555
556 void
mt_stackshot_task(task_t task,uint64_t * instrs,uint64_t * cycles)557 mt_stackshot_task(task_t task, uint64_t *instrs, uint64_t *cycles)
558 {
559 assert(mt_core_supported);
560
561 #ifdef MT_CORE_INSTRS
562 *instrs = task->task_monotonic.mtk_counts[MT_CORE_INSTRS];
563 #else /* defined(MT_CORE_INSTRS) */
564 *instrs = 0;
565 #endif /* !defined(MT_CORE_INSTRS) */
566
567 *cycles = task->task_monotonic.mtk_counts[MT_CORE_CYCLES];
568 }
569
570 /*
571 * Maintain reset values for the fixed instruction and cycle counters so
572 * clients can be notified after a given number of those events occur. This is
573 * only used by microstackshot.
574 */
575
576 bool mt_microstackshots = false;
577 unsigned int mt_microstackshot_ctr = 0;
578 mt_pmi_fn mt_microstackshot_pmi_handler = NULL;
579 void *mt_microstackshot_ctx = NULL;
580 uint64_t mt_core_reset_values[MT_CORE_NFIXED] = { 0 };
581
582 #define MT_MIN_FIXED_PERIOD (10 * 1000 * 1000)
583
584 int
mt_microstackshot_start(unsigned int ctr,uint64_t period,mt_pmi_fn handler,void * ctx)585 mt_microstackshot_start(unsigned int ctr, uint64_t period, mt_pmi_fn handler,
586 void *ctx)
587 {
588 assert(ctr < MT_CORE_NFIXED);
589
590 if (period < MT_MIN_FIXED_PERIOD) {
591 return EINVAL;
592 }
593 if (mt_microstackshots) {
594 return EBUSY;
595 }
596
597 mt_microstackshot_ctr = ctr;
598 mt_microstackshot_pmi_handler = handler;
599 mt_microstackshot_ctx = ctx;
600
601 int error = mt_microstackshot_start_arch(period);
602 if (error) {
603 mt_microstackshot_ctr = 0;
604 mt_microstackshot_pmi_handler = NULL;
605 mt_microstackshot_ctx = NULL;
606 return error;
607 }
608
609 mt_microstackshots = true;
610
611 return 0;
612 }
613
614 int
mt_microstackshot_stop(void)615 mt_microstackshot_stop(void)
616 {
617 mt_microstackshots = false;
618 memset(mt_core_reset_values, 0, sizeof(mt_core_reset_values));
619
620 return 0;
621 }
622