|
|
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: #define HASH_LOCK(lock) ((long)lock>>5 & (LOCK_INFO_HASH_COUNT-1))
68:
69: struct lock_info {
70: unsigned int success;
71: unsigned int fail;
72: unsigned int masked;
1.1.1.2 root 73: unsigned int stack;
1.1 root 74: time_stamp_t time;
75: decl_simple_lock_data(, *lock)
76: vm_offset_t caller;
77: };
78:
79: struct lock_info_bucket {
80: struct lock_info info[LOCK_INFO_PER_BUCKET];
81: };
82:
83: struct lock_info_bucket lock_info[LOCK_INFO_HASH_COUNT];
84: struct lock_info default_lock_info;
85: unsigned default_lock_stack = 0;
86:
1.1.1.4 ! root 87: extern spl_t curr_ipl[];
1.1 root 88:
89:
90:
91: struct lock_info *
92: locate_lock_info(lock)
93: decl_simple_lock_data(, **lock)
94: {
95: struct lock_info *li = &(lock_info[HASH_LOCK(*lock)].info[0]);
1.1.1.4 ! root 96: int i;
! 97: my_cpu = cpu_number();
1.1 root 98:
99: for (i=0; i < LOCK_INFO_PER_BUCKET; i++, li++)
100: if (li->lock) {
101: if (li->lock == *lock)
102: return(li);
103: } else {
104: li->lock = *lock;
105: li->caller = *((vm_offset_t *)lock - 1);
106: return(li);
107: }
108: db_printf("out of lock_info slots\n");
109: li = &default_lock_info;
110: return(li);
111: }
1.1.1.2 root 112:
1.1 root 113:
1.1.1.4 ! root 114: void simple_lock(lock)
1.1 root 115: decl_simple_lock_data(, *lock)
116: {
1.1.1.4 ! root 117: struct lock_info *li = locate_lock_info(&lock);
! 118: my_cpu = cpu_number();
1.1 root 119:
1.1.1.2 root 120: if (current_thread())
1.1 root 121: li->stack = current_thread()->lock_stack++;
122: if (curr_ipl[my_cpu])
123: li->masked++;
124: if (_simple_lock_try(lock))
125: li->success++;
126: else {
127: _simple_lock(lock);
128: li->fail++;
129: }
130: li->time = time_stamp - li->time;
131: }
132:
1.1.1.4 ! root 133: int simple_lock_try(lock)
1.1 root 134: decl_simple_lock_data(, *lock)
135: {
1.1.1.4 ! root 136: struct lock_info *li = locate_lock_info(&lock);
! 137: my_cpu = cpu_number();
1.1 root 138:
139: if (curr_ipl[my_cpu])
140: li->masked++;
141: if (_simple_lock_try(lock)) {
142: li->success++;
143: li->time = time_stamp - li->time;
144: if (current_thread())
145: li->stack = current_thread()->lock_stack++;
146: return(1);
147: } else {
148: li->fail++;
149: return(0);
150: }
151: }
152:
1.1.1.4 ! root 153: void simple_unlock(lock)
1.1 root 154: decl_simple_lock_data(, *lock)
155: {
1.1.1.4 ! root 156: time_stamp_t stamp = time_stamp;
! 157: time_stamp_t *time = &locate_lock_info(&lock)->time;
! 158: unsigned *lock_stack;
1.1 root 159:
160: *time = stamp - *time;
161: _simple_unlock(lock);
162: if (current_thread()) {
163: lock_stack = ¤t_thread()->lock_stack;
164: if (*lock_stack)
165: (*lock_stack)--;
166: }
167: }
168:
1.1.1.4 ! root 169: void lip(void) {
1.1 root 170: lis(4, 1, 0);
171: }
172:
173: #define lock_info_sort lis
174:
1.1.1.4 ! root 175: void lock_info_sort(arg, abs, count)
1.1 root 176: {
177: struct lock_info *li, mean;
178: int bucket = 0;
179: int i;
180: unsigned max_val;
181: unsigned old_val = (unsigned)-1;
182: struct lock_info *target_li = &lock_info[0].info[0];
183: unsigned sum;
184: unsigned empty, total;
185: unsigned curval;
186:
187: printf("\nSUCCESS FAIL MASKED STACK TIME LOCK/CALLER\n");
188: if (!count)
189: count = 8 ;
190: while (count && target_li) {
191: empty = LOCK_INFO_HASH_COUNT;
192: target_li = 0;
193: total = 0;
194: max_val = 0;
195: mean.success = 0;
196: mean.fail = 0;
197: mean.masked = 0;
198: mean.stack = 0;
199: mean.time = 0;
200: mean.lock = (simple_lock_data_t *) &lock_info;
201: mean.caller = (vm_offset_t) &lock_info;
202: for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
203: li = &lock_info[bucket].info[0];
204: if (li->lock)
205: empty--;
206: for (i= 0; i< LOCK_INFO_PER_BUCKET && li->lock; i++, li++) {
207: if (li->lock == &kdb_lock || li->lock == &printf_lock)
208: continue;
209: total++;
210: curval = *((int *)li + arg);
211: sum = li->success + li->fail;
212: if(!sum && !abs)
213: continue;
214: if (!abs) switch(arg) {
215: case 0:
216: break;
217: case 1:
218: case 2:
219: curval = (curval*100) / sum;
220: break;
221: case 3:
222: case 4:
223: curval = curval / sum;
224: break;
225: }
226: if (curval > max_val && curval < old_val) {
227: max_val = curval;
228: target_li = li;
229: }
230: if (curval == old_val && count != 0) {
231: print_lock_info(li);
232: count--;
233: }
234: mean.success += li->success;
235: mean.fail += li->fail;
236: mean.masked += li->masked;
237: mean.stack += li->stack;
238: mean.time += li->time;
239: }
240: }
241: if (target_li)
242: old_val = max_val;
243: }
244: db_printf("\n%d total locks, %d empty buckets", total, empty );
1.1.1.2 root 245: if (default_lock_info.success)
246: db_printf(", default: %d", default_lock_info.success + default_lock_info.fail);
1.1 root 247: db_printf("\n");
248: print_lock_info(&mean);
249: }
250:
251: #define lock_info_clear lic
252:
1.1.1.4 ! root 253: void lock_info_clear(void)
1.1 root 254: {
255: struct lock_info *li;
256: int bucket = 0;
257: int i;
258: for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
259: li = &lock_info[bucket].info[0];
260: for (i= 0; i< LOCK_INFO_PER_BUCKET; i++, li++) {
1.1.1.3 root 261: memset(li, 0, sizeof(struct lock_info));
1.1 root 262: }
263: }
1.1.1.3 root 264: memset(&default_lock_info, 0, sizeof(struct lock_info));
1.1 root 265: }
266:
1.1.1.4 ! root 267: void print_lock_info(li)
1.1 root 268: struct lock_info *li;
269: {
270: int off;
271: int sum = li->success + li->fail;
272: db_printf("%d %d/%d %d/%d %d/%d %d/%d ", li->success,
273: li->fail, (li->fail*100)/sum,
274: li->masked, (li->masked*100)/sum,
275: li->stack, li->stack/sum,
276: li->time, li->time/sum);
1.1.1.3 root 277: db_free_symbol(db_search_symbol(li->lock, 0, &off));
1.1 root 278: if (off < 1024)
279: db_printsym(li->lock, 0);
280: else {
281: db_printsym(li->caller, 0);
282: db_printf("(%X)", li->lock);
283: }
284: db_printf("\n");
285: }
286:
1.1.1.2 root 287: #endif /* NCPUS > 1 && MACH_LOCK_MON */
1.1 root 288:
289: #if TIME_STAMP
290:
291: /*
292: * Measure lock/unlock operations
293: */
294:
1.1.1.4 ! root 295: void time_lock(int loops)
1.1 root 296: {
297: decl_simple_lock_data(, lock)
1.1.1.4 ! root 298: time_stamp_t stamp;
! 299: int i;
1.1 root 300:
301:
302: if (!loops)
303: loops = 1000;
304: simple_lock_init(&lock);
305: stamp = time_stamp;
306: for (i = 0; i < loops; i++) {
307: simple_lock(&lock);
308: simple_unlock(&lock);
309: }
310: stamp = time_stamp - stamp;
311: db_printf("%d stamps for simple_locks\n", stamp/loops);
312: #if MACH_LOCK_MON
313: stamp = time_stamp;
314: for (i = 0; i < loops; i++) {
315: _simple_lock(&lock);
316: _simple_unlock(&lock);
317: }
318: stamp = time_stamp - stamp;
319: db_printf("%d stamps for _simple_locks\n", stamp/loops);
1.1.1.2 root 320: #endif /* MACH_LOCK_MON */
1.1 root 321: }
1.1.1.2 root 322: #endif /* TIME_STAMP */
1.1 root 323:
324: #if MACH_MP_DEBUG
325:
326: /*
327: * Arrange in the lock routines to call the following
328: * routines. This way, when locks are free there is no performance
329: * penalty
330: */
331:
332: void
333: retry_simple_lock(lock)
334: decl_simple_lock_data(, *lock)
335: {
1.1.1.4 ! root 336: count = 0;
1.1 root 337:
338: while(!simple_lock_try(lock))
339: if (count++ > 1000000 && lock != &kdb_lock) {
340: if (lock == &printf_lock)
341: return;
342: db_printf("cpu %d looping on simple_lock(%x) called by %x\n",
343: cpu_number(), lock, *(((int *)&lock) -1));
1.1.1.3 root 344: SoftDebugger("simple_lock timeout");
1.1 root 345: count = 0;
346: }
347: }
348:
349: void
350: retry_bit_lock(index, addr)
351: {
1.1.1.4 ! root 352: count = 0;
1.1 root 353:
354: while(!bit_lock_try(index, addr))
355: if (count++ > 1000000) {
356: db_printf("cpu %d looping on bit_lock(%x, %x) called by %x\n",
357: cpu_number(), index, addr, *(((int *)&index) -1));
1.1.1.3 root 358: SoftDebugger("bit_lock timeout");
1.1 root 359: count = 0;
360: }
361: }
1.1.1.2 root 362: #endif /* MACH_MP_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.