]>
git.saurik.com Git - apple/xnu.git/blob - osfmk/kperf/action.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@
30 * Called from a trigger. Actually takes the data from the different
31 * modules and puts them in a buffer
34 #include <mach/mach_types.h>
35 #include <machine/machine_routines.h>
36 // #include <libkern/libkern.h>
37 #include <kern/kalloc.h>
38 #include <kern/debug.h> /* panic */
39 #include <kern/thread.h>
40 #include <sys/errno.h>
42 #include <chud/chud_xnu.h>
43 #include <kperf/kperf.h>
45 #include <kperf/buffer.h>
46 #include <kperf/timetrigger.h>
47 #include <kperf/threadinfo.h>
48 #include <kperf/callstack.h>
49 #include <kperf/sample.h>
50 #include <kperf/filter.h>
51 #include <kperf/action.h>
52 #include <kperf/context.h>
53 #include <kperf/ast.h>
57 /* XXX: callback handler from chudxnu */
58 /* FIXME: hook this up to something */
59 //void (*kperf_thread_ast_handler)(thread_t);
61 /* the list of different actions to take */
67 /* the list of actions */
68 static unsigned actionc
= 0;
69 static struct action
*actionv
= NULL
;
72 /* Do the real work! */
73 /* this can be called in any context ... right? */
75 kperf_sample_internal( struct kperf_sample
*sbuf
,
76 struct kperf_context
*context
,
77 unsigned sample_what
, boolean_t pend_user
)
80 int did_ucallstack
= 0, did_tinfo_extra
= 0;
82 /* not much point continuing here, but what to do ? return
83 * Shutdown? cut a tracepoint and continue?
85 if( sample_what
== 0 )
86 return SAMPLE_CONTINUE
;
88 int is_kernel
= (context
->cur_pid
== 0);
90 /* an event occurred. Sample everything and dump it in a
94 /* collect data from samplers */
95 if( sample_what
& SAMPLER_TINFO
) {
96 kperf_threadinfo_sample( &sbuf
->threadinfo
, context
);
98 /* XXX FIXME This drops events when the thread is idle.
99 * This should be configurable. */
100 if (sbuf
->threadinfo
.runmode
& 0x40)
101 return SAMPLE_CONTINUE
;
104 if( sample_what
& SAMPLER_KSTACK
)
105 kperf_kcallstack_sample( &sbuf
->kcallstack
, context
);
111 if( sample_what
& SAMPLER_USTACK
)
112 did_ucallstack
= kperf_ucallstack_pend( context
);
114 if( sample_what
& SAMPLER_TINFOEX
)
115 did_tinfo_extra
= kperf_threadinfo_extra_pend( context
);
119 if( sample_what
& SAMPLER_USTACK
)
120 kperf_ucallstack_sample( &sbuf
->ucallstack
, context
);
122 if( sample_what
& SAMPLER_TINFOEX
)
123 kperf_threadinfo_extra_sample( &sbuf
->tinfo_ex
,
128 /* stash the data into the buffer
129 * interrupts off to ensure we don't get split
131 enabled
= ml_set_interrupts_enabled(FALSE
);
134 BUF_DATA1( PERF_GEN_EVENT
| DBG_FUNC_START
, sample_what
);
136 /* dump threadinfo */
137 if( sample_what
& SAMPLER_TINFO
)
138 kperf_threadinfo_log( &sbuf
->threadinfo
);
140 /* dump kcallstack */
141 if( sample_what
& SAMPLER_KSTACK
)
142 kperf_kcallstack_log( &sbuf
->kcallstack
);
145 /* dump user stuff */
149 if ( did_ucallstack
)
150 BUF_INFO1( PERF_CS_UPEND
, 0 );
152 if ( did_tinfo_extra
)
153 BUF_INFO1( PERF_TI_XPEND
, 0 );
157 if( sample_what
& SAMPLER_USTACK
)
158 kperf_ucallstack_log( &sbuf
->ucallstack
);
160 if( sample_what
& SAMPLER_TINFOEX
)
161 kperf_threadinfo_extra_log( &sbuf
->tinfo_ex
);
166 BUF_DATA1( PERF_GEN_EVENT
| DBG_FUNC_END
, sample_what
);
169 ml_set_interrupts_enabled(enabled
);
171 return SAMPLE_CONTINUE
;
174 /* Translate actionid into sample bits and take a sample */
176 kperf_sample( struct kperf_sample
*sbuf
,
177 struct kperf_context
*context
,
178 unsigned actionid
, boolean_t pend_user
)
180 unsigned sample_what
= 0;
182 /* check samppling is on, or panic */
183 if( kperf_sampling_status() == KPERF_SAMPLING_OFF
)
184 panic("trigger fired while sampling off");
185 else if( kperf_sampling_status() == KPERF_SAMPLING_SHUTDOWN
)
186 return SAMPLE_SHUTDOWN
;
188 /* work out what to sample, if anything */
189 if( actionid
>= actionc
)
190 return SAMPLE_SHUTDOWN
;
192 sample_what
= actionv
[actionid
].sample
;
194 return kperf_sample_internal( sbuf
, context
, sample_what
, pend_user
);
197 /* ast callback on a thread */
199 kperf_thread_ast_handler( thread_t thread
)
203 unsigned sample_what
= 0;
204 /* we know we're on a thread, so let's do stuff */
207 /* Don't sample if we are shutting down or off */
208 if( kperf_sampling_status() != KPERF_SAMPLING_ON
)
211 BUF_INFO1(PERF_AST_HNDLR
| DBG_FUNC_START
, thread
);
213 /* FIXME: probably want a faster allocator here... :P */
214 struct kperf_sample
*sbuf
= kalloc( sizeof(*sbuf
) );
217 /* FIXME: error code */
218 BUF_INFO1( PERF_AST_ERROR
, 0 );
222 /* make a context, take a sample */
223 struct kperf_context ctx
;
224 ctx
.cur_thread
= thread
;
227 task
= chudxnu_task_for_thread(thread
);
229 ctx
.cur_pid
= chudxnu_pid_for_task(task
);
231 /* decode the chud bits so we know what to sample */
232 t_chud
= kperf_get_thread_bits(thread
);
234 if (t_chud
& T_AST_NAME
)
235 sample_what
|= SAMPLER_TINFOEX
;
237 if (t_chud
& T_AST_CALLSTACK
)
238 sample_what
|= SAMPLER_USTACK
;
240 /* do the sample, just of the user stuff */
241 r
= kperf_sample_internal( sbuf
, &ctx
, sample_what
, FALSE
);
244 kfree( sbuf
, sizeof(*sbuf
) );
247 BUF_INFO1(PERF_AST_HNDLR
| DBG_FUNC_END
, r
);
251 /* register AST bits */
253 kperf_ast_pend( thread_t cur_thread
, uint32_t check_bits
,
256 /* pend on the thread */
257 uint32_t t_chud
, set_done
= 0;
259 /* can only pend on the current thread */
260 if( cur_thread
!= chudxnu_current_thread() )
261 panic("pending to non-current thread");
263 /* get our current bits */
264 t_chud
= kperf_get_thread_bits(cur_thread
);
266 /* see if it's already been done or pended */
267 if( !(t_chud
& check_bits
) )
269 /* set the bit on the thread */
271 kperf_set_thread_bits(cur_thread
, t_chud
);
273 /* set the actual AST */
274 kperf_set_thread_ast( cur_thread
);
281 // BUF_INFO3( dbg_code, (uintptr_t)cur_thread, t_chud, set_done );
285 kperf_action_get_count(void)
291 kperf_action_set_samplers( unsigned actionid
, uint32_t samplers
)
293 if( actionid
>= actionc
)
296 actionv
[actionid
].sample
= samplers
;
302 kperf_action_get_samplers( unsigned actionid
, uint32_t *samplers_out
)
304 if( actionid
>= actionc
)
307 *samplers_out
= actionv
[actionid
].sample
;
313 kperf_action_set_count(unsigned count
)
315 struct action
*new_actionv
= NULL
, *old_actionv
= NULL
;
319 if( count
== actionc
)
322 /* TODO: allow shrinking? */
323 if( count
< actionc
)
326 /* cap it for good measure */
327 if( count
> ACTION_MAX
)
330 /* creating the action arror for the first time. create a few
342 /* create a new array */
343 new_actionv
= kalloc( count
* sizeof(*new_actionv
) );
344 if( new_actionv
== NULL
)
347 old_actionv
= actionv
;
350 if( old_actionv
!= NULL
)
351 bcopy( actionv
, new_actionv
, actionc
* sizeof(*actionv
) );
353 bzero( &new_actionv
[actionc
], (count
- old_count
) * sizeof(*actionv
) );
355 actionv
= new_actionv
;
358 if( old_actionv
!= NULL
)
359 kfree( old_actionv
, old_count
* sizeof(*actionv
) );
361 printf( "kperf: done the alloc\n" );