xref: /xnu-8019.80.24/osfmk/kern/kern_monotonic.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
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