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