The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/kern/lock_mon.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 /*
   10  * HISTORY
   11  * $Log:        lock_mon.c,v $
   12  * Revision 2.2  93/01/14  17:35:07  danner
   13  *      64bit cleanup.
   14  *      [92/12/10  18:06:15  af]
   15  * 
   16  * Revision 2.1  91/12/23  04:05:35  bernadat
   17  * Created.
   18  * 
   19  */
   20 
   21 /*
   22  * Copyright 1990 by Open Software Foundation,
   23  * Grenoble, FRANCE
   24  *
   25  *              All Rights Reserved
   26  * 
   27  *   Permission to use, copy, modify, and distribute this software and
   28  * its documentation for any purpose and without fee is hereby granted,
   29  * provided that the above copyright notice appears in all copies and
   30  * that both the copyright notice and this permission notice appear in
   31  * supporting documentation, and that the name of OSF or Open Software
   32  * Foundation not be used in advertising or publicity pertaining to
   33  * distribution of the software without specific, written prior
   34  * permission.
   35  * 
   36  *   OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
   37  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
   38  * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
   39  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
   40  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
   41  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
   42  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   43  */
   44 
   45 /*
   46  *      Support For MP Debugging
   47  *              if MACH_MP_DEBUG is on, we use alternate locking
   48  *              routines do detect dealocks
   49  *      Support for MP lock monitoring (MACH_LOCK_MON).
   50  *              Registers use of locks, contention.
   51  *              Depending on hardware also records time spent with locks held
   52  */
   53 
   54 #include <cpus.h>
   55 #include <mach_mp_debug.h>
   56 #include <mach_lock_mon.h>
   57 #include <time_stamp.h>
   58 
   59 #include <sys/types.h>
   60 #include <mach/i386/vm_types.h>
   61 #include <mach/boolean.h>
   62 #include <kern/thread.h>
   63 #include <kern/lock.h>
   64 #include <kern/time_stamp.h>
   65 
   66 
   67 decl_simple_lock_data(extern , kdb_lock)
   68 decl_simple_lock_data(extern , printf_lock)
   69 
   70 #if     NCPUS > 1 && MACH_LOCK_MON
   71 
   72 #if     TIME_STAMP
   73 extern  time_stamp_t time_stamp;
   74 #else   TIME_STAMP
   75 typedef unsigned int time_stamp_t;
   76 #define time_stamp 0
   77 #endif  TIME_STAMP
   78 
   79 #define LOCK_INFO_MAX        (1024*32)
   80 #define LOCK_INFO_HASH_COUNT 1024
   81 #define LOCK_INFO_PER_BUCKET    (LOCK_INFO_MAX/LOCK_INFO_HASH_COUNT)
   82 
   83 
   84 #define HASH_LOCK(lock) ((long)lock>>5 & (LOCK_INFO_HASH_COUNT-1))
   85 
   86 struct lock_info {
   87         unsigned int    success;
   88         unsigned int    fail;
   89         unsigned int    masked;
   90         unsigned int    stack; 
   91         time_stamp_t    time;
   92         decl_simple_lock_data(, *lock)
   93         vm_offset_t     caller;
   94 };
   95 
   96 struct lock_info_bucket {
   97         struct lock_info info[LOCK_INFO_PER_BUCKET];
   98 };
   99 
  100 struct lock_info_bucket lock_info[LOCK_INFO_HASH_COUNT];
  101 struct lock_info default_lock_info;
  102 unsigned default_lock_stack = 0;
  103 
  104 extern int curr_ipl[];
  105 
  106 
  107 
  108 struct lock_info *
  109 locate_lock_info(lock)
  110 decl_simple_lock_data(, **lock)
  111 {
  112         struct lock_info *li =  &(lock_info[HASH_LOCK(*lock)].info[0]);
  113         register i;
  114         register my_cpu = cpu_number();
  115 
  116         for (i=0; i < LOCK_INFO_PER_BUCKET; i++, li++)
  117                 if (li->lock) {
  118                         if (li->lock == *lock)
  119                                 return(li);
  120                 } else {
  121                         li->lock = *lock;
  122                         li->caller = *((vm_offset_t *)lock - 1);
  123                         return(li);
  124                 }
  125         db_printf("out of lock_info slots\n");
  126         li = &default_lock_info;
  127         return(li);
  128 }
  129                 
  130 
  131 simple_lock(lock)
  132 decl_simple_lock_data(, *lock)
  133 {
  134         register struct lock_info *li = locate_lock_info(&lock);
  135         register my_cpu = cpu_number();
  136 
  137         if (current_thread()) 
  138                 li->stack = current_thread()->lock_stack++;
  139         if (curr_ipl[my_cpu])
  140                 li->masked++;
  141         if (_simple_lock_try(lock))
  142                 li->success++;
  143         else {
  144                 _simple_lock(lock);
  145                 li->fail++;
  146         }
  147         li->time = time_stamp - li->time;
  148 }
  149 
  150 simple_lock_try(lock)
  151 decl_simple_lock_data(, *lock)
  152 {
  153         register struct lock_info *li = locate_lock_info(&lock);
  154         register my_cpu = cpu_number();
  155 
  156         if (curr_ipl[my_cpu])
  157                 li->masked++;
  158         if (_simple_lock_try(lock)) {
  159                 li->success++;
  160                 li->time = time_stamp - li->time;
  161                 if (current_thread())
  162                         li->stack = current_thread()->lock_stack++;
  163                 return(1);
  164         } else {
  165                 li->fail++;
  166                 return(0);
  167         }
  168 }
  169 
  170 simple_unlock(lock)
  171 decl_simple_lock_data(, *lock)
  172 {
  173         register time_stamp_t stamp = time_stamp;
  174         register time_stamp_t *time = &locate_lock_info(&lock)->time;
  175         register unsigned *lock_stack;
  176 
  177         *time = stamp - *time;
  178         _simple_unlock(lock);
  179         if (current_thread()) {
  180                 lock_stack = &current_thread()->lock_stack;
  181                 if (*lock_stack)
  182                         (*lock_stack)--;
  183         }
  184 }
  185 
  186 lip() {
  187         lis(4, 1, 0);
  188 }
  189 
  190 #define lock_info_sort lis
  191 
  192 unsigned scurval, ssum;
  193 struct lock_info *sli;
  194 
  195 lock_info_sort(arg, abs, count)
  196 {
  197         struct lock_info *li, mean;
  198         int bucket = 0;
  199         int i;
  200         unsigned max_val;
  201         unsigned old_val = (unsigned)-1;
  202         struct lock_info *target_li = &lock_info[0].info[0];
  203         unsigned sum;
  204         unsigned empty, total;
  205         unsigned curval;
  206 
  207         printf("\nSUCCESS       FAIL    MASKED  STACK   TIME    LOCK/CALLER\n");
  208         if (!count)
  209                 count = 8 ;
  210         while (count && target_li) {
  211                 empty = LOCK_INFO_HASH_COUNT;
  212                 target_li = 0;
  213                 total = 0;
  214                 max_val = 0;
  215                 mean.success = 0;
  216                 mean.fail = 0;
  217                 mean.masked = 0;
  218                 mean.stack = 0;
  219                 mean.time = 0;
  220                 mean.lock = (simple_lock_data_t *) &lock_info;
  221                 mean.caller = (vm_offset_t) &lock_info;
  222                 for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
  223                         li = &lock_info[bucket].info[0];
  224                         if (li->lock)
  225                                 empty--;
  226                         for (i= 0; i< LOCK_INFO_PER_BUCKET && li->lock; i++, li++) {
  227                                 if (li->lock == &kdb_lock || li->lock == &printf_lock)
  228                                         continue;
  229                                 total++;
  230                                 curval = *((int *)li + arg);
  231                                 sum = li->success + li->fail;
  232                                 if(!sum && !abs)
  233                                         continue;
  234                                 scurval = curval;
  235                                 ssum = sum;
  236                                 sli = li;
  237                                 if (!abs) switch(arg) {
  238                                 case 0:
  239                                         break;
  240                                 case 1:
  241                                 case 2:
  242                                         curval = (curval*100) / sum;
  243                                         break;
  244                                 case 3:
  245                                 case 4:
  246                                         curval = curval / sum;
  247                                         break;
  248                                 }
  249                                 if (curval > max_val && curval < old_val) {
  250                                         max_val = curval;
  251                                         target_li = li;
  252                                 }
  253                                 if (curval == old_val && count != 0) {
  254                                         print_lock_info(li);
  255                                         count--;
  256                                 }
  257                                 mean.success += li->success;
  258                                 mean.fail += li->fail;
  259                                 mean.masked += li->masked;
  260                                 mean.stack += li->stack;
  261                                 mean.time += li->time;
  262                         }
  263                 }
  264                 if (target_li)
  265                         old_val = max_val;
  266         }
  267         db_printf("\n%d total locks, %d empty buckets", total, empty );
  268         if (default_lock_info.success) 
  269                 db_printf(", default: %d", default_lock_info.success + default_lock_info.fail); 
  270         db_printf("\n");
  271         print_lock_info(&mean);
  272 }
  273 
  274 #define lock_info_clear lic
  275 
  276 lock_info_clear()
  277 {
  278         struct lock_info *li;
  279         int bucket = 0;
  280         int i;
  281         for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
  282                 li = &lock_info[bucket].info[0];
  283                 for (i= 0; i< LOCK_INFO_PER_BUCKET; i++, li++) {
  284                         bzero(li, sizeof(struct lock_info));
  285                 }
  286         }
  287         bzero(&default_lock_info, sizeof(struct lock_info)); 
  288 }
  289 
  290 print_lock_info(li)
  291 struct lock_info *li;
  292 {
  293         int off;
  294         int sum = li->success + li->fail;
  295         db_printf("%d   %d/%d   %d/%d   %d/%d   %d/%d   ", li->success,
  296                    li->fail, (li->fail*100)/sum,
  297                    li->masked, (li->masked*100)/sum,
  298                    li->stack, li->stack/sum,
  299                    li->time, li->time/sum);
  300         db_search_symbol(li->lock, 0, &off);
  301         if (off < 1024)
  302                 db_printsym(li->lock, 0);
  303         else {
  304                 db_printsym(li->caller, 0);
  305                 db_printf("(%X)", li->lock);
  306         }
  307         db_printf("\n");
  308 }
  309 
  310 #endif  NCPUS > 1 && MACH_LOCK_MON
  311 
  312 #if     TIME_STAMP
  313 
  314 /*
  315  *      Measure lock/unlock operations
  316  */
  317 
  318 time_lock(loops)
  319 {
  320         decl_simple_lock_data(, lock)
  321         register time_stamp_t stamp;
  322         register int i;
  323 
  324 
  325         if (!loops)
  326                 loops = 1000;
  327         simple_lock_init(&lock);
  328         stamp = time_stamp;
  329         for (i = 0; i < loops; i++) {
  330                 simple_lock(&lock);
  331                 simple_unlock(&lock);
  332         }
  333         stamp = time_stamp - stamp;
  334         db_printf("%d stamps for simple_locks\n", stamp/loops);
  335 #if     MACH_LOCK_MON
  336         stamp = time_stamp;
  337         for (i = 0; i < loops; i++) {
  338                 _simple_lock(&lock);
  339                 _simple_unlock(&lock);
  340         }
  341         stamp = time_stamp - stamp;
  342         db_printf("%d stamps for _simple_locks\n", stamp/loops);
  343 #endif  MACH_LOCK_MON
  344 }
  345 #endif  TIME_STAMP
  346 
  347 #if     MACH_MP_DEBUG
  348 
  349 /*
  350  *      Arrange in the lock routines to call the following
  351  *      routines. This way, when locks are free there is no performance
  352  *      penalty
  353  */
  354 
  355 void
  356 retry_simple_lock(lock)
  357 decl_simple_lock_data(, *lock)
  358 {
  359         register count = 0;
  360 
  361         while(!simple_lock_try(lock))
  362                 if (count++ > 1000000 && lock != &kdb_lock) {
  363                         if (lock == &printf_lock)
  364                                 return;
  365                         db_printf("cpu %d looping on simple_lock(%x) called by %x\n",
  366                                 cpu_number(), lock, *(((int *)&lock) -1));
  367                         Debugger();
  368                         count = 0;
  369                 }
  370 }
  371 
  372 void
  373 retry_bit_lock(index, addr)
  374 {
  375         register count = 0;
  376 
  377         while(!bit_lock_try(index, addr))
  378                 if (count++ > 1000000) {
  379                         db_printf("cpu %d looping on bit_lock(%x, %x) called by %x\n",
  380                                 cpu_number(), index, addr, *(((int *)&index) -1));
  381                         Debugger();
  382                         count = 0;
  383                 }
  384 }
  385 #endif  MACH_MP_DEBUG
  386 
  387 
  388 

Cache object: ea3854ca83ceaf590af7f35dc2e80d1c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.