]> git.saurik.com Git - apple/xnu.git/blob - tools/lockstat/lockstat.c
xnu-1699.22.73.tar.gz
[apple/xnu.git] / tools / lockstat / lockstat.c
1 #include <mach/mach.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <signal.h>
5 #include <unistd.h>
6 #include <sys/time.h>
7 #include <time.h>
8 #include <mach/error.h>
9 #include <mach/mach_error.h>
10 #include <mach/mig_errors.h>
11 #include <mach/machine.h>
12 #include <mach/processor_info.h>
13 #include <assert.h>
14 #include <nlist.h>
15 #include <fcntl.h>
16 #include <string.h>
17 #include <mach/mach.h>
18 #include <mach/host_info.h>
19
20 /*
21 * lockstat.c
22 *
23 * Utility to display kernel lock contention statistics.
24 * Usage:
25 * lockstat [all, spin, mutex, rw, <lock group name>] {<repeat interval>} {abs}
26 *
27 * Argument 1 specifies the type of lock to display contention statistics
28 * for; alternatively, a lock group (a logically grouped set of locks,
29 * which can encompass multiple types of locks) can be specified by name.
30 * When argument 1 is "all", statistics are displayed for all lock groups
31 * which have statistics enabled.
32 * Lock types include mutexes, reader-writer locks and spin locks.
33 * Note that support for gathering contention statistics may not be present
34 * for all types of locks on all platforms.
35 *
36 * Argument 2 specifies a periodic interval. The program will display an
37 * updated list of statistics every <repeat interval> seconds. This
38 * argument is optional. The updates display the deltas from the previous
39 * set of statistics, unless "abs" is specified as argument 3.
40 *
41 * Argument 3, if "abs", causes the periodically refreshed lock statistics
42 * to be displayed as absolute values rather than deltas from the previous
43 * display.
44 *
45 * Types of statistics:
46 * Acquisitions: These can include both normal acquisitions, as well
47 * as acquisition attempts. These are listed in the first column.
48 * Examples include calls to lck_mtx_lock and lck_mtx_try_lock
49 * Misses: Incremented if a lock acquisition attempt failed, due to
50 * contention.
51 * Waits (Meaningful only for lock types that can block): Incremented
52 * if a lock acquisition attempt proceeded to block.
53 *
54 * Direct Waits (currently implemented only on i386/x86_64): For adaptive
55 * locks, such as mutexes, incremented if the owner of the mutex
56 * wasn't active on another processor at the time of the lock
57 * attempt. This indicates that no adaptive spin occurred.
58 */
59
60 /*
61 * HISTORY
62 * 2005: Bernard Semeria
63 * Created.
64 * 2006: Derek Kumar
65 * Display i386 specific stats, fix incremental display, add
66 * explanatory block comment.
67 */
68 void usage(void);
69 void print_spin_hdr(void);
70 void print_spin(int requested, lockgroup_info_t *lockgroup);
71 void print_all_spin(lockgroup_info_t *lockgroup);
72 void print_mutex_hdr(void);
73 void print_mutex(int requested, lockgroup_info_t *lockgroup);
74 void print_all_mutex(lockgroup_info_t *lockgroup);
75 void print_rw_hdr(void);
76 void print_rw(int requested, lockgroup_info_t *lockgroup);
77 void print_all_rw(lockgroup_info_t *lockgroup);
78 void prime_lockgroup_deltas(void);
79 void get_lockgroup_deltas(void);
80
81 char *pgmname;
82 mach_port_t host_control;
83
84 lockgroup_info_t *lockgroup_info, *lockgroup_start, *lockgroup_deltas;
85 unsigned int count;
86
87 unsigned int gDebug = 1;
88
89 int
90 main(int argc, char **argv)
91 {
92 kern_return_t kr;
93 int arg2;
94 unsigned int i;
95 int found;
96
97 setlinebuf(stdout);
98
99 pgmname = argv[0];
100 gDebug = (NULL != strstr(argv[0], "debug"));
101
102 host_control = mach_host_self();
103
104 kr = host_lockgroup_info(host_control, &lockgroup_info, &count);
105
106 if (kr != KERN_SUCCESS)
107 {
108 mach_error("host_statistics", kr);
109 exit (EXIT_FAILURE);
110 }
111 if (gDebug) {
112 printf("count = %d\n", count);
113 for (i = 0; i < count; i++) {
114 printf("%s\n",lockgroup_info[i].lockgroup_name);
115 }
116 }
117
118 switch (argc) {
119 case 2:
120 if (strcmp(argv[1], "all") == 0) {
121 print_spin_hdr();
122 print_all_spin(lockgroup_info);
123 print_mutex_hdr();
124 print_all_mutex(lockgroup_info);
125 print_rw_hdr();
126 print_all_rw(lockgroup_info);
127 }
128 else if (strcmp(argv[1], "spin") == 0) {
129 print_spin_hdr();
130 print_all_spin(lockgroup_info);
131 }
132 else if (strcmp(argv[1], "mutex") == 0) {
133 print_mutex_hdr();
134 print_all_mutex(lockgroup_info);
135 }
136 else if (strcmp(argv[1], "rw") == 0) {
137 print_rw_hdr();
138 print_all_rw(lockgroup_info);
139 }
140 else {
141 found = 0;
142 for (i = 0;i < count;i++) {
143 if (strcmp(argv[1], lockgroup_info[i].lockgroup_name) == 0) {
144 found = 1;
145 print_spin_hdr();
146 print_spin(i, lockgroup_info);
147 print_mutex_hdr();
148 print_mutex(i, lockgroup_info);
149 print_rw_hdr();
150 print_rw(i, lockgroup_info);
151 break;
152 }
153 }
154 if (found == 0)
155 { usage(); }
156 }
157 break;
158 case 3:
159 if (sscanf(argv[2], "%d", &arg2) != 1) {
160 usage();
161 }
162 if (arg2 < 0) {
163 usage();
164 }
165 prime_lockgroup_deltas();
166 if (strcmp(argv[1], "all") == 0) {
167
168 while (1) {
169 sleep(arg2);
170 get_lockgroup_deltas();
171 print_spin_hdr();
172 print_all_spin(lockgroup_deltas);
173 print_mutex_hdr();
174 print_all_mutex(lockgroup_deltas);
175 print_rw_hdr();
176 print_all_rw(lockgroup_deltas);
177 }
178 }
179 else if (strcmp(argv[1], "spin") == 0) {
180
181 while (1) {
182 sleep(arg2);
183 get_lockgroup_deltas();
184 print_spin_hdr();
185 print_all_spin(lockgroup_deltas);
186 }
187 }
188 else if (strcmp(argv[1], "mutex") == 0) {
189
190 while (1) {
191 sleep(arg2);
192 get_lockgroup_deltas();
193 print_mutex_hdr();
194 print_all_mutex(lockgroup_deltas);
195 }
196 }
197 else if (strcmp(argv[1], "rw") == 0) {
198
199 while (1) {
200 sleep(arg2);
201 get_lockgroup_deltas();
202 print_rw_hdr();
203 print_all_rw(lockgroup_deltas);
204 }
205 }
206 else {
207
208 found = 0;
209 for (i = 0;i < count;i++) {
210 if (strcmp(argv[1], lockgroup_info[i].lockgroup_name) == 0) {
211 found = 1;
212 while (1) {
213 sleep(arg2);
214 get_lockgroup_deltas();
215 print_spin_hdr();
216 print_spin(i, lockgroup_deltas);
217 print_mutex_hdr();
218 print_mutex(i, lockgroup_deltas);
219 print_rw_hdr();
220 print_rw(i, lockgroup_deltas);
221 }
222 }
223 }
224 if (found == 0)
225 { usage(); }
226 }
227 break;
228 case 4:
229 if (strcmp(argv[3], "abs") != 0)
230 { usage(); }
231 if (sscanf(argv[2], "%d", &arg2) != 1)
232 { usage(); }
233 if (strcmp(argv[1], "all") == 0) {
234 while (1)
235 {
236 print_spin_hdr();
237 print_all_spin(lockgroup_info);
238 print_mutex_hdr();
239 print_all_mutex(lockgroup_info);
240 print_rw_hdr();
241 print_all_rw(lockgroup_info);
242 sleep(arg2);
243 }
244 }
245 else if (strcmp(argv[1], "spin") == 0) {
246 while (1)
247 {print_all_spin(lockgroup_info);
248 sleep(arg2);
249 }
250 }
251 else if (strcmp(argv[1], "mutex") == 0) {
252 print_mutex_hdr();
253 while (1)
254 {print_all_mutex(lockgroup_info);
255 sleep(arg2);
256 }
257 }
258 else if (strcmp(argv[1], "rw") == 0) {
259 print_rw_hdr();
260 while (1)
261 {print_all_rw(lockgroup_info);
262 sleep(arg2);
263 }
264 }
265 else {
266 found = 0;
267 for (i = 0;i < count;i++) {
268 if (strcmp(argv[1], lockgroup_info[i].lockgroup_name) == 0) {
269 found = 1;
270 while (1)
271 {
272 print_spin_hdr();
273 print_spin(i, lockgroup_info);
274 print_mutex_hdr();
275 print_mutex(i, lockgroup_info);
276 print_rw_hdr();
277 print_rw(i, lockgroup_info);
278 sleep(arg2);
279 }
280 }
281 }
282 if (found == 0)
283 { usage(); }
284 }
285 break;
286 default:
287 usage();
288 break;
289 }
290
291 exit(0);
292 }
293
294 void
295 usage()
296 {
297 fprintf(stderr, "Usage: %s [all, spin, mutex, rw, <lock group name>] {<repeat interval>} {abs}\n", pgmname);
298 exit(EXIT_FAILURE);
299 }
300
301 void
302 print_spin_hdr(void)
303 {
304 printf(" Spinlock acquires misses Name\n");
305 }
306
307 void
308 print_spin(int requested, lockgroup_info_t *lockgroup)
309 {
310 lockgroup_info_t *curptr = &lockgroup[requested];
311
312 if (curptr->lock_spin_cnt != 0 && curptr->lock_spin_util_cnt != 0) {
313 printf("%16lld ", curptr->lock_spin_util_cnt);
314 printf("%16lld ", curptr->lock_spin_miss_cnt);
315 printf("%-14s\n", curptr->lockgroup_name);
316 }
317 }
318
319 void
320 print_all_spin(lockgroup_info_t *lockgroup)
321 {
322 unsigned int i;
323
324 for (i = 0;i < count;i++)
325 print_spin(i, lockgroup);
326 printf("\n");
327 }
328
329 void
330 print_mutex_hdr(void)
331 {
332 #if defined(__i386__) || defined(__x86_64__)
333 printf("Mutex lock attempts Misses Waits Direct Waits Name\n");
334 #else
335 printf(" mutex locks misses waits name\n");
336 #endif
337 }
338
339 void
340 print_mutex(int requested, lockgroup_info_t *lockgroup)
341 {
342 lockgroup_info_t *curptr = &lockgroup[requested];
343
344 if (curptr->lock_mtx_cnt != 0 && curptr->lock_mtx_util_cnt != 0) {
345 printf("%16lld ", curptr->lock_mtx_util_cnt);
346 #if defined(__i386__) || defined(__x86_64__)
347 printf("%10lld %10lld %10lld ", curptr->lock_mtx_miss_cnt, curptr->lock_mtx_wait_cnt, curptr->lock_mtx_held_cnt);
348 #else
349 printf("%16lld %16lld ", curptr->lock_mtx_miss_cnt, curptr->lock_mtx_wait_cnt);
350 #endif
351 printf("%-14s\n", curptr->lockgroup_name);
352 }
353 }
354
355 void
356 print_all_mutex(lockgroup_info_t *lockgroup)
357 {
358 unsigned int i;
359
360 for (i = 0;i < count;i++)
361 print_mutex(i, lockgroup);
362 printf("\n");
363
364 }
365
366 void
367 print_rw_hdr(void)
368 {
369 printf(" RW locks Misses Waits Name\n");
370 }
371
372 void
373 print_rw(int requested, lockgroup_info_t *lockgroup)
374 {
375 lockgroup_info_t *curptr = &lockgroup[requested];
376
377 if (curptr->lock_rw_cnt != 0 && curptr->lock_rw_util_cnt != 0) {
378 printf("%16lld ", curptr->lock_rw_util_cnt);
379 printf("%16lld %16lld ", curptr->lock_rw_miss_cnt, curptr->lock_rw_wait_cnt);
380 printf("%-14s\n", curptr->lockgroup_name);
381 }
382 }
383
384 void
385 print_all_rw(lockgroup_info_t *lockgroup)
386 {
387 unsigned int i;
388
389 for (i = 0;i < count;i++)
390 print_rw(i, lockgroup);
391 printf("\n");
392
393 }
394
395 void
396 prime_lockgroup_deltas(void)
397 {
398 lockgroup_start = calloc(count, sizeof(lockgroup_info_t));
399 if (lockgroup_start == NULL) {
400 fprintf(stderr, "Can't allocate memory for lockgroup info\n");
401 exit (EXIT_FAILURE);
402 }
403 memcpy(lockgroup_start, lockgroup_info, count * sizeof(lockgroup_info_t));
404
405 lockgroup_deltas = calloc(count, sizeof(lockgroup_info_t));
406 if (lockgroup_deltas == NULL) {
407 fprintf(stderr, "Can't allocate memory for lockgroup info\n");
408 exit (EXIT_FAILURE);
409 }
410 }
411
412 void
413 get_lockgroup_deltas(void)
414 {
415 kern_return_t kr;
416 unsigned int i;
417
418 kr = host_lockgroup_info(host_control, &lockgroup_info, &count);
419
420 if (kr != KERN_SUCCESS)
421 {
422 mach_error("host_statistics", kr);
423 exit (EXIT_FAILURE);
424 }
425
426 memcpy(lockgroup_deltas, lockgroup_info, count * sizeof(lockgroup_info_t));
427 for (i = 0; i < count; i++) {
428 lockgroup_deltas[i].lock_spin_util_cnt =
429 lockgroup_info[i].lock_spin_util_cnt -
430 lockgroup_start[i].lock_spin_util_cnt;
431 lockgroup_deltas[i].lock_spin_miss_cnt =
432 lockgroup_info[i].lock_spin_miss_cnt -
433 lockgroup_start[i].lock_spin_miss_cnt;
434 lockgroup_deltas[i].lock_mtx_util_cnt =
435 lockgroup_info[i].lock_mtx_util_cnt -
436 lockgroup_start[i].lock_mtx_util_cnt;
437 lockgroup_deltas[i].lock_mtx_miss_cnt =
438 lockgroup_info[i].lock_mtx_miss_cnt -
439 lockgroup_start[i].lock_mtx_miss_cnt;
440 lockgroup_deltas[i].lock_mtx_wait_cnt =
441 lockgroup_info[i].lock_mtx_wait_cnt -
442 lockgroup_start[i].lock_mtx_wait_cnt;
443 lockgroup_deltas[i].lock_mtx_held_cnt =
444 lockgroup_info[i].lock_mtx_held_cnt -
445 lockgroup_start[i].lock_mtx_held_cnt;
446 lockgroup_deltas[i].lock_rw_util_cnt =
447 lockgroup_info[i].lock_rw_util_cnt -
448 lockgroup_start[i].lock_rw_util_cnt;
449 lockgroup_deltas[i].lock_rw_miss_cnt =
450 lockgroup_info[i].lock_rw_miss_cnt -
451 lockgroup_start[i].lock_rw_miss_cnt;
452 lockgroup_deltas[i].lock_rw_wait_cnt =
453 lockgroup_info[i].lock_rw_wait_cnt -
454 lockgroup_start[i].lock_rw_wait_cnt;
455 }
456 memcpy(lockgroup_start, lockgroup_info, count * sizeof(lockgroup_info_t));
457 }