FreeBSD/Linux Kernel Cross Reference
sys/kern/pc_sample.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990,1989 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.4 93/08/03 12:31:18 mrt
30 * [93/08/02 16:50:13 bershad]
31 *
32 * Flavor support for PC sampling.
33 * [93/07/30 10:23:02 bershad]
34 *
35 * Revision 2.3 93/01/27 09:39:48 danner
36 * take_pc_sample() is void, get_sampled_pcs is static return_t
37 * [93/01/25 jfriedl]
38 *
39 * Revision 2.2 93/01/24 13:19:46 danner
40 * Lots of changes.
41 * [93/01/12 rvb]
42 * Created.
43 * [92/05/10 cmaeda]
44 *
45 */
46
47
48
49 #include <mach_pcsample.h>
50
51 #if MACH_PCSAMPLE > 0
52
53
54 #include <mach/mach_types.h> /* vm_address_t */
55 #include <mach/std_types.h> /* pointer_t */
56 #include <mach/pc_sample.h>
57 #include <kern/host.h>
58 #include <kern/thread.h>
59
60 #define MAX_PC_SAMPLES 512
61
62 typedef sampled_pc_t sampled_pcs[MAX_PC_SAMPLES];
63
64 int pc_sampling_enabled = 0;
65 decl_simple_lock_data(, pc_sampling_lock) /* lock for enabling */
66
67 void take_pc_sample(t, cp, flavor)
68 register thread_t t;
69 register sample_control_t *cp;
70 sampled_pc_flavor_t flavor;
71 {
72 unsigned pc;
73 struct sampled_pc *sample;
74
75 pc = interrupted_pc(t);
76 cp->seqno++;
77 sample = &((sampled_pc_t *)cp->buffer)[cp->seqno % MAX_PC_SAMPLES];
78 sample->id = (unsigned int)t;
79 sample->pc = pc;
80 sample->sampletype = flavor;
81 }
82
83 kern_return_t
84 thread_enable_pc_sampling(thread, tickp, flavors)
85 thread_t thread;
86 int *tickp;
87 sampled_pc_flavor_t flavors;
88 {
89 vm_offset_t buf;
90 extern int tick;
91
92 if (thread == THREAD_NULL) {
93 return KERN_INVALID_ARGUMENT;
94 }
95 if (!thread->pc_sample.buffer) {
96 if (!(int) (buf = (vm_offset_t) kalloc(sizeof (sampled_pcs)))) {
97 printf("thread_enable_pc_sampling: kalloc failed\n");
98 return KERN_INVALID_ARGUMENT;
99 }
100 thread->pc_sample.buffer = buf;
101 thread->pc_sample.seqno = 0;
102 }
103 *tickp = tick;
104 thread->pc_sample.sampletypes = flavors;
105 return KERN_SUCCESS;
106 }
107
108 kern_return_t
109 task_enable_pc_sampling(task, tickp, flavors)
110 task_t task;
111 int *tickp;
112 sampled_pc_flavor_t flavors;
113 {
114 vm_offset_t buf;
115 extern int tick;
116
117 if (task == TASK_NULL) {
118 return KERN_INVALID_ARGUMENT;
119 }
120 if (!task->pc_sample.buffer) {
121 if (!(int) (buf = (vm_offset_t) kalloc(sizeof (sampled_pcs)))) {
122 printf("task_enable_pc_sampling: kalloc failed\n");
123 return KERN_INVALID_ARGUMENT;
124 }
125 task->pc_sample.buffer = buf;
126 task->pc_sample.seqno = 0;
127 }
128 *tickp = tick;
129 task->pc_sample.sampletypes = flavors;
130 return KERN_SUCCESS;
131 }
132
133 kern_return_t
134 thread_disable_pc_sampling(thread, samplecntp)
135 thread_t thread;
136 int *samplecntp;
137 {
138 vm_offset_t buf;
139
140 if (thread == THREAD_NULL) {
141 return KERN_INVALID_ARGUMENT;
142 }
143 if (buf = thread->pc_sample.buffer)
144 kfree(buf, sizeof (sampled_pcs));
145 thread->pc_sample.buffer = (vm_offset_t) 0;
146 thread->pc_sample.seqno = 0;
147
148 return KERN_SUCCESS;
149 }
150
151 kern_return_t
152 task_disable_pc_sampling(task, samplecntp)
153 task_t task;
154 int *samplecntp;
155 {
156 vm_offset_t buf;
157
158 if (task == TASK_NULL) {
159 return KERN_INVALID_ARGUMENT;
160 }
161 if (buf = task->pc_sample.buffer)
162 kfree(buf, sizeof (sampled_pcs));
163 task->pc_sample.buffer = (vm_offset_t) 0;
164 task->pc_sample.seqno = 0;
165
166 return KERN_SUCCESS;
167 }
168
169 static kern_return_t
170 get_sampled_pcs(cp, seqnop, sampled_pcs_out, sampled_pcs_cntp)
171 sample_control_t *cp;
172 sampled_pc_seqno_t *seqnop;
173 sampled_pc_array_t sampled_pcs_out;
174 int *sampled_pcs_cntp;
175 {
176 int nsamples;
177 sampled_pc_seqno_t seqidx1, seqidx2;
178
179 nsamples = cp->seqno - *seqnop;
180 seqidx1 = *seqnop % MAX_PC_SAMPLES; /* index of *seqnop */
181 seqidx2 = cp->seqno % MAX_PC_SAMPLES; /* index of cp->seqno */
182
183 if (nsamples > MAX_PC_SAMPLES) {
184 nsamples = MAX_PC_SAMPLES;
185 seqidx1 = (seqidx2 + 1) % MAX_PC_SAMPLES;
186 }
187
188 if (nsamples > 0) {
189 /*
190 * Carefully copy sampled_pcs into sampled_pcs_msgbuf IN ORDER.
191 */
192 if (seqidx1 < seqidx2) {
193 /*
194 * Simple case: no wraparound.
195 * Copy from seqidx1 to seqidx2.
196 */
197 bcopy((sampled_pc_array_t)cp->buffer + seqidx1 + 1,
198 sampled_pcs_out,
199 nsamples * sizeof(sampled_pc_t));
200 } else {
201 /* seqidx1 > seqidx2 -- Handle wraparound. */
202
203 bcopy((sampled_pc_array_t)cp->buffer + seqidx1 + 1,
204 sampled_pcs_out,
205 (MAX_PC_SAMPLES - seqidx1 - 1) * sizeof(sampled_pc_t));
206
207 bcopy((sampled_pc_array_t)cp->buffer,
208 sampled_pcs_out + (MAX_PC_SAMPLES - seqidx1 - 1),
209 (seqidx2 + 1) * sizeof(sampled_pc_t));
210 }
211 } else {
212 /* could either be zero because of overflow, or because
213 * we are being lied to. In either case, return nothing.
214 * If overflow, only once in a blue moon. If being lied to,
215 * then we have no obligation to return anything useful anyway.
216 */
217 ;
218 }
219
220 *sampled_pcs_cntp = nsamples;
221 *seqnop = cp->seqno;
222 return KERN_SUCCESS;
223 }
224
225 kern_return_t
226 thread_get_sampled_pcs(thread, seqnop, sampled_pcs_out, sampled_pcs_cntp)
227 thread_t thread;
228 sampled_pc_seqno_t *seqnop;
229 sampled_pc_array_t sampled_pcs_out;
230 int *sampled_pcs_cntp;
231 {
232 if (thread == THREAD_NULL)
233 return KERN_INVALID_ARGUMENT;
234
235 if ((int)thread->pc_sample.buffer == 0)
236 return KERN_FAILURE;
237
238 return get_sampled_pcs(&thread->pc_sample, seqnop, sampled_pcs_out, sampled_pcs_cntp);
239 }
240
241 kern_return_t
242 task_get_sampled_pcs(task, seqnop, sampled_pcs_out, sampled_pcs_cntp)
243 task_t task;
244 sampled_pc_seqno_t *seqnop;
245 sampled_pc_array_t sampled_pcs_out;
246 int *sampled_pcs_cntp;
247 {
248 int nsamples;
249 sampled_pc_seqno_t seqidx1, seqidx2;
250
251 if (task == TASK_NULL)
252 return KERN_INVALID_ARGUMENT;
253
254 if ((int)task->pc_sample.buffer == 0)
255 return KERN_FAILURE;
256
257 return get_sampled_pcs(&task->pc_sample, seqnop, sampled_pcs_out, sampled_pcs_cntp);
258
259 }
260
261
262 #endif /* MACH_PCSAMPLE > 0 */
263
Cache object: 12c0aae8671352378d0f2f30d8bb1f93
|