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 /* Sample thread data */
32 #include <mach/mach_types.h>
33 #include <kern/thread.h> /* thread_* */
34 #include <kern/debug.h> /* panic */
35 // #include <sys/proc.h>
37 #include <chud/chud_xnu.h>
38 #include <kperf/kperf.h>
40 #include <kperf/buffer.h>
41 #include <kperf/context.h>
42 #include <kperf/threadinfo.h>
43 #include <kperf/ast.h>
45 // kAppleProfileTriggerClientThreadModeIdle = 0x40, // TH_IDLE
46 // #define TH_IDLE 0x40
48 //kAppleProfileTriggerClientThreadModeNotIdle = kAppleProfileTriggerClientThreadModeIdle << 16, // !TH_IDLE
49 #define TH_IDLE_N (TH_IDLE << 16)
52 make_runmode(thread_t thread
)
54 /* CEG: This is a translation of
55 * AppleProfileGetRunModeOfThread below... kinda magic :/
57 const int mode
= chudxnu_thread_get_scheduler_state(thread
);
59 #if !TARGET_OS_EMBEDDED
62 return (chudxnu_thread_get_idle(thread
) ? TH_IDLE
: TH_IDLE_N
);
66 // Today we happen to know there's a one-to-one mapping.
67 return ((mode
& 0xffff) | ((~mode
& 0xffff) << 16));
71 /* code to collect current thread info */
73 kperf_threadinfo_sample(struct threadinfo
*ti
, struct kperf_context
*context
)
75 thread_t cur_thread
= context
->cur_thread
;
76 BUF_INFO1( PERF_TI_SAMPLE
, (uintptr_t)cur_thread
);
78 // fill out the fields
79 ti
->pid
= context
->cur_pid
;
80 ti
->tid
= thread_tid(cur_thread
);
81 ti
->dq_addr
= thread_dispatchqaddr(cur_thread
);
82 ti
->runmode
= make_runmode(cur_thread
);
85 /* log an existing sample into the buffer */
87 kperf_threadinfo_log(struct threadinfo
*ti
)
90 BUF_DATA( PERF_TI_DATA
, ti
->pid
, ti
->tid
, ti
->dq_addr
, ti
->runmode
);
93 /* 'extra' thread-info functions that are deferred 'til thread-context
97 kperf_threadinfo_extra_sample(struct tinfo_ex
*tex
, struct kperf_context
*context
)
99 thread_t cur_thread
= context
->cur_thread
;
102 /* can only pend on the current thread */
103 /* this is valid from PET mode... */
105 if( cur_thread != chudxnu_current_thread() )
106 panic("pending to non-current thread");
109 /* get our current bits */
110 t_chud
= kperf_get_thread_bits(cur_thread
);
112 /* check if there's anything for us to do */
113 if( t_chud
& T_AST_NAME
)
115 BUF_INFO1( PERF_TI_XSAMPLE
, (uintptr_t)cur_thread
);
117 /* get the name out */
119 /* need kperfbsd.c? */
120 proc_name( context
->cur_pid
,
121 &tex
->p_comm
[0], CHUD_MAXPCOMM
);
124 /* mark that it's done */
125 t_chud
&= ~T_AST_NAME
;
126 t_chud
|= T_NAME_DONE
;
128 kperf_set_thread_bits(cur_thread
, t_chud
);
132 tex
->p_comm
[0] = '\0';
136 /* log it if there's anyting useful there */
138 kperf_threadinfo_extra_log(struct tinfo_ex
*tex
)
141 if( tex
->p_comm
[0] == '\0' )
144 /* FIXME: log more */
145 BUF_DATA1( PERF_TI_XDATA
, (uintptr_t)*(uintptr_t*)&tex
->p_comm
[0] );
148 /* pend a flag on a thread */
150 kperf_threadinfo_extra_pend(struct kperf_context
*context
)
152 return kperf_ast_pend( context
->cur_thread
, T_NAME_DONE
| T_AST_NAME
,
159 /* transalted from the APF */
161 APTIAKernelEntry_t
*threadInfo
= (APTIAKernelEntry_t
*)(threadInfos
+ account
->offset
);
163 context
->timeStamp
= mach_absolute_time();
164 context
->cpuNum
= chudxnu_cpu_number();
166 // record the process info from the callback context
167 context
->pid
= chudxnu_current_pid();
168 threadInfo
->pid
= context
->generic
->pid
;
170 // thread_tid is a thread_t to ID function in the kernel
171 context
->threadID
= chudxnu_current_thread();
172 threadInfo
->tid
= thread_tid(context
->generic
->threadID
);
174 // also a kernel function
175 threadInfo
->dispatch_queue_addr
= thread_dispatchqaddr(context
->generic
->threadID
);
178 threadInfo
->runMode
= AppleProfileGetRunModeOfThread(context
->generic
->threadID
);
181 /****** WTF is this?! *******/
183 /*!enum AppleProfileTriggerClientThreadRunMode
185 * Specifies the thread mode in which to record samples.
187 typedef enum { // Target Thread State - can be OR'd
188 // Basic Building Blocks:
189 // for Time Profile, use kAppleProfileTriggerClientThreadModeRunning (optionally with kAppleProfileTriggerClientThreadModeNotIdle).
190 // for Time Profile (All Thread States), use kAppleProfileTriggerClientThreadModeAny (or just don't specify any thread mode filters).
191 // for Time Profile (Blocked Threads), use kIOProfileTriggerClientThreadModeBlocked.
194 kAppleProfileTriggerClientThreadModeNone
= 0x0,
196 kAppleProfileTriggerClientThreadModeRunning
= 0x1, // On a core
197 kAppleProfileTriggerClientThreadModeRunnable
= 0x2, // TH_RUN
198 kAppleProfileTriggerClientThreadModeBlocked
= 0x4, // TH_WAIT
199 kAppleProfileTriggerClientThreadModeUninterruptible
= 0x8, // TH_UNINT
200 kAppleProfileTriggerClientThreadModeSuspended
= 0x10, // TH_SUSP
201 kAppleProfileTriggerClientThreadModeTerminating
= 0x20, // TH_TERMINATE
202 kAppleProfileTriggerClientThreadModeIdle
= 0x40, // TH_IDLE
204 kAppleProfileTriggerClientThreadModeNotRunning
= kAppleProfileTriggerClientThreadModeRunning
<< 16, // Not on a core
205 kAppleProfileTriggerClientThreadModeNotRunnable
= kAppleProfileTriggerClientThreadModeRunnable
<< 16, // !TH_RUN
206 kAppleProfileTriggerClientThreadModeNotBlocked
= kAppleProfileTriggerClientThreadModeBlocked
<< 16, // !TH_WAIT
207 kAppleProfileTriggerClientThreadModeNotUninterruptible
= kAppleProfileTriggerClientThreadModeUninterruptible
<< 16, // !TH_UNINT
208 kAppleProfileTriggerClientThreadModeNotSuspended
= kAppleProfileTriggerClientThreadModeSuspended
<< 16, // !TH_SUSP
209 kAppleProfileTriggerClientThreadModeNotTerminating
= kAppleProfileTriggerClientThreadModeTerminating
<< 16, // !TH_TERMINATE
210 kAppleProfileTriggerClientThreadModeNotIdle
= kAppleProfileTriggerClientThreadModeIdle
<< 16, // !TH_IDLE
212 kAppleProfileTriggerClientThreadModeAny
= ( kAppleProfileTriggerClientThreadModeRunning
213 | kAppleProfileTriggerClientThreadModeNotRunning
),
214 } AppleProfileTriggerClientThreadRunMode
;
216 extern "C" AppleProfileTriggerClientThreadRunMode
AppleProfileGetRunModeOfThread(thread_t thread
) {
217 const int mode
= chudxnu_thread_get_scheduler_state(thread
);
219 #if !TARGET_OS_EMBEDDED
221 return (chudxnu_thread_get_idle(thread
) ? kAppleProfileTriggerClientThreadModeIdle
: kAppleProfileTriggerClientThreadModeNotIdle
);
224 return (AppleProfileTriggerClientThreadRunMode
)((mode
& 0xffff) | ((~mode
& 0xffff) << 16)); // Today we happen to know there's a one-to-one mapping.