2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
31 * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez
32 * Import of Mac OS X kernel (~semeria)
34 * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez
35 * Import of OSF Mach kernel (~mburg)
37 * Revision 1.3.19.1 1997/09/22 17:39:46 barbou
38 * MP+RT: protect cpu_number() usage against preemption.
41 * Revision 1.3.15.4 1995/02/24 15:20:58 alanl
42 * DIPC: Merge from nmk17b2 to nmk18b8.
43 * Notes: major lock cleanup. Change kdb_lock and printf_lock
44 * references to conform with simple_lock declaration rules.
45 * This code is broken and non-portable; its functionality
46 * should be subsumed in the regular lock package.
49 * Revision 1.3.17.2 1994/11/10 06:13:19 dwm
50 * mk6 CR764 - s/spinlock/simple_lock/ (name change only)
51 * [1994/11/10 05:28:52 dwm]
53 * Revision 1.3.17.1 1994/11/04 10:07:54 dwm
54 * mk6 CR668 - 1.3b26 merge
55 * This file is obviously UNUSED - hence broken; merged anyway
56 * * Revision 1.3.4.4 1994/05/06 18:50:11 tmt
57 * Merge in DEC Alpha changes to osc1.3b19.
58 * Merge Alpha changes into osc1.312b source code.
61 * [1994/11/04 09:25:58 dwm]
63 * Revision 1.3.15.1 1994/09/23 02:21:48 ezf
64 * change marker to not FREE
65 * [1994/09/22 21:34:22 ezf]
67 * Revision 1.3.13.1 1994/06/09 14:11:30 dswartz
69 * [1994/06/09 14:07:06 dswartz]
71 * Revision 1.3.4.2 1993/06/09 02:36:12 gm
72 * Added to OSF/1 R1.3 from NMK15.0.
73 * [1993/06/02 21:13:15 jeffc]
75 * Revision 1.3 1993/04/19 16:26:56 devrcs
76 * Fix for TIME_STAMP configuration.
77 * [Patrick Petit <petit@gr.osf.org>]
80 * Revision 1.2 1992/11/25 01:11:05 robert
81 * integrate changes below for norma_14
83 * Philippe Bernadat (bernadat) at gr.osf.org
84 * Moved MACH_MP_DEBUG code to kern/lock.c
85 * [1992/11/13 19:33:47 robert]
87 * Revision 1.1 1992/09/30 02:09:28 robert
94 * Revision 2.1.2.1.3.1 92/02/18 19:08:45 jeffreyh
95 * Created. Might need some work if used on anything but a 386.
96 * [92/02/11 07:56:50 bernadat]
101 * Mach Operating System
102 * Copyright (c) 1990 Carnegie-Mellon University
103 * Copyright (c) 1989 Carnegie-Mellon University
104 * All rights reserved. The CMU software License Agreement specifies
105 * the terms and conditions for use and redistribution.
112 * Support For MP Debugging
113 * if MACH_MP_DEBUG is on, we use alternate locking
114 * routines do detect dealocks
115 * Support for MP lock monitoring (MACH_LOCK_MON).
116 * Registers use of locks, contention.
117 * Depending on hardware also records time spent with locks held
121 #include <mach_mp_debug.h>
122 #include <mach_lock_mon.h>
123 #include <time_stamp.h>
125 #include <sys/types.h>
126 #include <mach/machine/vm_types.h>
127 #include <mach/boolean.h>
128 #include <kern/thread.h>
129 #include <kern/lock.h>
132 decl_simple_lock_data(extern, kdb_lock
)
133 decl_simple_lock_data(extern, printf_lock
)
135 #if NCPUS > 1 && MACH_LOCK_MON
138 extern time_stamp_t time_stamp
;
140 typedef unsigned int time_stamp_t
;
144 #define LOCK_INFO_MAX (1024*32)
145 #define LOCK_INFO_HASH_COUNT 1024
146 #define LOCK_INFO_PER_BUCKET (LOCK_INFO_MAX/LOCK_INFO_HASH_COUNT)
149 #define HASH_LOCK(lock) ((long)lock>>5 & (LOCK_INFO_HASH_COUNT-1))
152 unsigned int success
;
158 simple_lock_data_t
* lock
;
163 struct lock_info_bucket
{
164 struct lock_info info
[LOCK_INFO_PER_BUCKET
];
167 struct lock_info_bucket lock_info
[LOCK_INFO_HASH_COUNT
];
168 struct lock_info default_lock_info
;
169 unsigned default_lock_stack
= 0;
171 extern int curr_ipl
[];
176 locate_lock_info(lock
)
177 simple_lock_data_t
** lock
;
179 struct lock_info
*li
= &(lock_info
[HASH_LOCK(*lock
)].info
[0]);
182 for (i
=0; i
< LOCK_INFO_PER_BUCKET
; i
++, li
++)
184 if (li
->lock
== *lock
)
188 li
->caller
= *((vm_offset_t
*)lock
- 1);
191 db_printf("out of lock_info slots\n");
192 li
= &default_lock_info
;
198 decl_simple_lock_data(, *lock
)
200 register struct lock_info
*li
= locate_lock_info(&lock
);
202 if (current_thread())
203 li
->stack
= current_thread()->lock_stack
++;
204 mp_disable_preemption();
205 if (curr_ipl
[cpu_number()])
207 mp_enable_preemption();
208 if (_simple_lock_try(lock
))
214 li
->time
= time_stamp
- li
->time
;
217 simple_lock_try(lock
)
218 decl_simple_lock_data(, *lock
)
220 register struct lock_info
*li
= locate_lock_info(&lock
);
222 mp_disable_preemption();
223 if (curr_ipl
[cpu_number()])
225 mp_enable_preemption();
226 if (_simple_lock_try(lock
)) {
228 li
->time
= time_stamp
- li
->time
;
229 if (current_thread())
230 li
->stack
= current_thread()->lock_stack
++;
239 decl_simple_lock_data(, *lock
)
241 register time_stamp_t stamp
= time_stamp
;
242 register time_stamp_t
*time
= &locate_lock_info(&lock
)->time
;
243 register unsigned *lock_stack
;
245 *time
= stamp
- *time
;
246 _simple_unlock(lock
);
247 if (current_thread()) {
248 lock_stack
= ¤t_thread()->lock_stack
;
258 #define lock_info_sort lis
260 unsigned scurval
, ssum
;
261 struct lock_info
*sli
;
263 lock_info_sort(arg
, abs
, count
)
265 struct lock_info
*li
, mean
;
269 unsigned old_val
= (unsigned)-1;
270 struct lock_info
*target_li
= &lock_info
[0].info
[0];
272 unsigned empty
, total
;
275 printf("\nSUCCESS FAIL MASKED STACK TIME LOCK/CALLER\n");
278 while (count
&& target_li
) {
279 empty
= LOCK_INFO_HASH_COUNT
;
288 mean
.lock
= (simple_lock_data_t
*) &lock_info
;
289 mean
.caller
= (vm_offset_t
) &lock_info
;
290 for (bucket
= 0; bucket
< LOCK_INFO_HASH_COUNT
; bucket
++) {
291 li
= &lock_info
[bucket
].info
[0];
294 for (i
= 0; i
< LOCK_INFO_PER_BUCKET
&& li
->lock
; i
++, li
++) {
295 if (li
->lock
== &kdb_lock
|| li
->lock
== &printf_lock
)
298 curval
= *((int *)li
+ arg
);
299 sum
= li
->success
+ li
->fail
;
305 if (!abs
) switch(arg
) {
310 curval
= (curval
*100) / sum
;
314 curval
= curval
/ sum
;
317 if (curval
> max_val
&& curval
< old_val
) {
321 if (curval
== old_val
&& count
!= 0) {
325 mean
.success
+= li
->success
;
326 mean
.fail
+= li
->fail
;
327 mean
.masked
+= li
->masked
;
328 mean
.stack
+= li
->stack
;
329 mean
.time
+= li
->time
;
335 db_printf("\n%d total locks, %d empty buckets", total
, empty
);
336 if (default_lock_info
.success
)
337 db_printf(", default: %d", default_lock_info
.success
+ default_lock_info
.fail
);
339 print_lock_info(&mean
);
342 #define lock_info_clear lic
346 struct lock_info
*li
;
349 for (bucket
= 0; bucket
< LOCK_INFO_HASH_COUNT
; bucket
++) {
350 li
= &lock_info
[bucket
].info
[0];
351 for (i
= 0; i
< LOCK_INFO_PER_BUCKET
; i
++, li
++) {
352 bzero(li
, sizeof(struct lock_info
));
355 bzero(&default_lock_info
, sizeof(struct lock_info
));
359 struct lock_info
*li
;
362 int sum
= li
->success
+ li
->fail
;
363 db_printf("%d %d/%d %d/%d %d/%d %d/%d ", li
->success
,
364 li
->fail
, (li
->fail
*100)/sum
,
365 li
->masked
, (li
->masked
*100)/sum
,
366 li
->stack
, li
->stack
/sum
,
367 li
->time
, li
->time
/sum
);
368 db_search_symbol(li
->lock
, 0, &off
);
370 db_printsym(li
->lock
, 0);
372 db_printsym(li
->caller
, 0);
373 db_printf("(%X)", li
->lock
);
378 #endif NCPUS > 1 && MACH_LOCK_MON
383 * Measure lock/unlock operations
388 decl_simple_lock_data(, lock
)
389 register time_stamp_t stamp
;
395 simple_lock_init(&lock
);
397 for (i
= 0; i
< loops
; i
++) {
399 simple_unlock(&lock
);
401 stamp
= time_stamp
- stamp
;
402 db_printf("%d stamps for simple_locks\n", stamp
/loops
);
405 for (i
= 0; i
< loops
; i
++) {
407 _simple_unlock(&lock
);
409 stamp
= time_stamp
- stamp
;
410 db_printf("%d stamps for _simple_locks\n", stamp
/loops
);