]> git.saurik.com Git - apple/xnu.git/blame_incremental - osfmk/kern/lock_mon.c
xnu-344.49.tar.gz
[apple/xnu.git] / osfmk / kern / lock_mon.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * @OSF_COPYRIGHT@
27 */
28/*
29 * HISTORY
30 *
31 * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez
32 * Import of Mac OS X kernel (~semeria)
33 *
34 * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez
35 * Import of OSF Mach kernel (~mburg)
36 *
37 * Revision 1.3.19.1 1997/09/22 17:39:46 barbou
38 * MP+RT: protect cpu_number() usage against preemption.
39 * [97/09/16 barbou]
40 *
41 * Revision 1.3.15.4 1995/02/24 15:20:58 alanl
42 * DIPC: Merge from nmk17b2 to nmk18b8.
43 * Notes: major lock cleanup. Change kdb_lock and printf_lock
44 * references to conform with simple_lock declaration rules.
45 * This code is broken and non-portable; its functionality
46 * should be subsumed in the regular lock package.
47 * [95/01/16 alanl]
48 *
49 * Revision 1.3.17.2 1994/11/10 06:13:19 dwm
50 * mk6 CR764 - s/spinlock/simple_lock/ (name change only)
51 * [1994/11/10 05:28:52 dwm]
52 *
53 * Revision 1.3.17.1 1994/11/04 10:07:54 dwm
54 * mk6 CR668 - 1.3b26 merge
55 * This file is obviously UNUSED - hence broken; merged anyway
56 * * Revision 1.3.4.4 1994/05/06 18:50:11 tmt
57 * Merge in DEC Alpha changes to osc1.3b19.
58 * Merge Alpha changes into osc1.312b source code.
59 * 64bit cleanup.
60 * * End1.3merge
61 * [1994/11/04 09:25:58 dwm]
62 *
63 * Revision 1.3.15.1 1994/09/23 02:21:48 ezf
64 * change marker to not FREE
65 * [1994/09/22 21:34:22 ezf]
66 *
67 * Revision 1.3.13.1 1994/06/09 14:11:30 dswartz
68 * Preemption merge.
69 * [1994/06/09 14:07:06 dswartz]
70 *
71 * Revision 1.3.4.2 1993/06/09 02:36:12 gm
72 * Added to OSF/1 R1.3 from NMK15.0.
73 * [1993/06/02 21:13:15 jeffc]
74 *
75 * Revision 1.3 1993/04/19 16:26:56 devrcs
76 * Fix for TIME_STAMP configuration.
77 * [Patrick Petit <petit@gr.osf.org>]
78 * [93/02/11 bernadat]
79 *
80 * Revision 1.2 1992/11/25 01:11:05 robert
81 * integrate changes below for norma_14
82 *
83 * Philippe Bernadat (bernadat) at gr.osf.org
84 * Moved MACH_MP_DEBUG code to kern/lock.c
85 * [1992/11/13 19:33:47 robert]
86 *
87 * Revision 1.1 1992/09/30 02:09:28 robert
88 * Initial revision
89 *
90 * $EndLog$
91 */
92/* CMU_HIST */
93/*
94 * Revision 2.1.2.1.3.1 92/02/18 19:08:45 jeffreyh
95 * Created. Might need some work if used on anything but a 386.
96 * [92/02/11 07:56:50 bernadat]
97 */
98/* CMU_ENDHIST */
99
100/*
101 * Mach Operating System
102 * Copyright (c) 1990 Carnegie-Mellon University
103 * Copyright (c) 1989 Carnegie-Mellon University
104 * All rights reserved. The CMU software License Agreement specifies
105 * the terms and conditions for use and redistribution.
106 */
107
108/*
109 */
110
111/*
112 * Support For MP Debugging
113 * if MACH_MP_DEBUG is on, we use alternate locking
114 * routines do detect dealocks
115 * Support for MP lock monitoring (MACH_LOCK_MON).
116 * Registers use of locks, contention.
117 * Depending on hardware also records time spent with locks held
118 */
119
120#include <cpus.h>
121#include <mach_mp_debug.h>
122#include <mach_lock_mon.h>
123#include <time_stamp.h>
124
125#include <sys/types.h>
126#include <mach/machine/vm_types.h>
127#include <mach/boolean.h>
128#include <kern/thread.h>
129#include <kern/lock.h>
130
131
132decl_simple_lock_data(extern, kdb_lock)
133decl_simple_lock_data(extern, printf_lock)
134
135#if NCPUS > 1 && MACH_LOCK_MON
136
137#if TIME_STAMP
138extern time_stamp_t time_stamp;
139#else TIME_STAMP
140typedef unsigned int time_stamp_t;
141#define time_stamp 0
142#endif TIME_STAMP
143
144#define LOCK_INFO_MAX (1024*32)
145#define LOCK_INFO_HASH_COUNT 1024
146#define LOCK_INFO_PER_BUCKET (LOCK_INFO_MAX/LOCK_INFO_HASH_COUNT)
147
148
149#define HASH_LOCK(lock) ((long)lock>>5 & (LOCK_INFO_HASH_COUNT-1))
150
151struct lock_info {
152 unsigned int success;
153 unsigned int fail;
154 unsigned int masked;
155 unsigned int stack;
156 unsigned int time;
157#if MACH_SLOCKS
158 simple_lock_data_t * lock;
159#endif
160 vm_offset_t caller;
161};
162
163struct lock_info_bucket {
164 struct lock_info info[LOCK_INFO_PER_BUCKET];
165};
166
167struct lock_info_bucket lock_info[LOCK_INFO_HASH_COUNT];
168struct lock_info default_lock_info;
169unsigned default_lock_stack = 0;
170
171extern int curr_ipl[];
172
173
174
175struct lock_info *
176locate_lock_info(lock)
177simple_lock_data_t ** lock;
178{
179 struct lock_info *li = &(lock_info[HASH_LOCK(*lock)].info[0]);
180 register i;
181
182 for (i=0; i < LOCK_INFO_PER_BUCKET; i++, li++)
183 if (li->lock) {
184 if (li->lock == *lock)
185 return(li);
186 } else {
187 li->lock = *lock;
188 li->caller = *((vm_offset_t *)lock - 1);
189 return(li);
190 }
191 db_printf("out of lock_info slots\n");
192 li = &default_lock_info;
193 return(li);
194}
195
196
197simple_lock(lock)
198decl_simple_lock_data(, *lock)
199{
200 register struct lock_info *li = locate_lock_info(&lock);
201
202 if (current_thread())
203 li->stack = current_thread()->lock_stack++;
204 mp_disable_preemption();
205 if (curr_ipl[cpu_number()])
206 li->masked++;
207 mp_enable_preemption();
208 if (_simple_lock_try(lock))
209 li->success++;
210 else {
211 _simple_lock(lock);
212 li->fail++;
213 }
214 li->time = time_stamp - li->time;
215}
216
217simple_lock_try(lock)
218decl_simple_lock_data(, *lock)
219{
220 register struct lock_info *li = locate_lock_info(&lock);
221
222 mp_disable_preemption();
223 if (curr_ipl[cpu_number()])
224 li->masked++;
225 mp_enable_preemption();
226 if (_simple_lock_try(lock)) {
227 li->success++;
228 li->time = time_stamp - li->time;
229 if (current_thread())
230 li->stack = current_thread()->lock_stack++;
231 return(1);
232 } else {
233 li->fail++;
234 return(0);
235 }
236}
237
238simple_unlock(lock)
239decl_simple_lock_data(, *lock)
240{
241 register time_stamp_t stamp = time_stamp;
242 register time_stamp_t *time = &locate_lock_info(&lock)->time;
243 register unsigned *lock_stack;
244
245 *time = stamp - *time;
246 _simple_unlock(lock);
247 if (current_thread()) {
248 lock_stack = &current_thread()->lock_stack;
249 if (*lock_stack)
250 (*lock_stack)--;
251 }
252}
253
254lip() {
255 lis(4, 1, 0);
256}
257
258#define lock_info_sort lis
259
260unsigned scurval, ssum;
261struct lock_info *sli;
262
263lock_info_sort(arg, abs, count)
264{
265 struct lock_info *li, mean;
266 int bucket = 0;
267 int i;
268 unsigned max_val;
269 unsigned old_val = (unsigned)-1;
270 struct lock_info *target_li = &lock_info[0].info[0];
271 unsigned sum;
272 unsigned empty, total;
273 unsigned curval;
274
275 printf("\nSUCCESS FAIL MASKED STACK TIME LOCK/CALLER\n");
276 if (!count)
277 count = 8 ;
278 while (count && target_li) {
279 empty = LOCK_INFO_HASH_COUNT;
280 target_li = 0;
281 total = 0;
282 max_val = 0;
283 mean.success = 0;
284 mean.fail = 0;
285 mean.masked = 0;
286 mean.stack = 0;
287 mean.time = 0;
288 mean.lock = (simple_lock_data_t *) &lock_info;
289 mean.caller = (vm_offset_t) &lock_info;
290 for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
291 li = &lock_info[bucket].info[0];
292 if (li->lock)
293 empty--;
294 for (i= 0; i< LOCK_INFO_PER_BUCKET && li->lock; i++, li++) {
295 if (li->lock == &kdb_lock || li->lock == &printf_lock)
296 continue;
297 total++;
298 curval = *((int *)li + arg);
299 sum = li->success + li->fail;
300 if(!sum && !abs)
301 continue;
302 scurval = curval;
303 ssum = sum;
304 sli = li;
305 if (!abs) switch(arg) {
306 case 0:
307 break;
308 case 1:
309 case 2:
310 curval = (curval*100) / sum;
311 break;
312 case 3:
313 case 4:
314 curval = curval / sum;
315 break;
316 }
317 if (curval > max_val && curval < old_val) {
318 max_val = curval;
319 target_li = li;
320 }
321 if (curval == old_val && count != 0) {
322 print_lock_info(li);
323 count--;
324 }
325 mean.success += li->success;
326 mean.fail += li->fail;
327 mean.masked += li->masked;
328 mean.stack += li->stack;
329 mean.time += li->time;
330 }
331 }
332 if (target_li)
333 old_val = max_val;
334 }
335 db_printf("\n%d total locks, %d empty buckets", total, empty );
336 if (default_lock_info.success)
337 db_printf(", default: %d", default_lock_info.success + default_lock_info.fail);
338 db_printf("\n");
339 print_lock_info(&mean);
340}
341
342#define lock_info_clear lic
343
344lock_info_clear()
345{
346 struct lock_info *li;
347 int bucket = 0;
348 int i;
349 for (bucket = 0; bucket < LOCK_INFO_HASH_COUNT; bucket++) {
350 li = &lock_info[bucket].info[0];
351 for (i= 0; i< LOCK_INFO_PER_BUCKET; i++, li++) {
352 bzero(li, sizeof(struct lock_info));
353 }
354 }
355 bzero(&default_lock_info, sizeof(struct lock_info));
356}
357
358print_lock_info(li)
359struct lock_info *li;
360{
361 int off;
362 int sum = li->success + li->fail;
363 db_printf("%d %d/%d %d/%d %d/%d %d/%d ", li->success,
364 li->fail, (li->fail*100)/sum,
365 li->masked, (li->masked*100)/sum,
366 li->stack, li->stack/sum,
367 li->time, li->time/sum);
368 db_search_symbol(li->lock, 0, &off);
369 if (off < 1024)
370 db_printsym(li->lock, 0);
371 else {
372 db_printsym(li->caller, 0);
373 db_printf("(%X)", li->lock);
374 }
375 db_printf("\n");
376}
377
378#endif NCPUS > 1 && MACH_LOCK_MON
379
380#if TIME_STAMP
381
382/*
383 * Measure lock/unlock operations
384 */
385
386time_lock(loops)
387{
388 decl_simple_lock_data(, lock)
389 register time_stamp_t stamp;
390 register int i;
391
392
393 if (!loops)
394 loops = 1000;
395 simple_lock_init(&lock);
396 stamp = time_stamp;
397 for (i = 0; i < loops; i++) {
398 simple_lock(&lock);
399 simple_unlock(&lock);
400 }
401 stamp = time_stamp - stamp;
402 db_printf("%d stamps for simple_locks\n", stamp/loops);
403#if MACH_LOCK_MON
404 stamp = time_stamp;
405 for (i = 0; i < loops; i++) {
406 _simple_lock(&lock);
407 _simple_unlock(&lock);
408 }
409 stamp = time_stamp - stamp;
410 db_printf("%d stamps for _simple_locks\n", stamp/loops);
411#endif MACH_LOCK_MON
412}
413#endif TIME_STAMP
414
415
416
417
418