123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363 |
- /*
- * Mach Operating System
- * Copyright (c) 1990 Carnegie-Mellon University
- * Copyright (c) 1989 Carnegie-Mellon University
- * All rights reserved. The CMU software License Agreement specifies
- * the terms and conditions for use and redistribution.
- */
- /*
- * Copyright 1990 by Open Software Foundation,
- * Grenoble, FRANCE
- *
- * All Rights Reserved
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appears in all copies and
- * that both the copyright notice and this permission notice appear in
- * supporting documentation, and that the name of OSF or Open Software
- * Foundation not be used in advertising or publicity pertaining to
- * distribution of the software without specific, written prior
- * permission.
- *
- * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
- * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
- * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- /*
- * Support For MP Debugging
- * if MACH_MP_DEBUG is on, we use alternate locking
- * routines do detect dealocks
- * Support for MP lock monitoring (MACH_LOCK_MON).
- * Registers use of locks, contention.
- * Depending on hardware also records time spent with locks held
- */
- #include <sys/types.h>
- #include <string.h>
- #include <mach/machine/vm_types.h>
- #include <mach/boolean.h>
- #include <kern/thread.h>
- #include <kern/lock.h>
- #include <kern/time_stamp.h>
- decl_simple_lock_data(extern , kdb_lock)
- decl_simple_lock_data(extern , printf_lock)
- #if NCPUS > 1 && MACH_LOCK_MON
- #if TIME_STAMP
- extern time_stamp_t time_stamp;
- #else /* TIME_STAMP */
- typedef unsigned int time_stamp_t;
- #define time_stamp 0
- #endif /* TIME_STAMP */
- #define LOCK_INFO_MAX (1024*32)
- #define LOCK_INFO_HASH_COUNT 1024
- #define LOCK_INFO_PER_BUCKET (LOCK_INFO_MAX/LOCK_INFO_HASH_COUNT)
- #define HASH_LOCK(lock) ((long)lock>>5 & (LOCK_INFO_HASH_COUNT-1))
- struct lock_info {
- unsigned int success;
- unsigned int fail;
- unsigned int masked;
- unsigned int stack;
- time_stamp_t time;
- decl_simple_lock_data(, *lock)
- vm_offset_t caller;
- };
- struct lock_info_bucket {
- struct lock_info info[LOCK_INFO_PER_BUCKET];
- };
- struct lock_info_bucket lock_info[LOCK_INFO_HASH_COUNT];
- struct lock_info default_lock_info;
- unsigned default_lock_stack = 0;
- extern spl_t curr_ipl[];
- struct lock_info *
- locate_lock_info(lock)
- decl_simple_lock_data(, **lock)
- {
- struct lock_info *li = &(lock_info[HASH_LOCK(*lock)].info[0]);
- int i;
- my_cpu = cpu_number();
- for (i=0; i < LOCK_INFO_PER_BUCKET; i++, li++)
- if (li->lock) {
- if (li->lock == *lock)
- return(li);
- } else {
- li->lock = *lock;
- li->caller = *((vm_offset_t *)lock - 1);
- return(li);
- }
- db_printf("out of lock_info slots\n");
- li = &default_lock_info;
- return(li);
- }
- void simple_lock(lock)
- decl_simple_lock_data(, *lock)
- {
- struct lock_info *li = locate_lock_info(&lock);
- my_cpu = cpu_number();
- if (current_thread())
- li->stack = current_thread()->lock_stack++;
- if (curr_ipl[my_cpu])
- li->masked++;
- if (_simple_lock_try(lock))
- li->success++;
- else {
- _simple_lock(lock);
- li->fail++;
- }
- li->time = time_stamp - li->time;
- }
- int simple_lock_try(lock)
- decl_simple_lock_data(, *lock)
- {
- struct lock_info *li = locate_lock_info(&lock);
- my_cpu = cpu_number();
- if (curr_ipl[my_cpu])
- li->masked++;
- if (_simple_lock_try(lock)) {
- li->success++;
- li->time = time_stamp - li->time;
- if (current_thread())
- li->stack = current_thread()->lock_stack++;
- return(1);
- } else {
- li->fail++;
- return(0);
- }
- }
- void simple_unlock(lock)
- decl_simple_lock_data(, *lock)
- {
- time_stamp_t stamp = time_stamp;
- time_stamp_t *time = &locate_lock_info(&lock)->time;
- unsigned *lock_stack;
- *time = stamp - *time;
- _simple_unlock(lock);
- if (current_thread()) {
- lock_stack = ¤t_thread()->lock_stack;
- if (*lock_stack)
- (*lock_stack)--;
- }
- }
- void lip(void) {
- lis(4, 1, 0);
- }
- #define lock_info_sort lis
- void lock_info_sort(arg, abs, count)
- {
- struct lock_info *li, mean;
- int bucket = 0;
- int i;
- unsigned max_val;
- unsigned old_val = (unsigned)-1;
- struct lock_info *target_li = &lock_info[0].info[0];
- unsigned sum;
- unsigned empty, total;
- unsigned curval;
- printf("\nSUCCESS FAIL MASKED STACK TIME LOCK/CALLER\n");
- if (!count)
- count = 8 ;
- while (count && target_li) {
- empty = LOCK_INFO_HASH_COUNT;
- target_li = 0;
- total = 0;
- max_val = 0;
- mean.success = 0;
- mean.fail = 0;
- mean.masked = 0;
- mean.stack = 0;
- mean.time = 0;
- mean.lock = (simple_lock_data_t *) &lock_info;
- mean.caller = (vm_offset_t) &lock_info;
- for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
- li = &lock_info[bucket].info[0];
- if (li->lock)
- empty--;
- for (i= 0; i< LOCK_INFO_PER_BUCKET && li->lock; i++, li++) {
- if (li->lock == &kdb_lock || li->lock == &printf_lock)
- continue;
- total++;
- curval = *((int *)li + arg);
- sum = li->success + li->fail;
- if(!sum && !abs)
- continue;
- if (!abs) switch(arg) {
- case 0:
- break;
- case 1:
- case 2:
- curval = (curval*100) / sum;
- break;
- case 3:
- case 4:
- curval = curval / sum;
- break;
- }
- if (curval > max_val && curval < old_val) {
- max_val = curval;
- target_li = li;
- }
- if (curval == old_val && count != 0) {
- print_lock_info(li);
- count--;
- }
- mean.success += li->success;
- mean.fail += li->fail;
- mean.masked += li->masked;
- mean.stack += li->stack;
- mean.time += li->time;
- }
- }
- if (target_li)
- old_val = max_val;
- }
- db_printf("\n%d total locks, %d empty buckets", total, empty );
- if (default_lock_info.success)
- db_printf(", default: %d", default_lock_info.success + default_lock_info.fail);
- db_printf("\n");
- print_lock_info(&mean);
- }
- #define lock_info_clear lic
- void lock_info_clear(void)
- {
- struct lock_info *li;
- int bucket = 0;
- int i;
- for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
- li = &lock_info[bucket].info[0];
- for (i= 0; i< LOCK_INFO_PER_BUCKET; i++, li++) {
- memset(li, 0, sizeof(struct lock_info));
- }
- }
- memset(&default_lock_info, 0, sizeof(struct lock_info));
- }
- void print_lock_info(li)
- struct lock_info *li;
- {
- int off;
- int sum = li->success + li->fail;
- db_printf("%d %d/%d %d/%d %d/%d %d/%d ", li->success,
- li->fail, (li->fail*100)/sum,
- li->masked, (li->masked*100)/sum,
- li->stack, li->stack/sum,
- li->time, li->time/sum);
- db_free_symbol(db_search_symbol(li->lock, 0, &off));
- if (off < 1024)
- db_printsym(li->lock, 0);
- else {
- db_printsym(li->caller, 0);
- db_printf("(%X)", li->lock);
- }
- db_printf("\n");
- }
- #endif /* NCPUS > 1 && MACH_LOCK_MON */
- #if TIME_STAMP
- /*
- * Measure lock/unlock operations
- */
- void time_lock(int loops)
- {
- decl_simple_lock_data(, lock)
- time_stamp_t stamp;
- int i;
- if (!loops)
- loops = 1000;
- simple_lock_init(&lock);
- stamp = time_stamp;
- for (i = 0; i < loops; i++) {
- simple_lock(&lock);
- simple_unlock(&lock);
- }
- stamp = time_stamp - stamp;
- db_printf("%d stamps for simple_locks\n", stamp/loops);
- #if MACH_LOCK_MON
- stamp = time_stamp;
- for (i = 0; i < loops; i++) {
- _simple_lock(&lock);
- _simple_unlock(&lock);
- }
- stamp = time_stamp - stamp;
- db_printf("%d stamps for _simple_locks\n", stamp/loops);
- #endif /* MACH_LOCK_MON */
- }
- #endif /* TIME_STAMP */
- #if MACH_MP_DEBUG
- /*
- * Arrange in the lock routines to call the following
- * routines. This way, when locks are free there is no performance
- * penalty
- */
- void
- retry_simple_lock(lock)
- decl_simple_lock_data(, *lock)
- {
- count = 0;
- while(!simple_lock_try(lock))
- if (count++ > 1000000 && lock != &kdb_lock) {
- if (lock == &printf_lock)
- return;
- db_printf("cpu %d looping on simple_lock(%x) called by %x\n",
- cpu_number(), lock, *(((int *)&lock) -1));
- SoftDebugger("simple_lock timeout");
- count = 0;
- }
- }
- void
- retry_bit_lock(index, addr)
- {
- count = 0;
- while(!bit_lock_try(index, addr))
- if (count++ > 1000000) {
- db_printf("cpu %d looping on bit_lock(%x, %x) called by %x\n",
- cpu_number(), index, addr, *(((int *)&index) -1));
- SoftDebugger("bit_lock timeout");
- count = 0;
- }
- }
- #endif /* MACH_MP_DEBUG */
|