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