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 */ 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 84lockgroup_info_t *lockgroup_info, *lockgroup_start, *lockgroup_deltas; 85unsigned int count; 86 87unsigned int gDebug = 1; 88 89int 90main(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 294void 295usage() 296{ 297 fprintf(stderr, "Usage: %s [all, spin, mutex, rw, <lock group name>] {<repeat interval>} {abs}\n", pgmname); 298 exit(EXIT_FAILURE); 299} 300 301void 302print_spin_hdr(void) 303{ 304 printf(" Spinlock acquires misses Name\n"); 305} 306 307void 308print_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 319void 320print_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 329void 330print_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 339void 340print_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 355void 356print_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 366void 367print_rw_hdr(void) 368{ 369 printf(" RW locks Misses Waits Name\n"); 370} 371 372void 373print_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 384void 385print_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 395void 396prime_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 412void 413get_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} 458