]>
git.saurik.com Git - apple/xnu.git/blob - osfmk/kperf/timetrigger.c
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@
29 /* Manage time triggers */
31 #include <mach/mach_types.h>
32 #include <kern/cpu_data.h> /* current_thread() */
33 #include <kern/kalloc.h>
34 #include <sys/errno.h>
36 #include <chud/chud_xnu.h>
38 #include <kperf/kperf.h>
39 #include <kperf/buffer.h>
40 #include <kperf/context.h>
41 #include <kperf/action.h>
42 #include <kperf/timetrigger.h>
43 #include <kperf/kperf_arch.h>
44 #include <kperf/pet.h>
46 /* represents a periodic timer */
49 struct timer_call tcall
;
52 volatile unsigned active
;
55 /* the list of timers */
56 static unsigned timerc
= 0;
57 static struct time_trigger
*timerv
;
58 static unsigned pet_timer
= 999;
60 /* maximum number of timers we can construct */
63 /* minimal interval for a timer (100usec in nsec) */
64 #define MIN_TIMER (100000)
67 kperf_timer_schedule( struct time_trigger
*trigger
, uint64_t now
)
71 BUF_INFO1(PERF_TM_SCHED
, trigger
->period
);
73 /* calculate deadline */
74 deadline
= now
+ trigger
->period
;
76 /* re-schedule the timer, making sure we don't apply slop */
77 timer_call_enter( &trigger
->tcall
, deadline
, TIMER_CALL_CRITICAL
);
81 kperf_ipi_handler( void *param
)
84 struct kperf_sample
*intbuf
= NULL
;
85 struct kperf_context ctx
;
86 struct time_trigger
*trigger
= param
;
89 BUF_INFO1(PERF_TM_HNDLR
| DBG_FUNC_START
, 0);
91 /* In an interrupt, get the interrupt buffer for this CPU */
92 intbuf
= kperf_intr_sample_buffer();
94 /* On a timer, we can see the "real" current thread */
95 ctx
.cur_pid
= 0; /* remove this? */
96 ctx
.cur_thread
= current_thread();
98 task
= chudxnu_task_for_thread(ctx
.cur_thread
);
100 ctx
.cur_pid
= chudxnu_pid_for_task(task
);
103 ctx
.trigger_type
= TRIGGER_TYPE_TIMER
;
104 ctx
.trigger_id
= (unsigned)(trigger
-timerv
); /* computer timer number */
106 /* call the action -- kernel-only from interrupt, pend user */
107 r
= kperf_sample( intbuf
, &ctx
, trigger
->actionid
, TRUE
);
109 BUF_INFO1(PERF_TM_HNDLR
| DBG_FUNC_END
, r
);
113 kperf_timer_handler( void *param0
, __unused
void *param1
)
115 struct time_trigger
*trigger
= param0
;
116 unsigned ntimer
= (unsigned)(trigger
- timerv
);
120 /* along the lines of do not ipi if we are all shutting down */
121 if( kperf_sampling_status() == KPERF_SAMPLING_SHUTDOWN
)
125 kperf_mp_broadcast( kperf_ipi_handler
, trigger
);
127 /* release the pet thread? */
128 if( ntimer
== pet_timer
)
130 /* timer re-enabled when thread done */
131 kperf_pet_thread_go();
135 /* re-enable the timer
136 * FIXME: get the current time from elsewhere
138 uint64_t now
= mach_absolute_time();
139 kperf_timer_schedule( trigger
, now
);
146 /* program the timer from the pet thread */
148 kperf_timer_pet_set( unsigned timer
)
151 struct time_trigger
*trigger
= NULL
;
153 if( timer
!= pet_timer
)
154 panic( "PET setting with bogus ID\n" );
156 if( timer
>= timerc
)
159 /* CHECKME: we probably took so damn long in the PET thread,
160 * it makes sense to take the time again.
162 now
= mach_absolute_time();
163 trigger
= &timerv
[timer
];
166 kperf_timer_schedule( trigger
, now
);
172 /* turn on all the timers */
177 uint64_t now
= mach_absolute_time();
179 for( i
= 0; i
< timerc
; i
++ )
181 if( timerv
[i
].period
== 0 )
184 kperf_timer_schedule( &timerv
[i
], now
);
192 kperf_timer_stop(void)
196 for( i
= 0; i
< timerc
; i
++ )
198 if( timerv
[i
].period
== 0 )
201 while (timerv
[i
].active
)
204 timer_call_cancel( &timerv
[i
].tcall
);
207 /* wait for PET to stop, too */
208 kperf_pet_thread_wait();
214 kperf_timer_get_petid(void)
220 kperf_timer_set_petid(unsigned timerid
)
222 struct time_trigger
*trigger
= NULL
;
224 /* they can program whatever... */
227 /* clear them if it's a bogus ID */
228 if( pet_timer
>= timerc
)
230 kperf_pet_timer_config( 0, 0 );
235 /* update the values */
236 trigger
= &timerv
[pet_timer
];
237 kperf_pet_timer_config( pet_timer
, trigger
->actionid
);
243 kperf_timer_get_period( unsigned timer
, uint64_t *period
)
245 printf( "get timer %u / %u\n", timer
, timerc
);
247 if( timer
>= timerc
)
250 *period
= timerv
[timer
].period
;
256 kperf_timer_set_period( unsigned timer
, uint64_t period
)
258 printf( "set timer %u\n", timer
);
260 if( timer
>= timerc
)
263 if( period
< MIN_TIMER
)
266 timerv
[timer
].period
= period
;
268 /* FIXME: re-program running timers? */
274 kperf_timer_get_count(void)
280 setup_timer_call( struct time_trigger
*trigger
)
282 timer_call_setup( &trigger
->tcall
, kperf_timer_handler
, trigger
);
286 kperf_timer_set_count(unsigned count
)
288 struct time_trigger
*new_timerv
= NULL
, *old_timerv
= NULL
;
289 unsigned old_count
, i
;
292 if( count
== timerc
)
294 printf( "already got %d timers\n", timerc
);
298 /* TODO: allow shrinking? */
302 /* cap it for good measure */
303 if( count
> TIMER_MAX
)
306 /* creating the action arror for the first time. create a few
318 /* get the PET thread going */
319 r
= kperf_pet_init();
324 /* create a new array */
325 new_timerv
= kalloc( count
* sizeof(*new_timerv
) );
326 if( new_timerv
== NULL
)
332 if( old_timerv
!= NULL
)
333 bcopy( timerv
, new_timerv
, timerc
* sizeof(*timerv
) );
335 /* zero the new entries */
336 bzero( &new_timerv
[timerc
], (count
- old_count
) * sizeof(*new_timerv
) );
338 /* setup the timer call info */
339 for( i
= old_count
; i
< count
; i
++ )
340 setup_timer_call( &new_timerv
[i
] );
345 if( old_timerv
!= NULL
)
346 kfree( old_timerv
, old_count
* sizeof(*timerv
) );
348 printf( "kperf: done timer alloc, timerc %d\n", timerc
);