FreeBSD/Linux Kernel Cross Reference
sys/kern/pc_sample.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: pc_sample.c,v $
29 * Revision 2.5 93/11/17 17:17:09 dbg
30 * Made file still build when MACH_PCSAMPLE == 0. Added
31 * ANSI function prototypes. Return current system clock
32 * period (in microseconds!) instead of 'tick'.
33 * [93/03/02 dbg]
34 *
35 * Revision 2.4 93/08/03 12:31:18 mrt
36 * [93/08/02 16:50:13 bershad]
37 *
38 * Flavor support for PC sampling.
39 * [93/07/30 10:23:02 bershad]
40 *
41 * Revision 2.3 93/01/27 09:39:48 danner
42 * take_pc_sample() is void, get_sampled_pcs is static return_t
43 * [93/01/25 jfriedl]
44 *
45 * Revision 2.2 93/01/24 13:19:46 danner
46 * Lots of changes.
47 * [93/01/12 rvb]
48 * Created.
49 * [92/05/10 cmaeda]
50 *
51 */
52
53
54
55 #include <mach_pcsample.h>
56
57 #include <mach/mach_types.h> /* vm_address_t */
58 #include <mach/std_types.h> /* pointer_t */
59 #include <mach/pc_sample.h>
60
61 #include <kern/clock.h>
62 #include <kern/host.h>
63 #include <kern/kern_io.h>
64 #include <kern/memory.h>
65 #include <kern/thread.h>
66 #include <kern/pc_sample.h>
67
68 #if MACH_PCSAMPLE
69
70 #define MAX_PC_SAMPLES 512
71
72 typedef sampled_pc_t sampled_pcs[MAX_PC_SAMPLES];
73
74 int pc_sampling_enabled = 0;
75 decl_simple_lock_data(, pc_sampling_lock) /* lock for enabling */
76
77 void take_pc_sample(
78 register thread_t t,
79 register sample_control_t *cp,
80 sampled_pc_flavor_t flavor)
81 {
82 vm_offset_t pc;
83 struct sampled_pc *sample;
84
85 pc = INTERRUPTED_PC(t);
86 cp->seqno++;
87 sample = &((sampled_pc_t *)cp->buffer)[cp->seqno % MAX_PC_SAMPLES];
88 sample->id = (natural_t)t;
89 sample->pc = pc;
90 sample->sampletype = flavor;
91 }
92
93 kern_return_t
94 thread_enable_pc_sampling(
95 thread_t thread,
96 int *tickp,
97 sampled_pc_flavor_t flavors)
98 {
99 vm_offset_t buf;
100
101 if (thread == THREAD_NULL) {
102 return KERN_INVALID_ARGUMENT;
103 }
104 if (thread->pc_sample.buffer == 0) {
105 buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
106 if (buf == 0) {
107 printf("thread_enable_pc_sampling: kalloc failed\n");
108 return KERN_INVALID_ARGUMENT;
109 }
110 thread->pc_sample.buffer = buf;
111 thread->pc_sample.seqno = 0;
112 }
113 *tickp = sys_clock->resolution / 1000; /* nanosec -> microsec */
114 thread->pc_sample.sampletypes = flavors;
115 return KERN_SUCCESS;
116 }
117
118 kern_return_t
119 task_enable_pc_sampling(
120 task_t task,
121 int *tickp,
122 sampled_pc_flavor_t flavors)
123 {
124 vm_offset_t buf;
125
126 if (task == TASK_NULL) {
127 return KERN_INVALID_ARGUMENT;
128 }
129 if (task->pc_sample.buffer == 0) {
130 buf = (vm_offset_t) kalloc(sizeof (sampled_pcs));
131 if (buf == 0) {
132 printf("task_enable_pc_sampling: kalloc failed\n");
133 return KERN_INVALID_ARGUMENT;
134 }
135 task->pc_sample.buffer = buf;
136 task->pc_sample.seqno = 0;
137 }
138 *tickp = sys_clock->resolution / 1000; /* nanosec -> microsec */
139 task->pc_sample.sampletypes = flavors;
140 return KERN_SUCCESS;
141 }
142
143 kern_return_t
144 thread_disable_pc_sampling(
145 thread_t thread,
146 int *samplecntp)
147 {
148 vm_offset_t buf;
149
150 if (thread == THREAD_NULL) {
151 return KERN_INVALID_ARGUMENT;
152 }
153 if ((buf = thread->pc_sample.buffer) != 0)
154 kfree(buf, sizeof (sampled_pcs));
155 thread->pc_sample.buffer = (vm_offset_t) 0;
156 thread->pc_sample.seqno = 0;
157 thread->pc_sample.sampletypes = 0; /* shut off sampling */
158
159 return KERN_SUCCESS;
160 }
161
162 kern_return_t
163 task_disable_pc_sampling(
164 task_t task,
165 int *samplecntp)
166 {
167 vm_offset_t buf;
168
169 if (task == TASK_NULL) {
170 return KERN_INVALID_ARGUMENT;
171 }
172 if ((buf = task->pc_sample.buffer) != 0)
173 kfree(buf, sizeof (sampled_pcs));
174 task->pc_sample.buffer = (vm_offset_t) 0;
175 task->pc_sample.seqno = 0;
176 task->pc_sample.sampletypes = 0; /* shut off sampling */
177
178 return KERN_SUCCESS;
179 }
180
181 static kern_return_t
182 get_sampled_pcs(
183 sample_control_t *cp,
184 sampled_pc_seqno_t *seqnop,
185 sampled_pc_array_t sampled_pcs_out,
186 int *sampled_pcs_cntp)
187 {
188 int nsamples;
189 sampled_pc_seqno_t seqidx1, seqidx2;
190
191 nsamples = cp->seqno - *seqnop;
192 seqidx1 = *seqnop % MAX_PC_SAMPLES; /* index of *seqnop */
193 seqidx2 = cp->seqno % MAX_PC_SAMPLES; /* index of cp->seqno */
194
195 if (nsamples > MAX_PC_SAMPLES) {
196 nsamples = MAX_PC_SAMPLES;
197 seqidx1 = (seqidx2 + 1) % MAX_PC_SAMPLES;
198 }
199
200 if (nsamples > 0) {
201 /*
202 * Carefully copy sampled_pcs into sampled_pcs_msgbuf IN ORDER.
203 */
204 if (seqidx1 < seqidx2) {
205 /*
206 * Simple case: no wraparound.
207 * Copy from seqidx1 to seqidx2.
208 */
209 bcopy((sampled_pc_array_t)cp->buffer + seqidx1 + 1,
210 sampled_pcs_out,
211 nsamples * sizeof(sampled_pc_t));
212 } else {
213 /* seqidx1 > seqidx2 -- Handle wraparound. */
214
215 bcopy((sampled_pc_array_t)cp->buffer + seqidx1 + 1,
216 sampled_pcs_out,
217 (MAX_PC_SAMPLES - seqidx1 - 1) * sizeof(sampled_pc_t));
218
219 bcopy((sampled_pc_array_t)cp->buffer,
220 sampled_pcs_out + (MAX_PC_SAMPLES - seqidx1 - 1),
221 (seqidx2 + 1) * sizeof(sampled_pc_t));
222 }
223 } else {
224 /* could either be zero because of overflow, or because
225 * we are being lied to. In either case, return nothing.
226 * If overflow, only once in a blue moon. If being lied to,
227 * then we have no obligation to return anything useful anyway.
228 */
229 ;
230 }
231
232 *sampled_pcs_cntp = nsamples;
233 *seqnop = cp->seqno;
234 return KERN_SUCCESS;
235 }
236
237 kern_return_t
238 thread_get_sampled_pcs(
239 thread_t thread,
240 sampled_pc_seqno_t *seqnop,
241 sampled_pc_array_t sampled_pcs_out,
242 int *sampled_pcs_cntp)
243 {
244 if (thread == THREAD_NULL)
245 return KERN_INVALID_ARGUMENT;
246
247 if (thread->pc_sample.buffer == 0)
248 return KERN_FAILURE;
249
250 return get_sampled_pcs(&thread->pc_sample, seqnop, sampled_pcs_out,
251 sampled_pcs_cntp);
252 }
253
254 kern_return_t
255 task_get_sampled_pcs(
256 task_t task,
257 sampled_pc_seqno_t *seqnop,
258 sampled_pc_array_t sampled_pcs_out,
259 int *sampled_pcs_cntp)
260 {
261 if (task == TASK_NULL)
262 return KERN_INVALID_ARGUMENT;
263
264 if (task->pc_sample.buffer == 0)
265 return KERN_FAILURE;
266
267 return get_sampled_pcs(&task->pc_sample, seqnop, sampled_pcs_out,
268 sampled_pcs_cntp);
269 }
270
271 #else /* MACH_PCSAMPLE */
272
273 kern_return_t
274 thread_enable_pc_sampling(
275 thread_t thread,
276 int *tickp,
277 sampled_pc_flavor_t flavors)
278 {
279 return KERN_FAILURE; /* not implemented */
280 }
281
282 kern_return_t
283 task_enable_pc_sampling(
284 task_t task;
285 int *tickp,
286 sampled_pc_flavor_t flavors)
287 {
288 return KERN_FAILURE; /* not implemented */
289 }
290
291 kern_return_t
292 thread_disable_pc_sampling(
293 thread_t thread,
294 int *samplecntp)
295 {
296 return KERN_FAILURE; /* not implemented */
297 }
298
299 kern_return_t
300 task_disable_pc_sampling(
301 task_t task,
302 int *samplecntp)
303 {
304 return KERN_FAILURE; /* not implemented */
305 }
306
307 kern_return_t
308 thread_get_sampled_pcs(
309 thread_t thread,
310 sampled_pc_seqno_t *seqnop,
311 sampled_pc_array_t sampled_pcs_out,
312 int *sampled_pcs_cntp)
313 {
314 return KERN_FAILURE; /* not implemented */
315 }
316
317 kern_return_t
318 task_get_sampled_pcs(
319 task_t task,
320 sampled_pc_seqno_t *seqnop,
321 sampled_pc_array_t sampled_pcs_out,
322 int *sampled_pcs_cntp)
323 {
324 return KERN_FAILURE; /* not implemented */
325 }
326
327 #endif /* MACH_PCSAMPLE */
Cache object: bec19ddf295cd76f45b0072bf8e65f5b
|