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 struct kperf_context ctx
;
110 assert(timer
!= NULL
);
112 /* Always cut a tracepoint to show a sample event occurred */
113 BUF_DATA(PERF_TM_HNDLR
| DBG_FUNC_START
, 0);
115 int ncpu
= cpu_number();
117 struct kperf_sample
*intbuf
= kperf_intr_sample_buffer();
119 /* On a timer, we can see the "real" current thread */
120 ctx
.cur_thread
= current_thread();
121 ctx
.cur_pid
= task_pid(get_threadtask(ctx
.cur_thread
));
124 ctx
.trigger_type
= TRIGGER_TYPE_TIMER
;
125 ctx
.trigger_id
= (unsigned int)(timer
- kperf_timerv
);
127 if (ctx
.trigger_id
== pet_timer_id
&& ncpu
< machine_info
.logical_cpu_max
) {
128 kperf_tid_on_cpus
[ncpu
] = thread_tid(ctx
.cur_thread
);
131 /* make sure sampling is on */
132 unsigned int status
= kperf_sampling_status();
133 if (status
== KPERF_SAMPLING_OFF
) {
134 BUF_INFO(PERF_TM_HNDLR
| DBG_FUNC_END
, SAMPLE_OFF
);
136 } else if (status
== KPERF_SAMPLING_SHUTDOWN
) {
137 BUF_INFO(PERF_TM_HNDLR
| DBG_FUNC_END
, SAMPLE_SHUTDOWN
);
141 /* call the action -- kernel-only from interrupt, pend user */
142 int r
= kperf_sample(intbuf
, &ctx
, timer
->actionid
,
143 SAMPLE_FLAG_PEND_USER
| (system_sample
? SAMPLE_FLAG_SYSTEM
: 0) |
144 (only_system
? SAMPLE_FLAG_ONLY_SYSTEM
: 0));
146 /* end tracepoint is informational */
147 BUF_INFO(PERF_TM_HNDLR
| DBG_FUNC_END
, r
);
149 (void)atomic_fetch_and_explicit(&timer
->pending_cpus
,
150 ~(UINT64_C(1) << ncpu
), memory_order_relaxed
);
154 kperf_ipi_handler(void *param
)
156 kperf_sample_cpu((struct kperf_timer
*)param
, false, false);
160 kperf_timer_handler(void *param0
, __unused
void *param1
)
162 struct kperf_timer
*timer
= param0
;
163 unsigned int ntimer
= (unsigned int)(timer
- kperf_timerv
);
164 unsigned int ncpus
= machine_info
.logical_cpu_max
;
165 bool system_only_self
= true;
167 if (timer
->actionid
== 0) {
173 /* along the lines of do not ipi if we are all shutting down */
174 if (kperf_sampling_status() == KPERF_SAMPLING_SHUTDOWN
) {
178 BUF_DATA(PERF_TM_FIRE
, ntimer
, ntimer
== pet_timer_id
, timer
->period
,
181 if (ntimer
== pet_timer_id
) {
182 kperf_pet_fire_before();
184 /* clean-up the thread-on-CPUs cache */
185 bzero(kperf_tid_on_cpus
, ncpus
* sizeof(*kperf_tid_on_cpus
));
189 * IPI other cores only if the action has non-system samplers.
191 if (kperf_sample_has_non_system(timer
->actionid
)) {
193 * If the core that's handling the timer is not scheduling
194 * threads, only run system samplers.
196 system_only_self
= kperf_mp_broadcast_other_running(timer
);
198 kperf_sample_cpu(timer
, true, system_only_self
);
200 /* release the pet thread? */
201 if (ntimer
== pet_timer_id
) {
202 /* PET mode is responsible for rearming the timer */
203 kperf_pet_fire_after();
206 * FIXME: Get the current time from elsewhere. The next
207 * timer's period now includes the time taken to reach this
208 * point. This causes a bias towards longer sampling periods
211 kperf_timer_schedule(timer
, mach_absolute_time());
218 /* program the timer from the PET thread */
220 kperf_timer_pet_rearm(uint64_t elapsed_ticks
)
222 struct kperf_timer
*timer
= NULL
;
227 * If the pet_timer_id is invalid, it has been disabled, so this should
230 if (pet_timer_id
>= kperf_timerc
) {
234 unsigned int status
= kperf_sampling_status();
235 /* do not reprogram the timer if it has been shutdown or sampling is off */
236 if (status
== KPERF_SAMPLING_OFF
) {
237 BUF_INFO(PERF_PET_END
, SAMPLE_OFF
);
239 } else if (status
== KPERF_SAMPLING_SHUTDOWN
) {
240 BUF_INFO(PERF_PET_END
, SAMPLE_SHUTDOWN
);
244 timer
= &(kperf_timerv
[pet_timer_id
]);
246 /* if we re-programmed the timer to zero, just drop it */
247 if (!timer
->period
) {
251 /* subtract the time the pet sample took being careful not to underflow */
252 if (timer
->period
> elapsed_ticks
) {
253 period
= timer
->period
- elapsed_ticks
;
256 /* make sure we don't set the next PET sample to happen too soon */
257 if (period
< min_period_pet_abstime
) {
258 period
= min_period_pet_abstime
;
261 /* we probably took so long in the PET thread, it makes sense to take
264 deadline
= mach_absolute_time() + period
;
266 BUF_INFO(PERF_PET_SCHED
, timer
->period
, period
, elapsed_ticks
, deadline
);
268 /* re-schedule the timer, making sure we don't apply slop */
269 timer_call_enter(&timer
->tcall
, deadline
, TIMER_CALL_SYS_CRITICAL
);
274 /* turn on all the timers */
278 /* get the PET thread going */
279 if (pet_timer_id
< kperf_timerc
) {
280 kperf_pet_config(kperf_timerv
[pet_timer_id
].actionid
);
283 uint64_t now
= mach_absolute_time();
285 for (unsigned int i
= 0; i
< kperf_timerc
; i
++) {
286 if (kperf_timerv
[i
].period
== 0) {
290 kperf_timer_schedule(&(kperf_timerv
[i
]), now
);
295 kperf_timer_stop(void)
297 for (unsigned int i
= 0; i
< kperf_timerc
; i
++) {
298 if (kperf_timerv
[i
].period
== 0) {
302 /* wait for the timer to stop */
303 while (kperf_timerv
[i
].active
);
305 timer_call_cancel(&kperf_timerv
[i
].tcall
);
308 /* wait for PET to stop, too */
313 kperf_timer_get_petid(void)
319 kperf_timer_set_petid(unsigned int timerid
)
321 if (timerid
< kperf_timerc
) {
324 min_period
= kperf_timer_min_pet_period_abstime();
325 if (kperf_timerv
[timerid
].period
< min_period
) {
326 kperf_timerv
[timerid
].period
= min_period
;
328 kperf_pet_config(kperf_timerv
[timerid
].actionid
);
330 /* clear the PET trigger if it's a bogus ID */
334 pet_timer_id
= timerid
;
340 kperf_timer_get_period(unsigned int timerid
, uint64_t *period_abstime
)
342 if (timerid
>= kperf_timerc
) {
346 *period_abstime
= kperf_timerv
[timerid
].period
;
351 kperf_timer_set_period(unsigned int timerid
, uint64_t period_abstime
)
355 if (timerid
>= kperf_timerc
) {
359 if (pet_timer_id
== timerid
) {
360 min_period
= kperf_timer_min_pet_period_abstime();
362 min_period
= kperf_timer_min_period_abstime();
365 if (period_abstime
> 0 && period_abstime
< min_period
) {
366 period_abstime
= min_period
;
369 kperf_timerv
[timerid
].period
= period_abstime
;
371 /* FIXME: re-program running timers? */
377 kperf_timer_get_action(unsigned int timerid
, uint32_t *action
)
379 if (timerid
>= kperf_timerc
) {
383 *action
= kperf_timerv
[timerid
].actionid
;
388 kperf_timer_set_action(unsigned int timerid
, uint32_t action
)
390 if (timerid
>= kperf_timerc
) {
394 kperf_timerv
[timerid
].actionid
= action
;
399 kperf_timer_get_count(void)
405 kperf_timer_reset(void)
407 kperf_timer_set_petid(999);
408 kperf_set_pet_idle_rate(KPERF_PET_DEFAULT_IDLE_RATE
);
409 kperf_set_lightweight_pet(0);
410 for (unsigned int i
= 0; i
< kperf_timerc
; i
++) {
411 kperf_timerv
[i
].period
= 0;
412 kperf_timerv
[i
].actionid
= 0;
413 kperf_timerv
[i
].pending_cpus
= 0;
418 kperf_timer_set_count(unsigned int count
)
420 struct kperf_timer
*new_timerv
= NULL
, *old_timerv
= NULL
;
421 unsigned int old_count
;
423 if (min_period_abstime
== 0) {
424 nanoseconds_to_absolutetime(KP_MIN_PERIOD_NS
, &min_period_abstime
);
425 nanoseconds_to_absolutetime(KP_MIN_PERIOD_BG_NS
, &min_period_bg_abstime
);
426 nanoseconds_to_absolutetime(KP_MIN_PERIOD_PET_NS
, &min_period_pet_abstime
);
427 nanoseconds_to_absolutetime(KP_MIN_PERIOD_PET_BG_NS
,
428 &min_period_pet_bg_abstime
);
429 assert(min_period_abstime
> 0);
432 if (count
== kperf_timerc
) {
435 if (count
> TIMER_MAX
) {
439 /* TODO: allow shrinking? */
440 if (count
< kperf_timerc
) {
445 * Make sure kperf is initialized when creating the array for the first
448 if (kperf_timerc
== 0) {
452 if ((r
= kperf_init())) {
458 * Shut down any running timers since we will be messing with the timer
463 /* create a new array */
464 new_timerv
= kalloc_tag(count
* sizeof(struct kperf_timer
),
465 VM_KERN_MEMORY_DIAG
);
466 if (new_timerv
== NULL
) {
469 old_timerv
= kperf_timerv
;
470 old_count
= kperf_timerc
;
472 if (old_timerv
!= NULL
) {
473 bcopy(kperf_timerv
, new_timerv
,
474 kperf_timerc
* sizeof(struct kperf_timer
));
477 /* zero the new entries */
478 bzero(&(new_timerv
[kperf_timerc
]),
479 (count
- old_count
) * sizeof(struct kperf_timer
));
481 /* (re-)setup the timer call info for all entries */
482 for (unsigned int i
= 0; i
< count
; i
++) {
483 timer_call_setup(&new_timerv
[i
].tcall
, kperf_timer_handler
, &new_timerv
[i
]);
486 kperf_timerv
= new_timerv
;
487 kperf_timerc
= count
;
489 if (old_timerv
!= NULL
) {
490 kfree(old_timerv
, old_count
* sizeof(struct kperf_timer
));