📄 lockstat.c
字号:
break; case 'R': g_rates = 1; break; case 'p': g_pflag = 1; break; case 'P': g_Pflag = 1; break; case 'o': if ((out = fopen(optarg, "w")) == NULL) fail(1, "error opening file"); break; case 'V': g_Vflag = 1; break; default: usage(); } } if (filt != NULL) { predicate_add(&g_predicate, filt, NULL, 0); filter_destroy(&filt); } if (ifilt != NULL) { predicate_add(&g_ipredicate, ifilt, NULL, 0); filter_destroy(&ifilt); } argc -= optind; argv += optind; if (g_recsize == 0) { if (g_gflag) { g_stkdepth = LS_MAX_STACK_DEPTH; g_recsize = LS_STACK(g_stkdepth); } else { g_recsize = LS_TIME; } } if (g_gflag && g_recsize <= LS_STACK(0)) fail(0, "'-g' requires at least '-s 1' data gathering"); /* * Make sure the alignment is reasonable */ g_recsize = -(-g_recsize & -sizeof (uint64_t)); for (i = 0; i < LS_MAX_EVENTS; i++) { /* * If no events were specified, enable -C. */ if (!events_specified && g_event_info[i].ev_type == 'C') g_enabled[i] = 1; } for (i = 0; i < LS_MAX_EVENTS; i++) { if (g_enabled[i]) dprog_addevent(i); } /* * Make sure there is a child command to execute */ if (argc <= 0) usage(); data_buf_size = (g_nrecs + 1) * g_recsize; /* * By default, we set our aggregation size to be the number of records * times a slop factor. */ (void) sprintf(data_buf_str, "%ld", (long)(g_nrecs * 512)); if (!g_tracing) { if (dtrace_setopt(g_dtp, "bufsize", "4k") == -1) dfail("failed to set 'bufsize'"); if (dtrace_setopt(g_dtp, "aggsize", data_buf_str) == -1) dfail("failed to set 'aggsize'"); } else { if (dtrace_setopt(g_dtp, "bufsize", data_buf_str) == -1) dfail("failed to set 'bufsize'"); } if (dtrace_setopt(g_dtp, "statusrate", "10sec") == -1) dfail("failed to set 'statusrate'"); if ((data_buf = memalign(sizeof (uint64_t), data_buf_size)) == NULL) fail(1, "Memory allocation failed"); dprog_compile(); status_init(); g_elapsed = -gethrtime(); /* * Spawn the specified command and wait for it to complete. */ child = fork(); if (child == -1) fail(1, "cannot fork"); if (child == 0) { (void) dtrace_close(g_dtp); (void) execvp(argv[0], &argv[0]); exec_errno = errno; exit(127); } while (waitpid(child, &status, WEXITED) != child) status_check(); g_elapsed += gethrtime(); if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { if (exec_errno != 0) { errno = exec_errno; fail(1, "could not execute %s", argv[0]); } (void) fprintf(stderr, "lockstat: warning: %s exited with code %d\n", argv[0], WEXITSTATUS(status)); } } else { (void) fprintf(stderr, "lockstat: warning: %s died on signal %d\n", argv[0], WTERMSIG(status)); } if (dtrace_stop(g_dtp) == -1) dfail("failed to stop dtrace"); /* * Read out the DTrace data. */ g_nrecs_used = process_data(out, data_buf); if (g_nrecs_used >= g_nrecs || g_dropped) (void) fprintf(stderr, "lockstat: warning: " "ran out of data records (use -n for more)\n"); /* LINTED - alignment */ for (i = 0, lsp = (lsrec_t *)data_buf; i < g_nrecs_used; i++, /* LINTED - alignment */ lsp = (lsrec_t *)((char *)lsp + g_recsize)) { ev_count[lsp->ls_event] += lsp->ls_count; ev_time[lsp->ls_event] += lsp->ls_time; } /* * If -g was specified, convert stacks into individual records. */ if (g_gflag) { lsrec_t *newlsp, *oldlsp; newlsp = memalign(sizeof (uint64_t), g_nrecs_used * LS_TIME * (g_stkdepth + 1)); if (newlsp == NULL) fail(1, "Cannot allocate space for -g processing"); lsp = newlsp; /* LINTED - alignment */ for (i = 0, oldlsp = (lsrec_t *)data_buf; i < g_nrecs_used; i++, /* LINTED - alignment */ oldlsp = (lsrec_t *)((char *)oldlsp + g_recsize)) { int fr; int caller_in_stack = 0; if (oldlsp->ls_count == 0) continue; for (fr = 0; fr < g_stkdepth; fr++) { if (oldlsp->ls_stack[fr] == 0) break; if (oldlsp->ls_stack[fr] == oldlsp->ls_caller) caller_in_stack = 1; bcopy(oldlsp, lsp, LS_TIME); lsp->ls_caller = oldlsp->ls_stack[fr]; /* LINTED - alignment */ lsp = (lsrec_t *)((char *)lsp + LS_TIME); } if (!caller_in_stack) { bcopy(oldlsp, lsp, LS_TIME); /* LINTED - alignment */ lsp = (lsrec_t *)((char *)lsp + LS_TIME); } } g_nrecs = g_nrecs_used = ((uintptr_t)lsp - (uintptr_t)newlsp) / LS_TIME; g_recsize = LS_TIME; g_stkdepth = 0; free(data_buf); data_buf = (char *)newlsp; } if ((sort_buf = calloc(2 * (g_nrecs + 1), sizeof (void *))) == NULL) fail(1, "Sort buffer allocation failed"); merge_buf = sort_buf + (g_nrecs + 1); /* * Build the sort buffer, discarding zero-count records along the way. */ /* LINTED - alignment */ for (i = 0, lsp = (lsrec_t *)data_buf; i < g_nrecs_used; i++, /* LINTED - alignment */ lsp = (lsrec_t *)((char *)lsp + g_recsize)) { if (lsp->ls_count == 0) lsp->ls_event = LS_MAX_EVENTS; sort_buf[i] = lsp; } if (g_nrecs_used == 0) exit(0); /* * Add a sentinel after the last record */ sort_buf[i] = lsp; lsp->ls_event = LS_MAX_EVENTS; if (g_tracing) { report_trace(out, sort_buf); return (0); } /* * Application of -g may have resulted in multiple records * with the same signature; coalesce them. */ if (g_gflag) { mergesort(lockcmp, sort_buf, merge_buf, g_nrecs_used); coalesce(lockcmp, sort_buf, g_nrecs_used); } /* * Coalesce locks within the same symbol if -c option specified. * Coalesce PCs within the same function if -k option specified. */ if (g_cflag || g_kflag) { for (i = 0; i < g_nrecs_used; i++) { int fr; lsp = sort_buf[i]; if (g_cflag) coalesce_symbol(&lsp->ls_lock); if (g_kflag) { for (fr = 0; fr < g_stkdepth; fr++) coalesce_symbol(&lsp->ls_stack[fr]); coalesce_symbol(&lsp->ls_caller); } } mergesort(lockcmp, sort_buf, merge_buf, g_nrecs_used); coalesce(lockcmp, sort_buf, g_nrecs_used); } /* * Coalesce callers if -w option specified */ if (g_wflag) { mergesort(lock_and_count_cmp_anywhere, sort_buf, merge_buf, g_nrecs_used); coalesce(lockcmp_anywhere, sort_buf, g_nrecs_used); } /* * Coalesce locks if -W option specified */ if (g_Wflag) { mergesort(site_and_count_cmp_anylock, sort_buf, merge_buf, g_nrecs_used); coalesce(sitecmp_anylock, sort_buf, g_nrecs_used); } /* * Sort data by contention count (ls_count) or total time (ls_time), * depending on g_Pflag. Override g_Pflag if time wasn't measured. */ if (g_recsize < LS_TIME) g_Pflag = 0; if (g_Pflag) mergesort(timecmp, sort_buf, merge_buf, g_nrecs_used); else mergesort(countcmp, sort_buf, merge_buf, g_nrecs_used); /* * Display data by event type */ first = &sort_buf[0]; while ((event = (*first)->ls_event) < LS_MAX_EVENTS) { current = first; while ((lsp = *current)->ls_event == event) current++; report_stats(out, first, current - first, ev_count[event], ev_time[event]); first = current; } return (0);}static char *format_symbol(char *buf, uintptr_t addr, int show_size){ uintptr_t symoff; char *symname; size_t symsize; symname = addr_to_sym(addr, &symoff, &symsize); if (show_size && symoff == 0) (void) sprintf(buf, "%s[%ld]", symname, (long)symsize); else if (symoff == 0) (void) sprintf(buf, "%s", symname); else if (symoff < 16 && bcmp(symname, "cpu[", 4) == 0) /* CPU+PIL */ (void) sprintf(buf, "%s+%ld", symname, (long)symoff); else if (symoff <= symsize || (symoff < 256 && addr != symoff)) (void) sprintf(buf, "%s+0x%llx", symname, (unsigned long long)symoff); else (void) sprintf(buf, "0x%llx", (unsigned long long)addr); return (buf);}static voidreport_stats(FILE *out, lsrec_t **sort_buf, size_t nrecs, uint64_t total_count, uint64_t total_time){ uint32_t event = sort_buf[0]->ls_event; lsrec_t *lsp; double ptotal = 0.0; double percent; int i, j, fr; int displayed; int first_bin, last_bin, max_bin_count, total_bin_count; int rectype; char buf[256]; char lhdr[80], chdr[80]; rectype = g_recsize; if (g_topn == 0) { (void) fprintf(out, "%20llu %s\n", g_rates == 0 ? total_count : ((unsigned long long)total_count * NANOSEC) / g_elapsed, g_event_info[event].ev_desc); return; } (void) sprintf(lhdr, "%s%s", g_Wflag ? "Hottest " : "", g_event_info[event].ev_lhdr); (void) sprintf(chdr, "%s%s", g_wflag ? "Hottest " : "", "Caller"); if (!g_pflag) (void) fprintf(out, "\n%s: %.0f events in %.3f seconds (%.0f events/sec)\n\n", g_event_info[event].ev_desc, (double)total_count, (double)g_elapsed / NANOSEC, (double)total_count * NANOSEC / g_elapsed); if (!g_pflag && rectype < LS_HIST) { (void) sprintf(buf, "%s", g_event_info[event].ev_units); (void) fprintf(out, "%5s %4s %4s %4s %8s %-22s %-24s\n", g_rates ? "ops/s" : "Count", g_gflag ? "genr" : "indv", "cuml", "rcnt", rectype >= LS_TIME ? buf : "", lhdr, chdr); (void) fprintf(out, "---------------------------------" "----------------------------------------------\n"); } displayed = 0; for (i = 0; i < nrecs; i++) { lsp = sort_buf[i]; if (displayed++ >= g_topn) break; if (g_pflag) { int j; (void) fprintf(out, "%u %u", lsp->ls_event, lsp->ls_count); (void) fprintf(out, " %s", format_symbol(buf, lsp->ls_lock, g_cflag)); (void) fprintf(out, " %s", format_symbol(buf, lsp->ls_caller, 0)); (void) fprintf(out, " %f", (double)lsp->ls_refcnt / lsp->ls_count); if (rectype >= LS_TIME) (void) fprintf(out, " %llu", (unsigned long long)lsp->ls_time); if (rectype >= LS_HIST) { for (j = 0; j < 64; j++) (void) fprintf(out, " %u", lsp->ls_hist[j]); } for (j = 0; j < LS_MAX_STACK_DEPTH; j++) { if (rectype <= LS_STACK(j) || lsp->ls_stack[j] == 0) break; (void) fprintf(out, " %s", format_symbol(buf, lsp->ls_stack[j], 0)); } (void) fprintf(out, "\n"); continue; } if (rectype >= LS_HIST) { (void) fprintf(out, "---------------------------------" "----------------------------------------------\n"); (void) sprintf(buf, "%s", g_event_info[event].ev_units); (void) fprintf(out, "%5s %4s %4s %4s %8s %-22s %-24s\n", g_rates ? "ops/s" : "Count", g_gflag ? "genr" : "indv", "cuml", "rcnt", buf, lhdr, chdr); } if (g_Pflag && total_time != 0) percent = (lsp->ls_time * 100.00) / total_time; else percent = (lsp->ls_count * 100.00) / total_count; ptotal += percent; if (rectype >= LS_TIME) (void) sprintf(buf, "%llu", (unsigned long long)(lsp->ls_time / lsp->ls_count)); else buf[0] = '\0'; (void) fprintf(out, "%5llu ", g_rates == 0 ? lsp->ls_count : ((uint64_t)lsp->ls_count * NANOSEC) / g_elapsed); (void) fprintf(out, "%3.0f%% ", percent); if (g_gflag) (void) fprintf(out, "---- "); else (void) fprintf(out, "%3.0f%% ", ptotal); (void) fprintf(out, "%4.2f %8s ", (double)lsp->ls_refcnt / lsp->ls_count, buf); (void) fprintf(out, "%-22s ", format_symbol(buf, lsp->ls_lock, g_cflag)); (void) fprintf(out, "%-24s\n", format_symbol(buf, lsp->ls_caller, 0)); if (rectype < LS_HIST) continue; (void) fprintf(out, "\n"); (void) fprintf(out, "%10s %31s %-9s %-24s\n", g_event_info[event].ev_units, "------ Time Distribution ------", g_rates ? "ops/s" : "count", rectype > LS_STACK(0) ? "Stack" : ""); first_bin = 0; while (lsp->ls_hist[first_bin] == 0) first_bin++; last_bin = 63; while (lsp->ls_hist[last_bin] == 0) last_bin--; max_bin_count = 0; total_bin_count = 0; for (j = first_bin; j <= last_bin; j++) { total_bin_count += lsp->ls_hist[j]; if (lsp->ls_hist[j] > max_bin_count) max_bin_count = lsp->ls_hist[j]; } /* * If we went a few frames below the caller, ignore them */ for (fr = 3; fr > 0; fr--) if (lsp->ls_stack[fr] == lsp->ls_caller) break; for (j = first_bin; j <= last_bin; j++) { uint_t depth = (lsp->ls_hist[j] * 30) / total_bin_count; (void) fprintf(out, "%10llu |%s%s %-9u ", 1ULL << j, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + 30 - depth, " " + depth, g_rates == 0 ? lsp->ls_hist[j] : (uint_t)(((uint64_t)lsp->ls_hist[j] * NANOSEC) / g_elapsed)); if (rectype <= LS_STACK(fr) || lsp->ls_stack[fr] == 0) { (void) fprintf(out, "\n"); continue; } (void) fprintf(out, "%-24s\n", format_symbol(buf, lsp->ls_stack[fr], 0)); fr++; } while (rectype > LS_STACK(fr) && lsp->ls_stack[fr] != 0) { (void) fprintf(out, "%15s %-36s %-24s\n", "", "", format_symbol(buf, lsp->ls_stack[fr], 0)); fr++; } } if (!g_pflag) (void) fprintf(out, "---------------------------------" "----------------------------------------------\n"); (void) fflush(out);}static voidreport_trace(FILE *out, lsrec_t **sort_buf){ lsrec_t *lsp; int i, fr; int rectype; char buf[256], buf2[256]; rectype = g_recsize; if (!g_pflag) { (void) fprintf(out, "%5s %7s %11s %-24s %-24s\n", "Event", "Time", "Owner", "Lock", "Caller"); (void) fprintf(out, "---------------------------------" "----------------------------------------------\n"); } for (i = 0; i < g_nrecs_used; i++) { lsp = sort_buf[i]; if (lsp->ls_event >= LS_MAX_EVENTS || lsp->ls_count == 0) continue; (void) fprintf(out, "%2d %10llu %11p %-24s %-24s\n", lsp->ls_event, (unsigned long long)lsp->ls_time, (void *)lsp->ls_next, format_symbol(buf, lsp->ls_lock, 0), format_symbol(buf2, lsp->ls_caller, 0)); if (rectype <= LS_STACK(0)) continue; /* * If we went a few frames below the caller, ignore them */ for (fr = 3; fr > 0; fr--) if (lsp->ls_stack[fr] == lsp->ls_caller) break; while (rectype > LS_STACK(fr) && lsp->ls_stack[fr] != 0) { (void) fprintf(out, "%53s %-24s\n", "", format_symbol(buf, lsp->ls_stack[fr], 0)); fr++; } (void) fprintf(out, "\n"); } (void) fflush(out);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -