]>
Commit | Line | Data |
---|---|---|
316670eb A |
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 | ||
29 | ||
30 | /* Sample thread data */ | |
31 | ||
32 | #include <mach/mach_types.h> | |
33 | #include <kern/thread.h> /* thread_* */ | |
34 | #include <kern/debug.h> /* panic */ | |
35 | // #include <sys/proc.h> | |
36 | ||
37 | #include <chud/chud_xnu.h> | |
38 | #include <kperf/kperf.h> | |
39 | ||
40 | #include <kperf/buffer.h> | |
41 | #include <kperf/context.h> | |
42 | #include <kperf/threadinfo.h> | |
43 | #include <kperf/ast.h> | |
44 | ||
45 | // kAppleProfileTriggerClientThreadModeIdle = 0x40, // TH_IDLE | |
46 | // #define TH_IDLE 0x40 | |
47 | ||
48 | //kAppleProfileTriggerClientThreadModeNotIdle = kAppleProfileTriggerClientThreadModeIdle << 16, // !TH_IDLE | |
49 | #define TH_IDLE_N (TH_IDLE << 16) | |
50 | ||
51 | static uint64_t | |
52 | make_runmode(thread_t thread) | |
53 | { | |
54 | /* CEG: This is a translation of | |
55 | * AppleProfileGetRunModeOfThread below... kinda magic :/ | |
56 | */ | |
57 | const int mode = chudxnu_thread_get_scheduler_state(thread); | |
58 | ||
316670eb A |
59 | if( 0 == mode) |
60 | { | |
61 | return (chudxnu_thread_get_idle(thread) ? TH_IDLE : TH_IDLE_N); | |
62 | } | |
63 | else | |
39236c6e | 64 | { |
316670eb A |
65 | // Today we happen to know there's a one-to-one mapping. |
66 | return ((mode & 0xffff) | ((~mode & 0xffff) << 16)); | |
39236c6e | 67 | } |
316670eb A |
68 | } |
69 | ||
70 | ||
71 | /* code to collect current thread info */ | |
72 | void | |
73 | kperf_threadinfo_sample(struct threadinfo *ti, struct kperf_context *context) | |
74 | { | |
75 | thread_t cur_thread = context->cur_thread; | |
3e170ce0 | 76 | BUF_INFO1( PERF_TI_SAMPLE, (uintptr_t)thread_tid(cur_thread) ); |
316670eb A |
77 | |
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); | |
83 | } | |
84 | ||
85 | /* log an existing sample into the buffer */ | |
86 | void | |
87 | kperf_threadinfo_log(struct threadinfo *ti) | |
88 | { | |
89 | /* XXX: K64 only? */ | |
90 | BUF_DATA( PERF_TI_DATA, ti->pid, ti->tid, ti->dq_addr, ti->runmode ); | |
91 | } | |
92 | ||
93 | /* 'extra' thread-info functions that are deferred 'til thread-context | |
94 | * time | |
95 | */ | |
96 | void | |
97 | kperf_threadinfo_extra_sample(struct tinfo_ex *tex, struct kperf_context *context) | |
98 | { | |
99 | thread_t cur_thread = context->cur_thread; | |
100 | uint32_t t_chud; | |
101 | ||
102 | /* can only pend on the current thread */ | |
103 | /* this is valid from PET mode... */ | |
104 | /* | |
105 | if( cur_thread != chudxnu_current_thread() ) | |
106 | panic("pending to non-current thread"); | |
107 | */ | |
108 | ||
109 | /* get our current bits */ | |
110 | t_chud = kperf_get_thread_bits(cur_thread); | |
111 | ||
112 | /* check if there's anything for us to do */ | |
113 | if( t_chud & T_AST_NAME ) | |
114 | { | |
3e170ce0 | 115 | BUF_INFO1( PERF_TI_XSAMPLE, (uintptr_t)thread_tid(cur_thread) ); |
316670eb A |
116 | |
117 | /* get the name out */ | |
118 | #ifdef FIXME | |
119 | /* need kperfbsd.c? */ | |
120 | proc_name( context->cur_pid, | |
121 | &tex->p_comm[0], CHUD_MAXPCOMM ); | |
122 | #endif | |
123 | ||
124 | /* mark that it's done */ | |
125 | t_chud &= ~T_AST_NAME; | |
126 | t_chud |= T_NAME_DONE; | |
127 | ||
128 | kperf_set_thread_bits(cur_thread, t_chud); | |
129 | } | |
130 | else | |
131 | /* empty string */ | |
132 | tex->p_comm[0] = '\0'; | |
133 | ||
134 | } | |
135 | ||
136 | /* log it if there's anyting useful there */ | |
137 | void | |
138 | kperf_threadinfo_extra_log(struct tinfo_ex *tex) | |
139 | { | |
140 | /* no data */ | |
141 | if( tex->p_comm[0] == '\0' ) | |
142 | return; | |
143 | ||
144 | /* FIXME: log more */ | |
145 | BUF_DATA1( PERF_TI_XDATA, (uintptr_t)*(uintptr_t*)&tex->p_comm[0] ); | |
146 | } | |
147 | ||
148 | /* pend a flag on a thread */ | |
149 | int | |
150 | kperf_threadinfo_extra_pend(struct kperf_context *context) | |
151 | { | |
152 | return kperf_ast_pend( context->cur_thread, T_NAME_DONE | T_AST_NAME, | |
153 | T_AST_NAME ); | |
154 | } | |
155 | ||
156 | ||
157 | #if 0 | |
158 | ||
159 | /* transalted from the APF */ | |
160 | ||
161 | APTIAKernelEntry_t *threadInfo = (APTIAKernelEntry_t*)(threadInfos + account->offset); | |
162 | ||
163 | context->timeStamp = mach_absolute_time(); | |
164 | context->cpuNum = chudxnu_cpu_number(); | |
165 | ||
166 | // record the process info from the callback context | |
167 | context->pid = chudxnu_current_pid(); | |
168 | threadInfo->pid = context->generic->pid; | |
169 | ||
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); | |
173 | ||
174 | // also a kernel function | |
175 | threadInfo->dispatch_queue_addr = thread_dispatchqaddr(context->generic->threadID); | |
176 | ||
177 | // see below | |
178 | threadInfo->runMode = AppleProfileGetRunModeOfThread(context->generic->threadID); | |
179 | ||
180 | ||
181 | /****** WTF is this?! *******/ | |
182 | ||
183 | /*!enum AppleProfileTriggerClientThreadRunMode | |
184 | * | |
185 | * Specifies the thread mode in which to record samples. | |
186 | */ | |
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. | |
192 | // etc... | |
193 | ||
194 | kAppleProfileTriggerClientThreadModeNone = 0x0, | |
195 | ||
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 | |
203 | ||
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 | |
211 | ||
212 | kAppleProfileTriggerClientThreadModeAny = ( kAppleProfileTriggerClientThreadModeRunning | |
213 | | kAppleProfileTriggerClientThreadModeNotRunning), | |
214 | } AppleProfileTriggerClientThreadRunMode; | |
215 | ||
216 | extern "C" AppleProfileTriggerClientThreadRunMode AppleProfileGetRunModeOfThread(thread_t thread) { | |
217 | const int mode = chudxnu_thread_get_scheduler_state(thread); | |
218 | ||
316670eb A |
219 | if (0 == mode) { |
220 | return (chudxnu_thread_get_idle(thread) ? kAppleProfileTriggerClientThreadModeIdle : kAppleProfileTriggerClientThreadModeNotIdle); | |
221 | } else | |
316670eb A |
222 | return (AppleProfileTriggerClientThreadRunMode)((mode & 0xffff) | ((~mode & 0xffff) << 16)); // Today we happen to know there's a one-to-one mapping. |
223 | } | |
224 | ||
225 | #endif |