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
);
67 // Today we happen to know there's a one-to-one mapping.
68 return ((mode
& 0xffff) | ((~mode
& 0xffff) << 16));
73 /* code to collect current thread info */
75 kperf_threadinfo_sample(struct threadinfo
*ti
, struct kperf_context
*context
)
77 thread_t cur_thread
= context
->cur_thread
;
78 BUF_INFO1( PERF_TI_SAMPLE
, (uintptr_t)cur_thread
);
80 // fill out the fields
81 ti
->pid
= context
->cur_pid
;
82 ti
->tid
= thread_tid(cur_thread
);
83 ti
->dq_addr
= thread_dispatchqaddr(cur_thread
);
84 ti
->runmode
= make_runmode(cur_thread
);
87 /* log an existing sample into the buffer */
89 kperf_threadinfo_log(struct threadinfo
*ti
)
92 BUF_DATA( PERF_TI_DATA
, ti
->pid
, ti
->tid
, ti
->dq_addr
, ti
->runmode
);
95 /* 'extra' thread-info functions that are deferred 'til thread-context
99 kperf_threadinfo_extra_sample(struct tinfo_ex
*tex
, struct kperf_context
*context
)
101 thread_t cur_thread
= context
->cur_thread
;
104 /* can only pend on the current thread */
105 /* this is valid from PET mode... */
107 if( cur_thread != chudxnu_current_thread() )
108 panic("pending to non-current thread");
111 /* get our current bits */
112 t_chud
= kperf_get_thread_bits(cur_thread
);
114 /* check if there's anything for us to do */
115 if( t_chud
& T_AST_NAME
)
117 BUF_INFO1( PERF_TI_XSAMPLE
, (uintptr_t)cur_thread
);
119 /* get the name out */
121 /* need kperfbsd.c? */
122 proc_name( context
->cur_pid
,
123 &tex
->p_comm
[0], CHUD_MAXPCOMM
);
126 /* mark that it's done */
127 t_chud
&= ~T_AST_NAME
;
128 t_chud
|= T_NAME_DONE
;
130 kperf_set_thread_bits(cur_thread
, t_chud
);
134 tex
->p_comm
[0] = '\0';
138 /* log it if there's anyting useful there */
140 kperf_threadinfo_extra_log(struct tinfo_ex
*tex
)
143 if( tex
->p_comm
[0] == '\0' )
146 /* FIXME: log more */
147 BUF_DATA1( PERF_TI_XDATA
, (uintptr_t)*(uintptr_t*)&tex
->p_comm
[0] );
150 /* pend a flag on a thread */
152 kperf_threadinfo_extra_pend(struct kperf_context
*context
)
154 return kperf_ast_pend( context
->cur_thread
, T_NAME_DONE
| T_AST_NAME
,
161 /* transalted from the APF */
163 APTIAKernelEntry_t
*threadInfo
= (APTIAKernelEntry_t
*)(threadInfos
+ account
->offset
);
165 context
->timeStamp
= mach_absolute_time();
166 context
->cpuNum
= chudxnu_cpu_number();
168 // record the process info from the callback context
169 context
->pid
= chudxnu_current_pid();
170 threadInfo
->pid
= context
->generic
->pid
;
172 // thread_tid is a thread_t to ID function in the kernel
173 context
->threadID
= chudxnu_current_thread();
174 threadInfo
->tid
= thread_tid(context
->generic
->threadID
);
176 // also a kernel function
177 threadInfo
->dispatch_queue_addr
= thread_dispatchqaddr(context
->generic
->threadID
);
180 threadInfo
->runMode
= AppleProfileGetRunModeOfThread(context
->generic
->threadID
);
183 /****** WTF is this?! *******/
185 /*!enum AppleProfileTriggerClientThreadRunMode
187 * Specifies the thread mode in which to record samples.
189 typedef enum { // Target Thread State - can be OR'd
190 // Basic Building Blocks:
191 // for Time Profile, use kAppleProfileTriggerClientThreadModeRunning (optionally with kAppleProfileTriggerClientThreadModeNotIdle).
192 // for Time Profile (All Thread States), use kAppleProfileTriggerClientThreadModeAny (or just don't specify any thread mode filters).
193 // for Time Profile (Blocked Threads), use kIOProfileTriggerClientThreadModeBlocked.
196 kAppleProfileTriggerClientThreadModeNone
= 0x0,
198 kAppleProfileTriggerClientThreadModeRunning
= 0x1, // On a core
199 kAppleProfileTriggerClientThreadModeRunnable
= 0x2, // TH_RUN
200 kAppleProfileTriggerClientThreadModeBlocked
= 0x4, // TH_WAIT
201 kAppleProfileTriggerClientThreadModeUninterruptible
= 0x8, // TH_UNINT
202 kAppleProfileTriggerClientThreadModeSuspended
= 0x10, // TH_SUSP
203 kAppleProfileTriggerClientThreadModeTerminating
= 0x20, // TH_TERMINATE
204 kAppleProfileTriggerClientThreadModeIdle
= 0x40, // TH_IDLE
206 kAppleProfileTriggerClientThreadModeNotRunning
= kAppleProfileTriggerClientThreadModeRunning
<< 16, // Not on a core
207 kAppleProfileTriggerClientThreadModeNotRunnable
= kAppleProfileTriggerClientThreadModeRunnable
<< 16, // !TH_RUN
208 kAppleProfileTriggerClientThreadModeNotBlocked
= kAppleProfileTriggerClientThreadModeBlocked
<< 16, // !TH_WAIT
209 kAppleProfileTriggerClientThreadModeNotUninterruptible
= kAppleProfileTriggerClientThreadModeUninterruptible
<< 16, // !TH_UNINT
210 kAppleProfileTriggerClientThreadModeNotSuspended
= kAppleProfileTriggerClientThreadModeSuspended
<< 16, // !TH_SUSP
211 kAppleProfileTriggerClientThreadModeNotTerminating
= kAppleProfileTriggerClientThreadModeTerminating
<< 16, // !TH_TERMINATE
212 kAppleProfileTriggerClientThreadModeNotIdle
= kAppleProfileTriggerClientThreadModeIdle
<< 16, // !TH_IDLE
214 kAppleProfileTriggerClientThreadModeAny
= ( kAppleProfileTriggerClientThreadModeRunning
215 | kAppleProfileTriggerClientThreadModeNotRunning
),
216 } AppleProfileTriggerClientThreadRunMode
;
218 extern "C" AppleProfileTriggerClientThreadRunMode
AppleProfileGetRunModeOfThread(thread_t thread
) {
219 const int mode
= chudxnu_thread_get_scheduler_state(thread
);
221 #if !TARGET_OS_EMBEDDED
223 return (chudxnu_thread_get_idle(thread
) ? kAppleProfileTriggerClientThreadModeIdle
: kAppleProfileTriggerClientThreadModeNotIdle
);
226 return (AppleProfileTriggerClientThreadRunMode
)((mode
& 0xffff) | ((~mode
& 0xffff) << 16)); // Today we happen to know there's a one-to-one mapping.