|
|
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.