|
|
1.1 root 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 <[email protected]>]
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 = ¤t_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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.