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 /* all thread states code */
30 #include <mach/mach_types.h>
31 #include <IOKit/IOTypes.h>
32 #include <IOKit/IOLocks.h>
33 #include <sys/errno.h>
35 #include <chud/chud_xnu.h>
37 #include <kperf/buffer.h>
38 #include <kperf/sample.h>
39 #include <kperf/context.h>
40 #include <kperf/action.h>
41 #include <kperf/filter.h>
42 #include <kperf/pet.h>
43 #include <kperf/timetrigger.h>
45 /* timer id to call back on */
46 static unsigned pet_timerid
= 0;
49 * We also use this as the sync point for waiting, for no good reason
51 static unsigned pet_actionid
= 0;
53 /* the actual thread pointer */
54 static thread_t pet_thread
= NULL
;
56 /* Lock on which to synchronise */
57 static IOLock
*pet_lock
= NULL
;
59 /* where to sample data to */
60 static struct kperf_sample pet_sample_buf
;
62 /* sample an actual, honest to god thread! */
64 pet_sample_thread( thread_t thread
)
66 struct kperf_context ctx
;
69 /* work out the context */
70 ctx
.cur_thread
= thread
;
73 task
= chudxnu_task_for_thread(thread
);
75 ctx
.cur_pid
= chudxnu_pid_for_task(task
);
77 /* do the actual sample */
78 kperf_sample( &pet_sample_buf
, &ctx
, pet_actionid
, false );
81 /* given a list of threads, preferably stopped, sample 'em! */
83 pet_sample_thread_list( mach_msg_type_number_t threadc
, thread_array_t threadv
)
87 for( i
= 0; i
< threadc
; i
++ )
89 thread_t thread
= threadv
[i
];
95 pet_sample_thread( thread
);
99 /* given a task (preferably stopped), sample all the threads in it */
101 pet_sample_task( task_t task
)
103 mach_msg_type_number_t threadc
;
104 thread_array_t threadv
;
107 kr
= chudxnu_task_threads(task
, &threadv
, &threadc
);
108 if( kr
!= KERN_SUCCESS
)
110 BUF_INFO2(PERF_PET_ERROR
, ERR_THREAD
, kr
);
114 pet_sample_thread_list( threadc
, threadv
);
116 chudxnu_free_thread_list(&threadv
, &threadc
);
119 /* given a list of tasks, sample all the threads in 'em */
121 pet_sample_task_list( int taskc
, task_array_t taskv
)
125 for( i
= 0; i
< taskc
; i
++ )
128 task_t task
= taskv
[i
];
130 /* FIXME: necessary? old code did this, our hacky
131 * filtering code does, too
137 /* try and stop any task other than the kernel task */
138 if( task
!= kernel_task
)
140 kr
= task_suspend( task
);
142 /* try the next task */
143 if( kr
!= KERN_SUCCESS
)
148 pet_sample_task( task
);
150 /* if it wasn't the kernel, resume it */
151 if( task
!= kernel_task
)
157 pet_sample_all_tasks(void)
159 task_array_t taskv
= NULL
;
160 mach_msg_type_number_t taskc
= 0;
163 kr
= chudxnu_all_tasks(&taskv
, &taskc
);
165 if( kr
!= KERN_SUCCESS
)
167 BUF_INFO2(PERF_PET_ERROR
, ERR_TASK
, kr
);
171 pet_sample_task_list( taskc
, taskv
);
172 chudxnu_free_task_list(&taskv
, &taskc
);
176 pet_sample_pid_filter(void)
178 task_t
*taskv
= NULL
;
182 kperf_filter_pid_list( &pidc
, &pidv
);
185 BUF_INFO2(PERF_PET_ERROR
, ERR_PID
, 0);
189 asize
= pidc
* sizeof(task_t
);
190 taskv
= kalloc( asize
);
195 /* convert the pid list into a task list */
196 for( i
= 0; i
< pidc
; i
++ )
202 taskv
[i
] = chudxnu_task_for_pid(pid
);
205 /* now sample the task list */
206 pet_sample_task_list( pidc
, taskv
);
211 kperf_filter_free_pid_list( &pidc
, &pidv
);
214 /* do the pet sample */
220 /* check if we're filtering on pid */
221 pid_filter
= kperf_filter_on_pid();
225 BUF_INFO1(PERF_PET_SAMPLE
| DBG_FUNC_START
, 1);
226 pet_sample_pid_filter();
230 /* otherwise filter everything */
231 BUF_INFO1(PERF_PET_SAMPLE
| DBG_FUNC_START
, 0);
232 pet_sample_all_tasks();
235 BUF_INFO1(PERF_PET_SAMPLE
| DBG_FUNC_END
, 0);
239 /* sleep indefinitely */
243 IOLockLock(pet_lock
);
244 IOLockSleep(pet_lock
, &pet_actionid
, THREAD_UNINT
);
245 IOLockUnlock(pet_lock
);
248 /* loop between sampling and waiting */
250 pet_thread_loop( __unused
void *param
, __unused wait_result_t wr
)
252 BUF_INFO1(PERF_PET_THREAD
, 1);
256 BUF_INFO1(PERF_PET_IDLE
, 0);
259 BUF_INFO1(PERF_PET_RUN
, 0);
262 /* re-program the timer */
263 kperf_timer_pet_set( pet_timerid
);
265 /* FIXME: break here on a condition? */
269 /* make sure the thread takes a new period value */
271 kperf_pet_timer_config( unsigned timerid
, unsigned actionid
)
273 /* hold the lock so pet thread doesn't run while we do this */
274 IOLockLock(pet_lock
);
276 BUF_INFO1(PERF_PET_THREAD
, 3);
279 pet_timerid
= timerid
;
280 pet_actionid
= actionid
;
283 IOLockUnlock(pet_lock
);
286 /* make the thread run! */
288 kperf_pet_thread_go(void)
290 /* Make the thread go */
291 IOLockWakeup(pet_lock
, &pet_actionid
, FALSE
);
295 /* wait for the pet thread to finish a run */
297 kperf_pet_thread_wait(void)
299 /* acquire the lock to ensure the thread is parked. */
300 IOLockLock(pet_lock
);
301 IOLockUnlock(pet_lock
);
304 /* keep the pet thread around while we run */
311 if( pet_thread
!= NULL
)
314 /* make the sync poing */
315 pet_lock
= IOLockAlloc();
316 if( pet_lock
== NULL
)
319 /* create the thread */
320 BUF_INFO1(PERF_PET_THREAD
, 0);
321 rc
= kernel_thread_start( pet_thread_loop
, NULL
, &t
);
322 if( rc
!= KERN_SUCCESS
)
324 IOLockFree( pet_lock
);