]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/lock_mon.c
xnu-201.tar.gz
[apple/xnu.git] / osfmk / kern / lock_mon.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * @OSF_COPYRIGHT@
24 */
25 /*
26 * HISTORY
27 *
28 * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez
29 * Import of Mac OS X kernel (~semeria)
30 *
31 * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez
32 * Import of OSF Mach kernel (~mburg)
33 *
34 * Revision 1.3.19.1 1997/09/22 17:39:46 barbou
35 * MP+RT: protect cpu_number() usage against preemption.
36 * [97/09/16 barbou]
37 *
38 * Revision 1.3.15.4 1995/02/24 15:20:58 alanl
39 * DIPC: Merge from nmk17b2 to nmk18b8.
40 * Notes: major lock cleanup. Change kdb_lock and printf_lock
41 * references to conform with simple_lock declaration rules.
42 * This code is broken and non-portable; its functionality
43 * should be subsumed in the regular lock package.
44 * [95/01/16 alanl]
45 *
46 * Revision 1.3.17.2 1994/11/10 06:13:19 dwm
47 * mk6 CR764 - s/spinlock/simple_lock/ (name change only)
48 * [1994/11/10 05:28:52 dwm]
49 *
50 * Revision 1.3.17.1 1994/11/04 10:07:54 dwm
51 * mk6 CR668 - 1.3b26 merge
52 * This file is obviously UNUSED - hence broken; merged anyway
53 * * Revision 1.3.4.4 1994/05/06 18:50:11 tmt
54 * Merge in DEC Alpha changes to osc1.3b19.
55 * Merge Alpha changes into osc1.312b source code.
56 * 64bit cleanup.
57 * * End1.3merge
58 * [1994/11/04 09:25:58 dwm]
59 *
60 * Revision 1.3.15.1 1994/09/23 02:21:48 ezf
61 * change marker to not FREE
62 * [1994/09/22 21:34:22 ezf]
63 *
64 * Revision 1.3.13.1 1994/06/09 14:11:30 dswartz
65 * Preemption merge.
66 * [1994/06/09 14:07:06 dswartz]
67 *
68 * Revision 1.3.4.2 1993/06/09 02:36:12 gm
69 * Added to OSF/1 R1.3 from NMK15.0.
70 * [1993/06/02 21:13:15 jeffc]
71 *
72 * Revision 1.3 1993/04/19 16:26:56 devrcs
73 * Fix for TIME_STAMP configuration.
74 * [Patrick Petit <petit@gr.osf.org>]
75 * [93/02/11 bernadat]
76 *
77 * Revision 1.2 1992/11/25 01:11:05 robert
78 * integrate changes below for norma_14
79 *
80 * Philippe Bernadat (bernadat) at gr.osf.org
81 * Moved MACH_MP_DEBUG code to kern/lock.c
82 * [1992/11/13 19:33:47 robert]
83 *
84 * Revision 1.1 1992/09/30 02:09:28 robert
85 * Initial revision
86 *
87 * $EndLog$
88 */
89 /* CMU_HIST */
90 /*
91 * Revision 2.1.2.1.3.1 92/02/18 19:08:45 jeffreyh
92 * Created. Might need some work if used on anything but a 386.
93 * [92/02/11 07:56:50 bernadat]
94 */
95 /* CMU_ENDHIST */
96
97 /*
98 * Mach Operating System
99 * Copyright (c) 1990 Carnegie-Mellon University
100 * Copyright (c) 1989 Carnegie-Mellon University
101 * All rights reserved. The CMU software License Agreement specifies
102 * the terms and conditions for use and redistribution.
103 */
104
105 /*
106 */
107
108 /*
109 * Support For MP Debugging
110 * if MACH_MP_DEBUG is on, we use alternate locking
111 * routines do detect dealocks
112 * Support for MP lock monitoring (MACH_LOCK_MON).
113 * Registers use of locks, contention.
114 * Depending on hardware also records time spent with locks held
115 */
116
117 #include <cpus.h>
118 #include <mach_mp_debug.h>
119 #include <mach_lock_mon.h>
120 #include <time_stamp.h>
121
122 #include <sys/types.h>
123 #include <mach/machine/vm_types.h>
124 #include <mach/boolean.h>
125 #include <kern/thread.h>
126 #include <kern/lock.h>
127
128
129 decl_simple_lock_data(extern, kdb_lock)
130 decl_simple_lock_data(extern, printf_lock)
131
132 #if NCPUS > 1 && MACH_LOCK_MON
133
134 #if TIME_STAMP
135 extern time_stamp_t time_stamp;
136 #else TIME_STAMP
137 typedef unsigned int time_stamp_t;
138 #define time_stamp 0
139 #endif TIME_STAMP
140
141 #define LOCK_INFO_MAX (1024*32)
142 #define LOCK_INFO_HASH_COUNT 1024
143 #define LOCK_INFO_PER_BUCKET (LOCK_INFO_MAX/LOCK_INFO_HASH_COUNT)
144
145
146 #define HASH_LOCK(lock) ((long)lock>>5 & (LOCK_INFO_HASH_COUNT-1))
147
148 struct lock_info {
149 unsigned int success;
150 unsigned int fail;
151 unsigned int masked;
152 unsigned int stack;
153 unsigned int time;
154 #if MACH_SLOCKS
155 simple_lock_data_t * lock;
156 #endif
157 vm_offset_t caller;
158 };
159
160 struct lock_info_bucket {
161 struct lock_info info[LOCK_INFO_PER_BUCKET];
162 };
163
164 struct lock_info_bucket lock_info[LOCK_INFO_HASH_COUNT];
165 struct lock_info default_lock_info;
166 unsigned default_lock_stack = 0;
167
168 extern int curr_ipl[];
169
170
171
172 struct lock_info *
173 locate_lock_info(lock)
174 simple_lock_data_t ** lock;
175 {
176 struct lock_info *li = &(lock_info[HASH_LOCK(*lock)].info[0]);
177 register i;
178
179 for (i=0; i < LOCK_INFO_PER_BUCKET; i++, li++)
180 if (li->lock) {
181 if (li->lock == *lock)
182 return(li);
183 } else {
184 li->lock = *lock;
185 li->caller = *((vm_offset_t *)lock - 1);
186 return(li);
187 }
188 db_printf("out of lock_info slots\n");
189 li = &default_lock_info;
190 return(li);
191 }
192
193
194 simple_lock(lock)
195 decl_simple_lock_data(, *lock)
196 {
197 register struct lock_info *li = locate_lock_info(&lock);
198
199 if (current_thread())
200 li->stack = current_thread()->lock_stack++;
201 mp_disable_preemption();
202 if (curr_ipl[cpu_number()])
203 li->masked++;
204 mp_enable_preemption();
205 if (_simple_lock_try(lock))
206 li->success++;
207 else {
208 _simple_lock(lock);
209 li->fail++;
210 }
211 li->time = time_stamp - li->time;
212 }
213
214 simple_lock_try(lock)
215 decl_simple_lock_data(, *lock)
216 {
217 register struct lock_info *li = locate_lock_info(&lock);
218
219 mp_disable_preemption();
220 if (curr_ipl[cpu_number()])
221 li->masked++;
222 mp_enable_preemption();
223 if (_simple_lock_try(lock)) {
224 li->success++;
225 li->time = time_stamp - li->time;
226 if (current_thread())
227 li->stack = current_thread()->lock_stack++;
228 return(1);
229 } else {
230 li->fail++;
231 return(0);
232 }
233 }
234
235 simple_unlock(lock)
236 decl_simple_lock_data(, *lock)
237 {
238 register time_stamp_t stamp = time_stamp;
239 register time_stamp_t *time = &locate_lock_info(&lock)->time;
240 register unsigned *lock_stack;
241
242 *time = stamp - *time;
243 _simple_unlock(lock);
244 if (current_thread()) {
245 lock_stack = &current_thread()->lock_stack;
246 if (*lock_stack)
247 (*lock_stack)--;
248 }
249 }
250
251 lip() {
252 lis(4, 1, 0);
253 }
254
255 #define lock_info_sort lis
256
257 unsigned scurval, ssum;
258 struct lock_info *sli;
259
260 lock_info_sort(arg, abs, count)
261 {
262 struct lock_info *li, mean;
263 int bucket = 0;
264 int i;
265 unsigned max_val;
266 unsigned old_val = (unsigned)-1;
267 struct lock_info *target_li = &lock_info[0].info[0];
268 unsigned sum;
269 unsigned empty, total;
270 unsigned curval;
271
272 printf("\nSUCCESS FAIL MASKED STACK TIME LOCK/CALLER\n");
273 if (!count)
274 count = 8 ;
275 while (count && target_li) {
276 empty = LOCK_INFO_HASH_COUNT;
277 target_li = 0;
278 total = 0;
279 max_val = 0;
280 mean.success = 0;
281 mean.fail = 0;
282 mean.masked = 0;
283 mean.stack = 0;
284 mean.time = 0;
285 mean.lock = (simple_lock_data_t *) &lock_info;
286 mean.caller = (vm_offset_t) &lock_info;
287 for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
288 li = &lock_info[bucket].info[0];
289 if (li->lock)
290 empty--;
291 for (i= 0; i< LOCK_INFO_PER_BUCKET && li->lock; i++, li++) {
292 if (li->lock == &kdb_lock || li->lock == &printf_lock)
293 continue;
294 total++;
295 curval = *((int *)li + arg);
296 sum = li->success + li->fail;
297 if(!sum && !abs)
298 continue;
299 scurval = curval;
300 ssum = sum;
301 sli = li;
302 if (!abs) switch(arg) {
303 case 0:
304 break;
305 case 1:
306 case 2:
307 curval = (curval*100) / sum;
308 break;
309 case 3:
310 case 4:
311 curval = curval / sum;
312 break;
313 }
314 if (curval > max_val && curval < old_val) {
315 max_val = curval;
316 target_li = li;
317 }
318 if (curval == old_val && count != 0) {
319 print_lock_info(li);
320 count--;
321 }
322 mean.success += li->success;
323 mean.fail += li->fail;
324 mean.masked += li->masked;
325 mean.stack += li->stack;
326 mean.time += li->time;
327 }
328 }
329 if (target_li)
330 old_val = max_val;
331 }
332 db_printf("\n%d total locks, %d empty buckets", total, empty );
333 if (default_lock_info.success)
334 db_printf(", default: %d", default_lock_info.success + default_lock_info.fail);
335 db_printf("\n");
336 print_lock_info(&mean);
337 }
338
339 #define lock_info_clear lic
340
341 lock_info_clear()
342 {
343 struct lock_info *li;
344 int bucket = 0;
345 int i;
346 for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
347 li = &lock_info[bucket].info[0];
348 for (i= 0; i< LOCK_INFO_PER_BUCKET; i++, li++) {
349 bzero(li, sizeof(struct lock_info));
350 }
351 }
352 bzero(&default_lock_info, sizeof(struct lock_info));
353 }
354
355 print_lock_info(li)
356 struct lock_info *li;
357 {
358 int off;
359 int sum = li->success + li->fail;
360 db_printf("%d %d/%d %d/%d %d/%d %d/%d ", li->success,
361 li->fail, (li->fail*100)/sum,
362 li->masked, (li->masked*100)/sum,
363 li->stack, li->stack/sum,
364 li->time, li->time/sum);
365 db_search_symbol(li->lock, 0, &off);
366 if (off < 1024)
367 db_printsym(li->lock, 0);
368 else {
369 db_printsym(li->caller, 0);
370 db_printf("(%X)", li->lock);
371 }
372 db_printf("\n");
373 }
374
375 #endif NCPUS > 1 && MACH_LOCK_MON
376
377 #if TIME_STAMP
378
379 /*
380 * Measure lock/unlock operations
381 */
382
383 time_lock(loops)
384 {
385 decl_simple_lock_data(, lock)
386 register time_stamp_t stamp;
387 register int i;
388
389
390 if (!loops)
391 loops = 1000;
392 simple_lock_init(&lock);
393 stamp = time_stamp;
394 for (i = 0; i < loops; i++) {
395 simple_lock(&lock);
396 simple_unlock(&lock);
397 }
398 stamp = time_stamp - stamp;
399 db_printf("%d stamps for simple_locks\n", stamp/loops);
400 #if MACH_LOCK_MON
401 stamp = time_stamp;
402 for (i = 0; i < loops; i++) {
403 _simple_lock(&lock);
404 _simple_unlock(&lock);
405 }
406 stamp = time_stamp - stamp;
407 db_printf("%d stamps for _simple_locks\n", stamp/loops);
408 #endif MACH_LOCK_MON
409 }
410 #endif TIME_STAMP
411
412
413
414
415