]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kperf/kperf.c
xnu-2422.1.72.tar.gz
[apple/xnu.git] / osfmk / kperf / kperf.c
1 /*
2 * Copyright (c) 2011 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
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>
33
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>
39
40 #include <kern/ipc_tt.h> /* port_name_to_task */
41
42 /** misc functions **/
43 #include <chud/chud_xnu.h> /* XXX: should bust this out */
44
45 /* thread on CPUs before starting the PET thread */
46 thread_t *kperf_thread_on_cpus = NULL;
47
48 /* interupt sample buffers -- one wired per CPU */
49 static struct kperf_sample *intr_samplev = NULL;
50 static unsigned intr_samplec = 0;
51
52 /* track recursion in the trace code */
53 static struct
54 {
55 int active;
56 int pad[64 / sizeof(int)];
57 } *kpdbg_recursev;
58 static unsigned kpdbg_recursec = 0;
59
60 /* Curren sampling status */
61 static unsigned sampling_status = KPERF_SAMPLING_OFF;
62
63 /* Make sure we only init once */
64 static unsigned kperf_initted = 0;
65
66 extern void (*chudxnu_thread_ast_handler)(thread_t);
67
68 struct kperf_sample*
69 kperf_intr_sample_buffer(void)
70 {
71 unsigned ncpu = chudxnu_cpu_number();
72
73 // XXX: assert?
74 if( ncpu >= intr_samplec )
75 return NULL;
76
77 return &intr_samplev[ncpu];
78 }
79
80 int
81 kperf_kdbg_recurse(int step)
82 {
83 unsigned ncpu = chudxnu_cpu_number();
84
85 // XXX: assert?
86 if( ncpu >= kpdbg_recursec )
87 return 1;
88
89 /* recursing in, available */
90 if( (step > 0)
91 && (kpdbg_recursev[ncpu].active == 0) )
92 {
93 kpdbg_recursev[ncpu].active = 1;
94 return 0;
95 }
96
97 /* recursing in, unavailable */
98 if( (step > 0)
99 && (kpdbg_recursev[ncpu].active != 0) )
100 {
101 return 1;
102 }
103
104 /* recursing out, unavailable */
105 if( (step < 0)
106 && (kpdbg_recursev[ncpu].active != 0) )
107 {
108 kpdbg_recursev[ncpu].active = 0;
109 return 0;
110 }
111
112 /* recursing out, available */
113 if( (step < 0)
114 && (kpdbg_recursev[ncpu].active == 0) )
115 panic( "return from non-recursed kperf kdebug call" );
116
117 panic( "unknown kperf kdebug call" );
118 return 1;
119 }
120
121 /* setup interrupt sample buffers */
122 int
123 kperf_init(void)
124 {
125 unsigned ncpus = 0;
126 int err;
127
128 if( kperf_initted )
129 return 0;
130
131 /* get number of cpus */
132 ncpus = machine_info.logical_cpu_max;
133
134 kperf_thread_on_cpus = kalloc( ncpus * sizeof(*kperf_thread_on_cpus) );
135 if( kperf_thread_on_cpus == NULL )
136 {
137 err = ENOMEM;
138 goto error;
139 }
140
141 /* clear it */
142 bzero( kperf_thread_on_cpus, ncpus * sizeof(*kperf_thread_on_cpus) );
143
144 /* make the CPU array
145 * FIXME: cache alignment
146 */
147 intr_samplev = kalloc( ncpus * sizeof(*intr_samplev));
148 intr_samplec = ncpus;
149
150 if( intr_samplev == NULL )
151 {
152 err = ENOMEM;
153 goto error;
154 }
155
156 /* clear it */
157 bzero( intr_samplev, ncpus * sizeof(*intr_samplev) );
158
159 /* make the recursion array */
160 kpdbg_recursev = kalloc( ncpus * sizeof(*kpdbg_recursev));
161 kpdbg_recursec = ncpus;
162
163 /* clear it */
164 bzero( kpdbg_recursev, ncpus * sizeof(*kpdbg_recursev) );
165
166 /* we're done */
167 kperf_initted = 1;
168
169 return 0;
170 error:
171 if( intr_samplev )
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) );
175 return err;
176 }
177
178 /* random misc-ish functions */
179 uint32_t
180 kperf_get_thread_bits( thread_t thread )
181 {
182 return thread->t_chud;
183 }
184
185 void
186 kperf_set_thread_bits( thread_t thread, uint32_t bits )
187 {
188 thread->t_chud = bits;
189 }
190
191 /* mark an AST to fire on a thread */
192 void
193 kperf_set_thread_ast( thread_t thread )
194 {
195 /* FIXME: only call this on current thread from an interrupt
196 * handler for now...
197 */
198 if( thread != current_thread() )
199 panic( "unsafe AST set" );
200
201 act_set_kperf(thread);
202 }
203
204 unsigned
205 kperf_sampling_status(void)
206 {
207 return sampling_status;
208 }
209
210 int
211 kperf_sampling_enable(void)
212 {
213 /* already running! */
214 if( sampling_status == KPERF_SAMPLING_ON )
215 return 0;
216
217 if ( sampling_status != KPERF_SAMPLING_OFF )
218 panic( "kperf: sampling wasn't off" );
219
220 /* make sure interrupt tables and actions are initted */
221 if( !kperf_initted
222 || (kperf_action_get_count() == 0) )
223 return ECANCELED;
224
225 /* mark as running */
226 sampling_status = KPERF_SAMPLING_ON;
227
228 /* tell timers to enable */
229 kperf_timer_go();
230
231 return 0;
232 }
233
234 int
235 kperf_sampling_disable(void)
236 {
237 if( sampling_status != KPERF_SAMPLING_ON )
238 return 0;
239
240 /* mark a shutting down */
241 sampling_status = KPERF_SAMPLING_SHUTDOWN;
242
243 /* tell timers to disable */
244 kperf_timer_stop();
245
246 /* mark as off */
247 sampling_status = KPERF_SAMPLING_OFF;
248
249 return 0;
250 }
251
252 int
253 kperf_port_to_pid(mach_port_name_t portname)
254 {
255 task_t task;
256 int pid;
257
258 if( !MACH_PORT_VALID(portname) )
259 return -1;
260
261 task = port_name_to_task(portname);
262
263 if( task == TASK_NULL )
264 return -1;
265
266
267 pid = chudxnu_pid_for_task(task);
268
269 task_deallocate_internal(task);
270
271 return pid;
272 }