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@
28 #include <mach/mach_types.h>
29 #include <kern/thread.h>
30 #include <kern/machine.h>
31 #include <kern/kalloc.h>
32 #include <sys/errno.h>
34 #include <kperf/sample.h>
35 #include <kperf/pet.h>
36 #include <kperf/action.h>
37 #include <kperf/kperf.h>
38 #include <kperf/timetrigger.h>
40 #include <kern/ipc_tt.h> /* port_name_to_task */
42 /** misc functions **/
43 #include <chud/chud_xnu.h> /* XXX: should bust this out */
45 /* thread on CPUs before starting the PET thread */
46 thread_t
*kperf_thread_on_cpus
= NULL
;
48 /* interupt sample buffers -- one wired per CPU */
49 static struct kperf_sample
*intr_samplev
= NULL
;
50 static unsigned intr_samplec
= 0;
52 /* track recursion in the trace code */
56 int pad
[64 / sizeof(int)];
58 static unsigned kpdbg_recursec
= 0;
60 /* Curren sampling status */
61 static unsigned sampling_status
= KPERF_SAMPLING_OFF
;
63 /* Make sure we only init once */
64 static unsigned kperf_initted
= 0;
66 extern void (*chudxnu_thread_ast_handler
)(thread_t
);
69 kperf_intr_sample_buffer(void)
71 unsigned ncpu
= chudxnu_cpu_number();
74 if( ncpu
>= intr_samplec
)
77 return &intr_samplev
[ncpu
];
81 kperf_kdbg_recurse(int step
)
83 unsigned ncpu
= chudxnu_cpu_number();
86 if( ncpu
>= kpdbg_recursec
)
89 /* recursing in, available */
91 && (kpdbg_recursev
[ncpu
].active
== 0) )
93 kpdbg_recursev
[ncpu
].active
= 1;
97 /* recursing in, unavailable */
99 && (kpdbg_recursev
[ncpu
].active
!= 0) )
104 /* recursing out, unavailable */
106 && (kpdbg_recursev
[ncpu
].active
!= 0) )
108 kpdbg_recursev
[ncpu
].active
= 0;
112 /* recursing out, available */
114 && (kpdbg_recursev
[ncpu
].active
== 0) )
115 panic( "return from non-recursed kperf kdebug call" );
117 panic( "unknown kperf kdebug call" );
121 /* setup interrupt sample buffers */
131 /* get number of cpus */
132 ncpus
= machine_info
.logical_cpu_max
;
134 kperf_thread_on_cpus
= kalloc( ncpus
* sizeof(*kperf_thread_on_cpus
) );
135 if( kperf_thread_on_cpus
== NULL
)
142 bzero( kperf_thread_on_cpus
, ncpus
* sizeof(*kperf_thread_on_cpus
) );
144 /* make the CPU array
145 * FIXME: cache alignment
147 intr_samplev
= kalloc( ncpus
* sizeof(*intr_samplev
));
148 intr_samplec
= ncpus
;
150 if( intr_samplev
== NULL
)
157 bzero( intr_samplev
, ncpus
* sizeof(*intr_samplev
) );
159 /* make the recursion array */
160 kpdbg_recursev
= kalloc( ncpus
* sizeof(*kpdbg_recursev
));
161 kpdbg_recursec
= ncpus
;
164 bzero( kpdbg_recursev
, ncpus
* sizeof(*kpdbg_recursev
) );
172 kfree( intr_samplev
, ncpus
* sizeof(*intr_samplev
) );
173 if( kperf_thread_on_cpus
)
174 kfree( kperf_thread_on_cpus
, ncpus
* sizeof(*kperf_thread_on_cpus
) );
178 /* random misc-ish functions */
180 kperf_get_thread_bits( thread_t thread
)
182 return thread
->t_chud
;
186 kperf_set_thread_bits( thread_t thread
, uint32_t bits
)
188 thread
->t_chud
= bits
;
191 /* mark an AST to fire on a thread */
193 kperf_set_thread_ast( thread_t thread
)
195 /* FIXME: only call this on current thread from an interrupt
198 if( thread
!= current_thread() )
199 panic( "unsafe AST set" );
201 act_set_kperf(thread
);
205 kperf_sampling_status(void)
207 return sampling_status
;
211 kperf_sampling_enable(void)
213 /* already running! */
214 if( sampling_status
== KPERF_SAMPLING_ON
)
217 if ( sampling_status
!= KPERF_SAMPLING_OFF
)
218 panic( "kperf: sampling wasn't off" );
220 /* make sure interrupt tables and actions are initted */
222 || (kperf_action_get_count() == 0) )
225 /* mark as running */
226 sampling_status
= KPERF_SAMPLING_ON
;
228 /* tell timers to enable */
235 kperf_sampling_disable(void)
237 if( sampling_status
!= KPERF_SAMPLING_ON
)
240 /* mark a shutting down */
241 sampling_status
= KPERF_SAMPLING_SHUTDOWN
;
243 /* tell timers to disable */
247 sampling_status
= KPERF_SAMPLING_OFF
;
253 kperf_port_to_pid(mach_port_name_t portname
)
258 if( !MACH_PORT_VALID(portname
) )
261 task
= port_name_to_task(portname
);
263 if( task
== TASK_NULL
)
267 pid
= chudxnu_pid_for_task(task
);
269 task_deallocate_internal(task
);