lock_mon.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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. * Support For MP Debugging
  33. * if MACH_MP_DEBUG is on, we use alternate locking
  34. * routines do detect dealocks
  35. * Support for MP lock monitoring (MACH_LOCK_MON).
  36. * Registers use of locks, contention.
  37. * Depending on hardware also records time spent with locks held
  38. */
  39. #include <sys/types.h>
  40. #include <string.h>
  41. #include <mach/machine/vm_types.h>
  42. #include <mach/boolean.h>
  43. #include <kern/thread.h>
  44. #include <kern/lock.h>
  45. #include <kern/time_stamp.h>
  46. decl_simple_lock_data(extern , kdb_lock)
  47. decl_simple_lock_data(extern , printf_lock)
  48. #if NCPUS > 1 && MACH_LOCK_MON
  49. #if TIME_STAMP
  50. extern time_stamp_t time_stamp;
  51. #else /* TIME_STAMP */
  52. typedef unsigned int time_stamp_t;
  53. #define time_stamp 0
  54. #endif /* TIME_STAMP */
  55. #define LOCK_INFO_MAX (1024*32)
  56. #define LOCK_INFO_HASH_COUNT 1024
  57. #define LOCK_INFO_PER_BUCKET (LOCK_INFO_MAX/LOCK_INFO_HASH_COUNT)
  58. #define HASH_LOCK(lock) ((long)lock>>5 & (LOCK_INFO_HASH_COUNT-1))
  59. struct lock_info {
  60. unsigned int success;
  61. unsigned int fail;
  62. unsigned int masked;
  63. unsigned int stack;
  64. time_stamp_t time;
  65. decl_simple_lock_data(, *lock)
  66. vm_offset_t caller;
  67. };
  68. struct lock_info_bucket {
  69. struct lock_info info[LOCK_INFO_PER_BUCKET];
  70. };
  71. struct lock_info_bucket lock_info[LOCK_INFO_HASH_COUNT];
  72. struct lock_info default_lock_info;
  73. unsigned default_lock_stack = 0;
  74. extern spl_t curr_ipl[];
  75. struct lock_info *
  76. locate_lock_info(lock)
  77. decl_simple_lock_data(, **lock)
  78. {
  79. struct lock_info *li = &(lock_info[HASH_LOCK(*lock)].info[0]);
  80. int i;
  81. my_cpu = cpu_number();
  82. for (i=0; i < LOCK_INFO_PER_BUCKET; i++, li++)
  83. if (li->lock) {
  84. if (li->lock == *lock)
  85. return(li);
  86. } else {
  87. li->lock = *lock;
  88. li->caller = *((vm_offset_t *)lock - 1);
  89. return(li);
  90. }
  91. db_printf("out of lock_info slots\n");
  92. li = &default_lock_info;
  93. return(li);
  94. }
  95. void simple_lock(lock)
  96. decl_simple_lock_data(, *lock)
  97. {
  98. struct lock_info *li = locate_lock_info(&lock);
  99. my_cpu = cpu_number();
  100. if (current_thread())
  101. li->stack = current_thread()->lock_stack++;
  102. if (curr_ipl[my_cpu])
  103. li->masked++;
  104. if (_simple_lock_try(lock))
  105. li->success++;
  106. else {
  107. _simple_lock(lock);
  108. li->fail++;
  109. }
  110. li->time = time_stamp - li->time;
  111. }
  112. int simple_lock_try(lock)
  113. decl_simple_lock_data(, *lock)
  114. {
  115. struct lock_info *li = locate_lock_info(&lock);
  116. my_cpu = cpu_number();
  117. if (curr_ipl[my_cpu])
  118. li->masked++;
  119. if (_simple_lock_try(lock)) {
  120. li->success++;
  121. li->time = time_stamp - li->time;
  122. if (current_thread())
  123. li->stack = current_thread()->lock_stack++;
  124. return(1);
  125. } else {
  126. li->fail++;
  127. return(0);
  128. }
  129. }
  130. void simple_unlock(lock)
  131. decl_simple_lock_data(, *lock)
  132. {
  133. time_stamp_t stamp = time_stamp;
  134. time_stamp_t *time = &locate_lock_info(&lock)->time;
  135. unsigned *lock_stack;
  136. *time = stamp - *time;
  137. _simple_unlock(lock);
  138. if (current_thread()) {
  139. lock_stack = &current_thread()->lock_stack;
  140. if (*lock_stack)
  141. (*lock_stack)--;
  142. }
  143. }
  144. void lip(void) {
  145. lis(4, 1, 0);
  146. }
  147. #define lock_info_sort lis
  148. void lock_info_sort(arg, abs, count)
  149. {
  150. struct lock_info *li, mean;
  151. int bucket = 0;
  152. int i;
  153. unsigned max_val;
  154. unsigned old_val = (unsigned)-1;
  155. struct lock_info *target_li = &lock_info[0].info[0];
  156. unsigned sum;
  157. unsigned empty, total;
  158. unsigned curval;
  159. printf("\nSUCCESS FAIL MASKED STACK TIME LOCK/CALLER\n");
  160. if (!count)
  161. count = 8 ;
  162. while (count && target_li) {
  163. empty = LOCK_INFO_HASH_COUNT;
  164. target_li = 0;
  165. total = 0;
  166. max_val = 0;
  167. mean.success = 0;
  168. mean.fail = 0;
  169. mean.masked = 0;
  170. mean.stack = 0;
  171. mean.time = 0;
  172. mean.lock = (simple_lock_data_t *) &lock_info;
  173. mean.caller = (vm_offset_t) &lock_info;
  174. for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
  175. li = &lock_info[bucket].info[0];
  176. if (li->lock)
  177. empty--;
  178. for (i= 0; i< LOCK_INFO_PER_BUCKET && li->lock; i++, li++) {
  179. if (li->lock == &kdb_lock || li->lock == &printf_lock)
  180. continue;
  181. total++;
  182. curval = *((int *)li + arg);
  183. sum = li->success + li->fail;
  184. if(!sum && !abs)
  185. continue;
  186. if (!abs) switch(arg) {
  187. case 0:
  188. break;
  189. case 1:
  190. case 2:
  191. curval = (curval*100) / sum;
  192. break;
  193. case 3:
  194. case 4:
  195. curval = curval / sum;
  196. break;
  197. }
  198. if (curval > max_val && curval < old_val) {
  199. max_val = curval;
  200. target_li = li;
  201. }
  202. if (curval == old_val && count != 0) {
  203. print_lock_info(li);
  204. count--;
  205. }
  206. mean.success += li->success;
  207. mean.fail += li->fail;
  208. mean.masked += li->masked;
  209. mean.stack += li->stack;
  210. mean.time += li->time;
  211. }
  212. }
  213. if (target_li)
  214. old_val = max_val;
  215. }
  216. db_printf("\n%d total locks, %d empty buckets", total, empty );
  217. if (default_lock_info.success)
  218. db_printf(", default: %d", default_lock_info.success + default_lock_info.fail);
  219. db_printf("\n");
  220. print_lock_info(&mean);
  221. }
  222. #define lock_info_clear lic
  223. void lock_info_clear(void)
  224. {
  225. struct lock_info *li;
  226. int bucket = 0;
  227. int i;
  228. for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
  229. li = &lock_info[bucket].info[0];
  230. for (i= 0; i< LOCK_INFO_PER_BUCKET; i++, li++) {
  231. memset(li, 0, sizeof(struct lock_info));
  232. }
  233. }
  234. memset(&default_lock_info, 0, sizeof(struct lock_info));
  235. }
  236. void print_lock_info(li)
  237. struct lock_info *li;
  238. {
  239. int off;
  240. int sum = li->success + li->fail;
  241. db_printf("%d %d/%d %d/%d %d/%d %d/%d ", li->success,
  242. li->fail, (li->fail*100)/sum,
  243. li->masked, (li->masked*100)/sum,
  244. li->stack, li->stack/sum,
  245. li->time, li->time/sum);
  246. db_free_symbol(db_search_symbol(li->lock, 0, &off));
  247. if (off < 1024)
  248. db_printsym(li->lock, 0);
  249. else {
  250. db_printsym(li->caller, 0);
  251. db_printf("(%X)", li->lock);
  252. }
  253. db_printf("\n");
  254. }
  255. #endif /* NCPUS > 1 && MACH_LOCK_MON */
  256. #if TIME_STAMP
  257. /*
  258. * Measure lock/unlock operations
  259. */
  260. void time_lock(int loops)
  261. {
  262. decl_simple_lock_data(, lock)
  263. time_stamp_t stamp;
  264. int i;
  265. if (!loops)
  266. loops = 1000;
  267. simple_lock_init(&lock);
  268. stamp = time_stamp;
  269. for (i = 0; i < loops; i++) {
  270. simple_lock(&lock);
  271. simple_unlock(&lock);
  272. }
  273. stamp = time_stamp - stamp;
  274. db_printf("%d stamps for simple_locks\n", stamp/loops);
  275. #if MACH_LOCK_MON
  276. stamp = time_stamp;
  277. for (i = 0; i < loops; i++) {
  278. _simple_lock(&lock);
  279. _simple_unlock(&lock);
  280. }
  281. stamp = time_stamp - stamp;
  282. db_printf("%d stamps for _simple_locks\n", stamp/loops);
  283. #endif /* MACH_LOCK_MON */
  284. }
  285. #endif /* TIME_STAMP */
  286. #if MACH_MP_DEBUG
  287. /*
  288. * Arrange in the lock routines to call the following
  289. * routines. This way, when locks are free there is no performance
  290. * penalty
  291. */
  292. void
  293. retry_simple_lock(lock)
  294. decl_simple_lock_data(, *lock)
  295. {
  296. count = 0;
  297. while(!simple_lock_try(lock))
  298. if (count++ > 1000000 && lock != &kdb_lock) {
  299. if (lock == &printf_lock)
  300. return;
  301. db_printf("cpu %d looping on simple_lock(%x) called by %x\n",
  302. cpu_number(), lock, *(((int *)&lock) -1));
  303. SoftDebugger("simple_lock timeout");
  304. count = 0;
  305. }
  306. }
  307. void
  308. retry_bit_lock(index, addr)
  309. {
  310. count = 0;
  311. while(!bit_lock_try(index, addr))
  312. if (count++ > 1000000) {
  313. db_printf("cpu %d looping on bit_lock(%x, %x) called by %x\n",
  314. cpu_number(), index, addr, *(((int *)&index) -1));
  315. SoftDebugger("bit_lock timeout");
  316. count = 0;
  317. }
  318. }
  319. #endif /* MACH_MP_DEBUG */