2 * Copyright (c) 2011 Apple Computer, 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@
31 #include <mach/mach_types.h>
32 #include <kern/cpu_data.h> /* current_thread() */
33 #include <kern/kalloc.h>
34 #include <stdatomic.h>
35 #include <sys/errno.h>
37 #include <sys/ktrace.h>
39 #include <machine/machine_routines.h>
40 #if defined(__x86_64__)
42 #endif /* defined(__x86_64__) */
44 #include <kperf/kperf.h>
45 #include <kperf/buffer.h>
46 #include <kperf/context.h>
47 #include <kperf/action.h>
48 #include <kperf/kperf_timer.h>
49 #include <kperf/kperf_arch.h>
50 #include <kperf/pet.h>
51 #include <kperf/sample.h>
53 /* the list of timers */
54 struct kperf_timer
*kperf_timerv
= NULL
;
55 unsigned int kperf_timerc
= 0;
57 static unsigned int pet_timer_id
= 999;
59 /* maximum number of timers we can construct */
60 #define TIMER_MAX (16)
62 static uint64_t min_period_abstime
;
63 static uint64_t min_period_bg_abstime
;
64 static uint64_t min_period_pet_abstime
;
65 static uint64_t min_period_pet_bg_abstime
;
68 kperf_timer_min_period_abstime(void)
70 if (ktrace_background_active()) {
71 return min_period_bg_abstime
;
73 return min_period_abstime
;
78 kperf_timer_min_pet_period_abstime(void)
80 if (ktrace_background_active()) {
81 return min_period_pet_bg_abstime
;
83 return min_period_pet_abstime
;
88 kperf_timer_schedule(struct kperf_timer
*timer
, uint64_t now
)
90 BUF_INFO(PERF_TM_SCHED
, timer
->period
);
92 /* if we re-programmed the timer to zero, just drop it */
93 if (timer
->period
== 0) {
97 /* calculate deadline */
98 uint64_t deadline
= now
+ timer
->period
;
100 /* re-schedule the timer, making sure we don't apply slop */
101 timer_call_enter(&timer
->tcall
, deadline
, TIMER_CALL_SYS_CRITICAL
);
105 kperf_sample_cpu(struct kperf_timer
*timer
, bool system_sample
,
108 assert(timer
!= NULL
);
110 /* Always cut a tracepoint to show a sample event occurred */
111 BUF_DATA(PERF_TM_HNDLR
| DBG_FUNC_START
, 0);
113 int ncpu
= cpu_number();
115 struct kperf_sample
*intbuf
= kperf_intr_sample_buffer();
116 #if DEVELOPMENT || DEBUG
117 intbuf
->sample_time
= mach_absolute_time();
118 #endif /* DEVELOPMENT || DEBUG */
120 /* On a timer, we can see the "real" current thread */
121 struct kperf_context ctx
= {
122 .cur_thread
= current_thread(),
123 .trigger_type
= TRIGGER_TYPE_TIMER
,
124 .trigger_id
= (unsigned int)(timer
- kperf_timerv
),
126 ctx
.cur_pid
= task_pid(get_threadtask(ctx
.cur_thread
));
128 if (ctx
.trigger_id
== pet_timer_id
&& ncpu
< machine_info
.logical_cpu_max
) {
129 kperf_tid_on_cpus
[ncpu
] = thread_tid(ctx
.cur_thread
);
132 /* make sure sampling is on */
133 unsigned int status
= kperf_sampling_status();
134 if (status
== KPERF_SAMPLING_OFF
) {
135 BUF_INFO(PERF_TM_HNDLR
| DBG_FUNC_END
, SAMPLE_OFF
);
137 } else if (status
== KPERF_SAMPLING_SHUTDOWN
) {
138 BUF_INFO(PERF_TM_HNDLR
| DBG_FUNC_END
, SAMPLE_SHUTDOWN
);
142 /* call the action -- kernel-only from interrupt, pend user */
143 int r
= kperf_sample(intbuf
, &ctx
, timer
->actionid
,
144 SAMPLE_FLAG_PEND_USER
| (system_sample
? SAMPLE_FLAG_SYSTEM
: 0) |
145 (only_system
? SAMPLE_FLAG_ONLY_SYSTEM
: 0));
147 /* end tracepoint is informational */
148 BUF_INFO(PERF_TM_HNDLR
| DBG_FUNC_END
, r
);
150 (void)atomic_fetch_and_explicit(&timer
->pending_cpus
,
151 ~(UINT64_C(1) << ncpu
), memory_order_relaxed
);
155 kperf_ipi_handler(void *param
)
157 kperf_sample_cpu((struct kperf_timer
*)param
, false, false);
161 kperf_timer_handler(void *param0
, __unused
void *param1
)
163 struct kperf_timer
*timer
= param0
;
164 unsigned int ntimer
= (unsigned int)(timer
- kperf_timerv
);
165 unsigned int ncpus
= machine_info
.logical_cpu_max
;
166 bool system_only_self
= true;
168 if (timer
->actionid
== 0) {
173 #if DEVELOPMENT || DEBUG
174 timer
->fire_time
= mach_absolute_time();
175 #endif /* DEVELOPMENT || DEBUG */
177 /* along the lines of do not ipi if we are all shutting down */
178 if (kperf_sampling_status() == KPERF_SAMPLING_SHUTDOWN
) {
182 BUF_DATA(PERF_TM_FIRE
, ntimer
, ntimer
== pet_timer_id
, timer
->period
,
185 if (ntimer
== pet_timer_id
) {
186 kperf_pet_fire_before();
188 /* clean-up the thread-on-CPUs cache */
189 bzero(kperf_tid_on_cpus
, ncpus
* sizeof(*kperf_tid_on_cpus
));
193 * IPI other cores only if the action has non-system samplers.
195 if (kperf_sample_has_non_system(timer
->actionid
)) {
197 * If the core that's handling the timer is not scheduling
198 * threads, only run system samplers.
200 system_only_self
= kperf_mp_broadcast_other_running(timer
);
202 kperf_sample_cpu(timer
, true, system_only_self
);
204 /* release the pet thread? */
205 if (ntimer
== pet_timer_id
) {
206 /* PET mode is responsible for rearming the timer */
207 kperf_pet_fire_after();
210 * FIXME: Get the current time from elsewhere. The next
211 * timer's period now includes the time taken to reach this
212 * point. This causes a bias towards longer sampling periods
215 kperf_timer_schedule(timer
, mach_absolute_time());
222 /* program the timer from the PET thread */
224 kperf_timer_pet_rearm(uint64_t elapsed_ticks
)
226 struct kperf_timer
*timer
= NULL
;
231 * If the pet_timer_id is invalid, it has been disabled, so this should
234 if (pet_timer_id
>= kperf_timerc
) {
238 unsigned int status
= kperf_sampling_status();
239 /* do not reprogram the timer if it has been shutdown or sampling is off */
240 if (status
== KPERF_SAMPLING_OFF
) {
241 BUF_INFO(PERF_PET_END
, SAMPLE_OFF
);
243 } else if (status
== KPERF_SAMPLING_SHUTDOWN
) {
244 BUF_INFO(PERF_PET_END
, SAMPLE_SHUTDOWN
);
248 timer
= &(kperf_timerv
[pet_timer_id
]);
250 /* if we re-programmed the timer to zero, just drop it */
251 if (!timer
->period
) {
255 /* subtract the time the pet sample took being careful not to underflow */
256 if (timer
->period
> elapsed_ticks
) {
257 period
= timer
->period
- elapsed_ticks
;
260 /* make sure we don't set the next PET sample to happen too soon */
261 if (period
< min_period_pet_abstime
) {
262 period
= min_period_pet_abstime
;
265 /* we probably took so long in the PET thread, it makes sense to take
268 deadline
= mach_absolute_time() + period
;
270 BUF_INFO(PERF_PET_SCHED
, timer
->period
, period
, elapsed_ticks
, deadline
);
272 /* re-schedule the timer, making sure we don't apply slop */
273 timer_call_enter(&timer
->tcall
, deadline
, TIMER_CALL_SYS_CRITICAL
);
278 /* turn on all the timers */
282 /* get the PET thread going */
283 if (pet_timer_id
< kperf_timerc
) {
284 kperf_pet_config(kperf_timerv
[pet_timer_id
].actionid
);
287 uint64_t now
= mach_absolute_time();
289 for (unsigned int i
= 0; i
< kperf_timerc
; i
++) {
290 if (kperf_timerv
[i
].period
== 0) {
294 kperf_timer_schedule(&(kperf_timerv
[i
]), now
);
299 kperf_timer_stop(void)
301 for (unsigned int i
= 0; i
< kperf_timerc
; i
++) {
302 if (kperf_timerv
[i
].period
== 0) {
306 /* wait for the timer to stop */
307 while (kperf_timerv
[i
].active
);
309 timer_call_cancel(&kperf_timerv
[i
].tcall
);
312 /* wait for PET to stop, too */
317 kperf_timer_get_petid(void)
323 kperf_timer_set_petid(unsigned int timerid
)
325 if (timerid
< kperf_timerc
) {
328 min_period
= kperf_timer_min_pet_period_abstime();
329 if (kperf_timerv
[timerid
].period
< min_period
) {
330 kperf_timerv
[timerid
].period
= min_period
;
332 kperf_pet_config(kperf_timerv
[timerid
].actionid
);
334 /* clear the PET trigger if it's a bogus ID */
338 pet_timer_id
= timerid
;
344 kperf_timer_get_period(unsigned int timerid
, uint64_t *period_abstime
)
346 if (timerid
>= kperf_timerc
) {
350 *period_abstime
= kperf_timerv
[timerid
].period
;
355 kperf_timer_set_period(unsigned int timerid
, uint64_t period_abstime
)
359 if (timerid
>= kperf_timerc
) {
363 if (pet_timer_id
== timerid
) {
364 min_period
= kperf_timer_min_pet_period_abstime();
366 min_period
= kperf_timer_min_period_abstime();
369 if (period_abstime
> 0 && period_abstime
< min_period
) {
370 period_abstime
= min_period
;
373 kperf_timerv
[timerid
].period
= period_abstime
;
375 /* FIXME: re-program running timers? */
381 kperf_timer_get_action(unsigned int timerid
, uint32_t *action
)
383 if (timerid
>= kperf_timerc
) {
387 *action
= kperf_timerv
[timerid
].actionid
;
392 kperf_timer_set_action(unsigned int timerid
, uint32_t action
)
394 if (timerid
>= kperf_timerc
) {
398 kperf_timerv
[timerid
].actionid
= action
;
403 kperf_timer_get_count(void)
409 kperf_timer_reset(void)
411 kperf_timer_set_petid(999);
412 kperf_set_pet_idle_rate(KPERF_PET_DEFAULT_IDLE_RATE
);
413 kperf_set_lightweight_pet(0);
414 for (unsigned int i
= 0; i
< kperf_timerc
; i
++) {
415 kperf_timerv
[i
].period
= 0;
416 kperf_timerv
[i
].actionid
= 0;
417 kperf_timerv
[i
].pending_cpus
= 0;
422 kperf_timer_set_count(unsigned int count
)
424 struct kperf_timer
*new_timerv
= NULL
, *old_timerv
= NULL
;
425 unsigned int old_count
;
427 if (min_period_abstime
== 0) {
428 nanoseconds_to_absolutetime(KP_MIN_PERIOD_NS
, &min_period_abstime
);
429 nanoseconds_to_absolutetime(KP_MIN_PERIOD_BG_NS
, &min_period_bg_abstime
);
430 nanoseconds_to_absolutetime(KP_MIN_PERIOD_PET_NS
, &min_period_pet_abstime
);
431 nanoseconds_to_absolutetime(KP_MIN_PERIOD_PET_BG_NS
,
432 &min_period_pet_bg_abstime
);
433 assert(min_period_abstime
> 0);
436 if (count
== kperf_timerc
) {
439 if (count
> TIMER_MAX
) {
443 /* TODO: allow shrinking? */
444 if (count
< kperf_timerc
) {
449 * Make sure kperf is initialized when creating the array for the first
452 if (kperf_timerc
== 0) {
456 if ((r
= kperf_init())) {
462 * Shut down any running timers since we will be messing with the timer
467 /* create a new array */
468 new_timerv
= kalloc_tag(count
* sizeof(struct kperf_timer
),
469 VM_KERN_MEMORY_DIAG
);
470 if (new_timerv
== NULL
) {
473 old_timerv
= kperf_timerv
;
474 old_count
= kperf_timerc
;
476 if (old_timerv
!= NULL
) {
477 bcopy(kperf_timerv
, new_timerv
,
478 kperf_timerc
* sizeof(struct kperf_timer
));
481 /* zero the new entries */
482 bzero(&(new_timerv
[kperf_timerc
]),
483 (count
- old_count
) * sizeof(struct kperf_timer
));
485 /* (re-)setup the timer call info for all entries */
486 for (unsigned int i
= 0; i
< count
; i
++) {
487 timer_call_setup(&new_timerv
[i
].tcall
, kperf_timer_handler
, &new_timerv
[i
]);
490 kperf_timerv
= new_timerv
;
491 kperf_timerc
= count
;
493 if (old_timerv
!= NULL
) {
494 kfree(old_timerv
, old_count
* sizeof(struct kperf_timer
));