FreeBSD/Linux Kernel Cross Reference
sys/kern/lock_mon.c
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 = ¤t_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: f3e6ba85ea4422a07c91dcce5397e320
|