|
|
1.1.1.2 root 1: /*
1.1 root 2: * Mach Operating System
3: * Copyright (c) 1990 Carnegie-Mellon University
4: * Copyright (c) 1989 Carnegie-Mellon University
5: * All rights reserved. The CMU software License Agreement specifies
6: * the terms and conditions for use and redistribution.
7: */
8: /*
9: * Copyright 1990 by Open Software Foundation,
10: * Grenoble, FRANCE
11: *
12: * All Rights Reserved
1.1.1.2 root 13: *
1.1 root 14: * Permission to use, copy, modify, and distribute this software and
15: * its documentation for any purpose and without fee is hereby granted,
16: * provided that the above copyright notice appears in all copies and
17: * that both the copyright notice and this permission notice appear in
18: * supporting documentation, and that the name of OSF or Open Software
19: * Foundation not be used in advertising or publicity pertaining to
20: * distribution of the software without specific, written prior
21: * permission.
1.1.1.2 root 22: *
1.1 root 23: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
24: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
25: * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
26: * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
27: * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
28: * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
29: * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
30: */
31:
32: /*
33: * Support For MP Debugging
34: * if MACH_MP_DEBUG is on, we use alternate locking
35: * routines do detect dealocks
36: * Support for MP lock monitoring (MACH_LOCK_MON).
37: * Registers use of locks, contention.
38: * Depending on hardware also records time spent with locks held
39: */
40:
41: #include <sys/types.h>
1.1.1.3 ! root 42: #include <string.h>
! 43:
1.1 root 44: #include <mach/machine/vm_types.h>
45: #include <mach/boolean.h>
46: #include <kern/thread.h>
47: #include <kern/lock.h>
48: #include <kern/time_stamp.h>
49:
50:
51: decl_simple_lock_data(extern , kdb_lock)
52: decl_simple_lock_data(extern , printf_lock)
53:
54: #if NCPUS > 1 && MACH_LOCK_MON
55:
56: #if TIME_STAMP
57: extern time_stamp_t time_stamp;
1.1.1.2 root 58: #else /* TIME_STAMP */
1.1 root 59: typedef unsigned int time_stamp_t;
60: #define time_stamp 0
1.1.1.2 root 61: #endif /* TIME_STAMP */
1.1 root 62:
63: #define LOCK_INFO_MAX (1024*32)
64: #define LOCK_INFO_HASH_COUNT 1024
65: #define LOCK_INFO_PER_BUCKET (LOCK_INFO_MAX/LOCK_INFO_HASH_COUNT)
66:
67:
68: #define HASH_LOCK(lock) ((long)lock>>5 & (LOCK_INFO_HASH_COUNT-1))
69:
70: struct lock_info {
71: unsigned int success;
72: unsigned int fail;
73: unsigned int masked;
1.1.1.2 root 74: unsigned int stack;
1.1 root 75: time_stamp_t time;
76: decl_simple_lock_data(, *lock)
77: vm_offset_t caller;
78: };
79:
80: struct lock_info_bucket {
81: struct lock_info info[LOCK_INFO_PER_BUCKET];
82: };
83:
84: struct lock_info_bucket lock_info[LOCK_INFO_HASH_COUNT];
85: struct lock_info default_lock_info;
86: unsigned default_lock_stack = 0;
87:
88: extern int curr_ipl[];
89:
90:
91:
92: struct lock_info *
93: locate_lock_info(lock)
94: decl_simple_lock_data(, **lock)
95: {
96: struct lock_info *li = &(lock_info[HASH_LOCK(*lock)].info[0]);
97: register i;
98: register my_cpu = cpu_number();
99:
100: for (i=0; i < LOCK_INFO_PER_BUCKET; i++, li++)
101: if (li->lock) {
102: if (li->lock == *lock)
103: return(li);
104: } else {
105: li->lock = *lock;
106: li->caller = *((vm_offset_t *)lock - 1);
107: return(li);
108: }
109: db_printf("out of lock_info slots\n");
110: li = &default_lock_info;
111: return(li);
112: }
1.1.1.2 root 113:
1.1 root 114:
115: simple_lock(lock)
116: decl_simple_lock_data(, *lock)
117: {
118: register struct lock_info *li = locate_lock_info(&lock);
119: register my_cpu = cpu_number();
120:
1.1.1.2 root 121: if (current_thread())
1.1 root 122: li->stack = current_thread()->lock_stack++;
123: if (curr_ipl[my_cpu])
124: li->masked++;
125: if (_simple_lock_try(lock))
126: li->success++;
127: else {
128: _simple_lock(lock);
129: li->fail++;
130: }
131: li->time = time_stamp - li->time;
132: }
133:
134: simple_lock_try(lock)
135: decl_simple_lock_data(, *lock)
136: {
137: register struct lock_info *li = locate_lock_info(&lock);
138: register my_cpu = cpu_number();
139:
140: if (curr_ipl[my_cpu])
141: li->masked++;
142: if (_simple_lock_try(lock)) {
143: li->success++;
144: li->time = time_stamp - li->time;
145: if (current_thread())
146: li->stack = current_thread()->lock_stack++;
147: return(1);
148: } else {
149: li->fail++;
150: return(0);
151: }
152: }
153:
154: simple_unlock(lock)
155: decl_simple_lock_data(, *lock)
156: {
157: register time_stamp_t stamp = time_stamp;
158: register time_stamp_t *time = &locate_lock_info(&lock)->time;
159: register unsigned *lock_stack;
160:
161: *time = stamp - *time;
162: _simple_unlock(lock);
163: if (current_thread()) {
164: lock_stack = ¤t_thread()->lock_stack;
165: if (*lock_stack)
166: (*lock_stack)--;
167: }
168: }
169:
170: lip() {
171: lis(4, 1, 0);
172: }
173:
174: #define lock_info_sort lis
175:
176: unsigned scurval, ssum;
177: struct lock_info *sli;
178:
179: lock_info_sort(arg, abs, count)
180: {
181: struct lock_info *li, mean;
182: int bucket = 0;
183: int i;
184: unsigned max_val;
185: unsigned old_val = (unsigned)-1;
186: struct lock_info *target_li = &lock_info[0].info[0];
187: unsigned sum;
188: unsigned empty, total;
189: unsigned curval;
190:
191: printf("\nSUCCESS FAIL MASKED STACK TIME LOCK/CALLER\n");
192: if (!count)
193: count = 8 ;
194: while (count && target_li) {
195: empty = LOCK_INFO_HASH_COUNT;
196: target_li = 0;
197: total = 0;
198: max_val = 0;
199: mean.success = 0;
200: mean.fail = 0;
201: mean.masked = 0;
202: mean.stack = 0;
203: mean.time = 0;
204: mean.lock = (simple_lock_data_t *) &lock_info;
205: mean.caller = (vm_offset_t) &lock_info;
206: for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
207: li = &lock_info[bucket].info[0];
208: if (li->lock)
209: empty--;
210: for (i= 0; i< LOCK_INFO_PER_BUCKET && li->lock; i++, li++) {
211: if (li->lock == &kdb_lock || li->lock == &printf_lock)
212: continue;
213: total++;
214: curval = *((int *)li + arg);
215: sum = li->success + li->fail;
216: if(!sum && !abs)
217: continue;
218: scurval = curval;
219: ssum = sum;
220: sli = li;
221: if (!abs) switch(arg) {
222: case 0:
223: break;
224: case 1:
225: case 2:
226: curval = (curval*100) / sum;
227: break;
228: case 3:
229: case 4:
230: curval = curval / sum;
231: break;
232: }
233: if (curval > max_val && curval < old_val) {
234: max_val = curval;
235: target_li = li;
236: }
237: if (curval == old_val && count != 0) {
238: print_lock_info(li);
239: count--;
240: }
241: mean.success += li->success;
242: mean.fail += li->fail;
243: mean.masked += li->masked;
244: mean.stack += li->stack;
245: mean.time += li->time;
246: }
247: }
248: if (target_li)
249: old_val = max_val;
250: }
251: db_printf("\n%d total locks, %d empty buckets", total, empty );
1.1.1.2 root 252: if (default_lock_info.success)
253: db_printf(", default: %d", default_lock_info.success + default_lock_info.fail);
1.1 root 254: db_printf("\n");
255: print_lock_info(&mean);
256: }
257:
258: #define lock_info_clear lic
259:
260: lock_info_clear()
261: {
262: struct lock_info *li;
263: int bucket = 0;
264: int i;
265: for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
266: li = &lock_info[bucket].info[0];
267: for (i= 0; i< LOCK_INFO_PER_BUCKET; i++, li++) {
1.1.1.3 ! root 268: memset(li, 0, sizeof(struct lock_info));
1.1 root 269: }
270: }
1.1.1.3 ! root 271: memset(&default_lock_info, 0, sizeof(struct lock_info));
1.1 root 272: }
273:
274: print_lock_info(li)
275: struct lock_info *li;
276: {
277: int off;
278: int sum = li->success + li->fail;
279: db_printf("%d %d/%d %d/%d %d/%d %d/%d ", li->success,
280: li->fail, (li->fail*100)/sum,
281: li->masked, (li->masked*100)/sum,
282: li->stack, li->stack/sum,
283: li->time, li->time/sum);
1.1.1.3 ! root 284: db_free_symbol(db_search_symbol(li->lock, 0, &off));
1.1 root 285: if (off < 1024)
286: db_printsym(li->lock, 0);
287: else {
288: db_printsym(li->caller, 0);
289: db_printf("(%X)", li->lock);
290: }
291: db_printf("\n");
292: }
293:
1.1.1.2 root 294: #endif /* NCPUS > 1 && MACH_LOCK_MON */
1.1 root 295:
296: #if TIME_STAMP
297:
298: /*
299: * Measure lock/unlock operations
300: */
301:
302: time_lock(loops)
303: {
304: decl_simple_lock_data(, lock)
305: register time_stamp_t stamp;
306: register int i;
307:
308:
309: if (!loops)
310: loops = 1000;
311: simple_lock_init(&lock);
312: stamp = time_stamp;
313: for (i = 0; i < loops; i++) {
314: simple_lock(&lock);
315: simple_unlock(&lock);
316: }
317: stamp = time_stamp - stamp;
318: db_printf("%d stamps for simple_locks\n", stamp/loops);
319: #if MACH_LOCK_MON
320: stamp = time_stamp;
321: for (i = 0; i < loops; i++) {
322: _simple_lock(&lock);
323: _simple_unlock(&lock);
324: }
325: stamp = time_stamp - stamp;
326: db_printf("%d stamps for _simple_locks\n", stamp/loops);
1.1.1.2 root 327: #endif /* MACH_LOCK_MON */
1.1 root 328: }
1.1.1.2 root 329: #endif /* TIME_STAMP */
1.1 root 330:
331: #if MACH_MP_DEBUG
332:
333: /*
334: * Arrange in the lock routines to call the following
335: * routines. This way, when locks are free there is no performance
336: * penalty
337: */
338:
339: void
340: retry_simple_lock(lock)
341: decl_simple_lock_data(, *lock)
342: {
343: register count = 0;
344:
345: while(!simple_lock_try(lock))
346: if (count++ > 1000000 && lock != &kdb_lock) {
347: if (lock == &printf_lock)
348: return;
349: db_printf("cpu %d looping on simple_lock(%x) called by %x\n",
350: cpu_number(), lock, *(((int *)&lock) -1));
1.1.1.3 ! root 351: SoftDebugger("simple_lock timeout");
1.1 root 352: count = 0;
353: }
354: }
355:
356: void
357: retry_bit_lock(index, addr)
358: {
359: register count = 0;
360:
361: while(!bit_lock_try(index, addr))
362: if (count++ > 1000000) {
363: db_printf("cpu %d looping on bit_lock(%x, %x) called by %x\n",
364: cpu_number(), index, addr, *(((int *)&index) -1));
1.1.1.3 ! root 365: SoftDebugger("bit_lock timeout");
1.1 root 366: count = 0;
367: }
368: }
1.1.1.2 root 369: #endif /* MACH_MP_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.