]> git.saurik.com Git - apple/xnu.git/blame - tools/lockstat/lockstat.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tools / lockstat / lockstat.c
CommitLineData
2d21ac55
A
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 *
6d2010ae 54 * Direct Waits (currently implemented only on i386/x86_64): For adaptive
2d21ac55
A
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 */
68void usage(void);
69void print_spin_hdr(void);
70void print_spin(int requested, lockgroup_info_t *lockgroup);
71void print_all_spin(lockgroup_info_t *lockgroup);
72void print_mutex_hdr(void);
73void print_mutex(int requested, lockgroup_info_t *lockgroup);
74void print_all_mutex(lockgroup_info_t *lockgroup);
75void print_rw_hdr(void);
76void print_rw(int requested, lockgroup_info_t *lockgroup);
77void print_all_rw(lockgroup_info_t *lockgroup);
78void prime_lockgroup_deltas(void);
79void get_lockgroup_deltas(void);
80
81char *pgmname;
82mach_port_t host_control;
83
0a7de745
A
84lockgroup_info_t *lockgroup_info, *lockgroup_start, *lockgroup_deltas;
85unsigned int count;
2d21ac55 86
0a7de745 87unsigned int gDebug = 1;
2d21ac55
A
88
89int
90main(int argc, char **argv)
91{
0a7de745
A
92 kern_return_t kr;
93 int arg2;
94 unsigned int i;
95 int found;
2d21ac55
A
96
97 setlinebuf(stdout);
98
99 pgmname = argv[0];
100 gDebug = (NULL != strstr(argv[0], "debug"));
101
0a7de745 102 host_control = mach_host_self();
2d21ac55
A
103
104 kr = host_lockgroup_info(host_control, &lockgroup_info, &count);
105
0a7de745 106 if (kr != KERN_SUCCESS) {
2d21ac55 107 mach_error("host_statistics", kr);
0a7de745 108 exit(EXIT_FAILURE);
2d21ac55
A
109 }
110 if (gDebug) {
111 printf("count = %d\n", count);
112 for (i = 0; i < count; i++) {
0a7de745 113 printf("%s\n", lockgroup_info[i].lockgroup_name);
2d21ac55
A
114 }
115 }
116
117 switch (argc) {
118 case 2:
119 if (strcmp(argv[1], "all") == 0) {
120 print_spin_hdr();
121 print_all_spin(lockgroup_info);
122 print_mutex_hdr();
123 print_all_mutex(lockgroup_info);
124 print_rw_hdr();
125 print_all_rw(lockgroup_info);
0a7de745 126 } else if (strcmp(argv[1], "spin") == 0) {
2d21ac55
A
127 print_spin_hdr();
128 print_all_spin(lockgroup_info);
0a7de745 129 } else if (strcmp(argv[1], "mutex") == 0) {
2d21ac55
A
130 print_mutex_hdr();
131 print_all_mutex(lockgroup_info);
0a7de745 132 } else if (strcmp(argv[1], "rw") == 0) {
2d21ac55
A
133 print_rw_hdr();
134 print_all_rw(lockgroup_info);
0a7de745 135 } else {
2d21ac55 136 found = 0;
0a7de745 137 for (i = 0; i < count; i++) {
2d21ac55
A
138 if (strcmp(argv[1], lockgroup_info[i].lockgroup_name) == 0) {
139 found = 1;
140 print_spin_hdr();
141 print_spin(i, lockgroup_info);
142 print_mutex_hdr();
143 print_mutex(i, lockgroup_info);
144 print_rw_hdr();
145 print_rw(i, lockgroup_info);
146 break;
147 }
148 }
0a7de745
A
149 if (found == 0) {
150 usage();
151 }
2d21ac55 152 }
0a7de745 153 break;
2d21ac55
A
154 case 3:
155 if (sscanf(argv[2], "%d", &arg2) != 1) {
156 usage();
157 }
158 if (arg2 < 0) {
159 usage();
160 }
161 prime_lockgroup_deltas();
162 if (strcmp(argv[1], "all") == 0) {
2d21ac55
A
163 while (1) {
164 sleep(arg2);
165 get_lockgroup_deltas();
166 print_spin_hdr();
167 print_all_spin(lockgroup_deltas);
168 print_mutex_hdr();
169 print_all_mutex(lockgroup_deltas);
170 print_rw_hdr();
171 print_all_rw(lockgroup_deltas);
172 }
0a7de745 173 } else if (strcmp(argv[1], "spin") == 0) {
2d21ac55
A
174 while (1) {
175 sleep(arg2);
176 get_lockgroup_deltas();
177 print_spin_hdr();
178 print_all_spin(lockgroup_deltas);
179 }
0a7de745 180 } else if (strcmp(argv[1], "mutex") == 0) {
2d21ac55
A
181 while (1) {
182 sleep(arg2);
183 get_lockgroup_deltas();
184 print_mutex_hdr();
185 print_all_mutex(lockgroup_deltas);
186 }
0a7de745 187 } else if (strcmp(argv[1], "rw") == 0) {
2d21ac55
A
188 while (1) {
189 sleep(arg2);
190 get_lockgroup_deltas();
191 print_rw_hdr();
192 print_all_rw(lockgroup_deltas);
193 }
0a7de745 194 } else {
2d21ac55 195 found = 0;
0a7de745 196 for (i = 0; i < count; i++) {
2d21ac55
A
197 if (strcmp(argv[1], lockgroup_info[i].lockgroup_name) == 0) {
198 found = 1;
199 while (1) {
200 sleep(arg2);
201 get_lockgroup_deltas();
202 print_spin_hdr();
203 print_spin(i, lockgroup_deltas);
204 print_mutex_hdr();
205 print_mutex(i, lockgroup_deltas);
206 print_rw_hdr();
207 print_rw(i, lockgroup_deltas);
208 }
209 }
210 }
0a7de745
A
211 if (found == 0) {
212 usage();
213 }
2d21ac55
A
214 }
215 break;
216 case 4:
0a7de745
A
217 if (strcmp(argv[3], "abs") != 0) {
218 usage();
219 }
220 if (sscanf(argv[2], "%d", &arg2) != 1) {
221 usage();
222 }
2d21ac55 223 if (strcmp(argv[1], "all") == 0) {
0a7de745 224 while (1) {
2d21ac55
A
225 print_spin_hdr();
226 print_all_spin(lockgroup_info);
227 print_mutex_hdr();
228 print_all_mutex(lockgroup_info);
229 print_rw_hdr();
230 print_all_rw(lockgroup_info);
231 sleep(arg2);
232 }
0a7de745
A
233 } else if (strcmp(argv[1], "spin") == 0) {
234 while (1) {
235 print_all_spin(lockgroup_info);
2d21ac55
A
236 sleep(arg2);
237 }
0a7de745 238 } else if (strcmp(argv[1], "mutex") == 0) {
2d21ac55 239 print_mutex_hdr();
0a7de745
A
240 while (1) {
241 print_all_mutex(lockgroup_info);
2d21ac55
A
242 sleep(arg2);
243 }
0a7de745 244 } else if (strcmp(argv[1], "rw") == 0) {
2d21ac55 245 print_rw_hdr();
0a7de745
A
246 while (1) {
247 print_all_rw(lockgroup_info);
2d21ac55
A
248 sleep(arg2);
249 }
0a7de745 250 } else {
2d21ac55 251 found = 0;
0a7de745 252 for (i = 0; i < count; i++) {
2d21ac55
A
253 if (strcmp(argv[1], lockgroup_info[i].lockgroup_name) == 0) {
254 found = 1;
0a7de745 255 while (1) {
2d21ac55
A
256 print_spin_hdr();
257 print_spin(i, lockgroup_info);
258 print_mutex_hdr();
259 print_mutex(i, lockgroup_info);
260 print_rw_hdr();
261 print_rw(i, lockgroup_info);
262 sleep(arg2);
263 }
264 }
265 }
0a7de745
A
266 if (found == 0) {
267 usage();
268 }
2d21ac55
A
269 }
270 break;
271 default:
272 usage();
273 break;
0a7de745 274 }
2d21ac55
A
275
276 exit(0);
277}
0a7de745
A
278
279void
2d21ac55
A
280usage()
281{
282 fprintf(stderr, "Usage: %s [all, spin, mutex, rw, <lock group name>] {<repeat interval>} {abs}\n", pgmname);
283 exit(EXIT_FAILURE);
284}
285
286void
287print_spin_hdr(void)
288{
289 printf(" Spinlock acquires misses Name\n");
290}
291
292void
293print_spin(int requested, lockgroup_info_t *lockgroup)
294{
0a7de745 295 lockgroup_info_t *curptr = &lockgroup[requested];
2d21ac55
A
296
297 if (curptr->lock_spin_cnt != 0 && curptr->lock_spin_util_cnt != 0) {
298 printf("%16lld ", curptr->lock_spin_util_cnt);
299 printf("%16lld ", curptr->lock_spin_miss_cnt);
300 printf("%-14s\n", curptr->lockgroup_name);
301 }
302}
303
304void
305print_all_spin(lockgroup_info_t *lockgroup)
306{
0a7de745 307 unsigned int i;
2d21ac55 308
0a7de745 309 for (i = 0; i < count; i++) {
2d21ac55 310 print_spin(i, lockgroup);
0a7de745
A
311 }
312 printf("\n");
2d21ac55
A
313}
314
315void
316print_mutex_hdr(void)
317{
6d2010ae 318#if defined(__i386__) || defined(__x86_64__)
2d21ac55
A
319 printf("Mutex lock attempts Misses Waits Direct Waits Name\n");
320#else
0a7de745 321 printf(" mutex locks misses waits name\n");
2d21ac55
A
322#endif
323}
324
325void
326print_mutex(int requested, lockgroup_info_t *lockgroup)
327{
0a7de745 328 lockgroup_info_t *curptr = &lockgroup[requested];
2d21ac55
A
329
330 if (curptr->lock_mtx_cnt != 0 && curptr->lock_mtx_util_cnt != 0) {
331 printf("%16lld ", curptr->lock_mtx_util_cnt);
6d2010ae 332#if defined(__i386__) || defined(__x86_64__)
0a7de745 333 printf("%10lld %10lld %10lld ", curptr->lock_mtx_miss_cnt, curptr->lock_mtx_wait_cnt, curptr->lock_mtx_held_cnt);
2d21ac55 334#else
0a7de745 335 printf("%16lld %16lld ", curptr->lock_mtx_miss_cnt, curptr->lock_mtx_wait_cnt);
2d21ac55
A
336#endif
337 printf("%-14s\n", curptr->lockgroup_name);
338 }
339}
340
341void
342print_all_mutex(lockgroup_info_t *lockgroup)
343{
0a7de745 344 unsigned int i;
2d21ac55 345
0a7de745 346 for (i = 0; i < count; i++) {
2d21ac55 347 print_mutex(i, lockgroup);
0a7de745
A
348 }
349 printf("\n");
2d21ac55
A
350}
351
352void
353print_rw_hdr(void)
354{
355 printf(" RW locks Misses Waits Name\n");
356}
357
358void
359print_rw(int requested, lockgroup_info_t *lockgroup)
360{
0a7de745 361 lockgroup_info_t *curptr = &lockgroup[requested];
2d21ac55
A
362
363 if (curptr->lock_rw_cnt != 0 && curptr->lock_rw_util_cnt != 0) {
364 printf("%16lld ", curptr->lock_rw_util_cnt);
0a7de745 365 printf("%16lld %16lld ", curptr->lock_rw_miss_cnt, curptr->lock_rw_wait_cnt);
2d21ac55
A
366 printf("%-14s\n", curptr->lockgroup_name);
367 }
368}
369
370void
371print_all_rw(lockgroup_info_t *lockgroup)
372{
0a7de745 373 unsigned int i;
2d21ac55 374
0a7de745 375 for (i = 0; i < count; i++) {
2d21ac55 376 print_rw(i, lockgroup);
0a7de745
A
377 }
378 printf("\n");
2d21ac55
A
379}
380
381void
382prime_lockgroup_deltas(void)
383{
384 lockgroup_start = calloc(count, sizeof(lockgroup_info_t));
385 if (lockgroup_start == NULL) {
386 fprintf(stderr, "Can't allocate memory for lockgroup info\n");
0a7de745 387 exit(EXIT_FAILURE);
2d21ac55
A
388 }
389 memcpy(lockgroup_start, lockgroup_info, count * sizeof(lockgroup_info_t));
390
0a7de745 391 lockgroup_deltas = calloc(count, sizeof(lockgroup_info_t));
2d21ac55
A
392 if (lockgroup_deltas == NULL) {
393 fprintf(stderr, "Can't allocate memory for lockgroup info\n");
0a7de745 394 exit(EXIT_FAILURE);
2d21ac55
A
395 }
396}
397
398void
399get_lockgroup_deltas(void)
400{
0a7de745
A
401 kern_return_t kr;
402 unsigned int i;
2d21ac55
A
403
404 kr = host_lockgroup_info(host_control, &lockgroup_info, &count);
405
0a7de745 406 if (kr != KERN_SUCCESS) {
2d21ac55 407 mach_error("host_statistics", kr);
0a7de745 408 exit(EXIT_FAILURE);
2d21ac55
A
409 }
410
411 memcpy(lockgroup_deltas, lockgroup_info, count * sizeof(lockgroup_info_t));
412 for (i = 0; i < count; i++) {
413 lockgroup_deltas[i].lock_spin_util_cnt =
414 lockgroup_info[i].lock_spin_util_cnt -
415 lockgroup_start[i].lock_spin_util_cnt;
416 lockgroup_deltas[i].lock_spin_miss_cnt =
417 lockgroup_info[i].lock_spin_miss_cnt -
418 lockgroup_start[i].lock_spin_miss_cnt;
419 lockgroup_deltas[i].lock_mtx_util_cnt =
420 lockgroup_info[i].lock_mtx_util_cnt -
421 lockgroup_start[i].lock_mtx_util_cnt;
422 lockgroup_deltas[i].lock_mtx_miss_cnt =
423 lockgroup_info[i].lock_mtx_miss_cnt -
424 lockgroup_start[i].lock_mtx_miss_cnt;
425 lockgroup_deltas[i].lock_mtx_wait_cnt =
426 lockgroup_info[i].lock_mtx_wait_cnt -
427 lockgroup_start[i].lock_mtx_wait_cnt;
428 lockgroup_deltas[i].lock_mtx_held_cnt =
429 lockgroup_info[i].lock_mtx_held_cnt -
430 lockgroup_start[i].lock_mtx_held_cnt;
431 lockgroup_deltas[i].lock_rw_util_cnt =
432 lockgroup_info[i].lock_rw_util_cnt -
433 lockgroup_start[i].lock_rw_util_cnt;
434 lockgroup_deltas[i].lock_rw_miss_cnt =
435 lockgroup_info[i].lock_rw_miss_cnt -
436 lockgroup_start[i].lock_rw_miss_cnt;
437 lockgroup_deltas[i].lock_rw_wait_cnt =
438 lockgroup_info[i].lock_rw_wait_cnt -
439 lockgroup_start[i].lock_rw_wait_cnt;
440 }
441 memcpy(lockgroup_start, lockgroup_info, count * sizeof(lockgroup_info_t));
442}