2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
28 * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez
29 * Import of Mac OS X kernel (~semeria)
31 * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez
32 * Import of OSF Mach kernel (~mburg)
34 * Revision 1.3.19.1 1997/09/22 17:39:46 barbou
35 * MP+RT: protect cpu_number() usage against preemption.
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.
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]
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.
58 * [1994/11/04 09:25:58 dwm]
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]
64 * Revision 1.3.13.1 1994/06/09 14:11:30 dswartz
66 * [1994/06/09 14:07:06 dswartz]
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]
72 * Revision 1.3 1993/04/19 16:26:56 devrcs
73 * Fix for TIME_STAMP configuration.
74 * [Patrick Petit <petit@gr.osf.org>]
77 * Revision 1.2 1992/11/25 01:11:05 robert
78 * integrate changes below for norma_14
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]
84 * Revision 1.1 1992/09/30 02:09:28 robert
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]
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.
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
118 #include <mach_mp_debug.h>
119 #include <mach_lock_mon.h>
120 #include <time_stamp.h>
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>
129 decl_simple_lock_data(extern, kdb_lock
)
130 decl_simple_lock_data(extern, printf_lock
)
132 #if NCPUS > 1 && MACH_LOCK_MON
135 extern time_stamp_t time_stamp
;
137 typedef unsigned int time_stamp_t
;
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)
146 #define HASH_LOCK(lock) ((long)lock>>5 & (LOCK_INFO_HASH_COUNT-1))
149 unsigned int success
;
155 simple_lock_data_t
* lock
;
160 struct lock_info_bucket
{
161 struct lock_info info
[LOCK_INFO_PER_BUCKET
];
164 struct lock_info_bucket lock_info
[LOCK_INFO_HASH_COUNT
];
165 struct lock_info default_lock_info
;
166 unsigned default_lock_stack
= 0;
168 extern int curr_ipl
[];
173 locate_lock_info(lock
)
174 simple_lock_data_t
** lock
;
176 struct lock_info
*li
= &(lock_info
[HASH_LOCK(*lock
)].info
[0]);
179 for (i
=0; i
< LOCK_INFO_PER_BUCKET
; i
++, li
++)
181 if (li
->lock
== *lock
)
185 li
->caller
= *((vm_offset_t
*)lock
- 1);
188 db_printf("out of lock_info slots\n");
189 li
= &default_lock_info
;
195 decl_simple_lock_data(, *lock
)
197 register struct lock_info
*li
= locate_lock_info(&lock
);
199 if (current_thread())
200 li
->stack
= current_thread()->lock_stack
++;
201 mp_disable_preemption();
202 if (curr_ipl
[cpu_number()])
204 mp_enable_preemption();
205 if (_simple_lock_try(lock
))
211 li
->time
= time_stamp
- li
->time
;
214 simple_lock_try(lock
)
215 decl_simple_lock_data(, *lock
)
217 register struct lock_info
*li
= locate_lock_info(&lock
);
219 mp_disable_preemption();
220 if (curr_ipl
[cpu_number()])
222 mp_enable_preemption();
223 if (_simple_lock_try(lock
)) {
225 li
->time
= time_stamp
- li
->time
;
226 if (current_thread())
227 li
->stack
= current_thread()->lock_stack
++;
236 decl_simple_lock_data(, *lock
)
238 register time_stamp_t stamp
= time_stamp
;
239 register time_stamp_t
*time
= &locate_lock_info(&lock
)->time
;
240 register unsigned *lock_stack
;
242 *time
= stamp
- *time
;
243 _simple_unlock(lock
);
244 if (current_thread()) {
245 lock_stack
= ¤t_thread()->lock_stack
;
255 #define lock_info_sort lis
257 unsigned scurval
, ssum
;
258 struct lock_info
*sli
;
260 lock_info_sort(arg
, abs
, count
)
262 struct lock_info
*li
, mean
;
266 unsigned old_val
= (unsigned)-1;
267 struct lock_info
*target_li
= &lock_info
[0].info
[0];
269 unsigned empty
, total
;
272 printf("\nSUCCESS FAIL MASKED STACK TIME LOCK/CALLER\n");
275 while (count
&& target_li
) {
276 empty
= LOCK_INFO_HASH_COUNT
;
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];
291 for (i
= 0; i
< LOCK_INFO_PER_BUCKET
&& li
->lock
; i
++, li
++) {
292 if (li
->lock
== &kdb_lock
|| li
->lock
== &printf_lock
)
295 curval
= *((int *)li
+ arg
);
296 sum
= li
->success
+ li
->fail
;
302 if (!abs
) switch(arg
) {
307 curval
= (curval
*100) / sum
;
311 curval
= curval
/ sum
;
314 if (curval
> max_val
&& curval
< old_val
) {
318 if (curval
== old_val
&& count
!= 0) {
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
;
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
);
336 print_lock_info(&mean
);
339 #define lock_info_clear lic
343 struct lock_info
*li
;
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
));
352 bzero(&default_lock_info
, sizeof(struct lock_info
));
356 struct lock_info
*li
;
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
);
367 db_printsym(li
->lock
, 0);
369 db_printsym(li
->caller
, 0);
370 db_printf("(%X)", li
->lock
);
375 #endif NCPUS > 1 && MACH_LOCK_MON
380 * Measure lock/unlock operations
385 decl_simple_lock_data(, lock
)
386 register time_stamp_t stamp
;
392 simple_lock_init(&lock
);
394 for (i
= 0; i
< loops
; i
++) {
396 simple_unlock(&lock
);
398 stamp
= time_stamp
- stamp
;
399 db_printf("%d stamps for simple_locks\n", stamp
/loops
);
402 for (i
= 0; i
< loops
; i
++) {
404 _simple_unlock(&lock
);
406 stamp
= time_stamp
- stamp
;
407 db_printf("%d stamps for _simple_locks\n", stamp
/loops
);