From 3142b37664aacab88dc8df5420ed4527807e8b60 Mon Sep 17 00:00:00 2001 From: Mark Johnston Date: Wed, 30 Sep 2015 05:46:56 +0000 Subject: [PATCH] Have lockstat(1) trace locks by name rather than by address. Previously, lockstat(1) would use a lock's address as its identifier when consuming data describing lock contention and hold events. After collecting the requested data, it would use ksyms(4) to resolve lock addresses to names. Of course, this doesn't work too well for locks contained in dynamically-allocated memory. This change modifies lockstat(1) to trace the lock names obtained from the base struct lock_object instead, leading to output that is generally much more useful. This change also removes the -c option, which is used to coalesce data for locks in an array. It's not possible to support this option without also tracing lock addresses, and since lock arrays in which the lock names are distinct are not very common in FreeBSD, it's simpler to just remove the option. Reviewed by: avg (earlier revision) Differential Revision: https://reviews.freebsd.org/D3661 --- .../opensolaris/cmd/lockstat/lockstat.1 | 6 +- .../opensolaris/cmd/lockstat/lockstat.c | 64 +++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1 b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1 index 1aa73cc114ea..552496840d3b 100644 --- a/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1 +++ b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.1 @@ -21,7 +21,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 24, 2015 +.Dd September 29, 2015 .Dt LOCKSTAT 1 .Os .Sh NAME @@ -38,7 +38,7 @@ .Op Fl d Ar duration .Op Fl f Ar function Oo Ns , Ns Ar size Oc .Op Fl T -.Op Fl ckgwWRpP +.Op Fl kgwWRpP .Op Fl D Ar count .Op Fl o filename .Op Fl x Ar opt Oo Ns = Ns Ar val Oc @@ -172,8 +172,6 @@ This is off by default. .El .Ss Data Reporting .Bl -tag -width indent -.It Fl c -Coalesce lock data for lock arrays. .It Fl D Ar count Only display the top .Ar count diff --git a/cddl/contrib/opensolaris/cmd/lockstat/lockstat.c b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.c index b59bee74f294..38bf681325e6 100644 --- a/cddl/contrib/opensolaris/cmd/lockstat/lockstat.c +++ b/cddl/contrib/opensolaris/cmd/lockstat/lockstat.c @@ -65,7 +65,11 @@ typedef uintptr_t pc_t; typedef struct lsrec { struct lsrec *ls_next; /* next in hash chain */ +#ifdef illumos uintptr_t ls_lock; /* lock address */ +#else + char *ls_lock; /* lock name */ +#endif uintptr_t ls_caller; /* caller address */ uint32_t ls_count; /* cumulative event count */ uint32_t ls_event; /* type of event */ @@ -338,7 +342,9 @@ usage(void) " -d duration only watch events longer than \n" " -T trace (rather than sample) events\n" "\nData reporting options:\n\n" +#ifdef illumos " -c coalesce lock data for arrays like pse_mutex[]\n" +#endif " -k coalesce PCs within functions\n" " -g show total events generated by function\n" " -w wherever: don't distinguish events by caller\n" @@ -381,12 +387,16 @@ lockcmp(lsrec_t *a, lsrec_t *b) if (a->ls_caller > b->ls_caller) return (1); +#ifdef illumos if (a->ls_lock < b->ls_lock) return (-1); if (a->ls_lock > b->ls_lock) return (1); return (0); +#else + return (strcmp(a->ls_lock, b->ls_lock)); +#endif } static int @@ -424,26 +434,40 @@ lockcmp_anywhere(lsrec_t *a, lsrec_t *b) if (a->ls_event > b->ls_event) return (1); +#ifdef illumos if (a->ls_lock < b->ls_lock) return (-1); if (a->ls_lock > b->ls_lock) return (1); return (0); +#else + return (strcmp(a->ls_lock, b->ls_lock)); +#endif } static int lock_and_count_cmp_anywhere(lsrec_t *a, lsrec_t *b) { +#ifndef illumos + int cmp; +#endif + if (a->ls_event < b->ls_event) return (-1); if (a->ls_event > b->ls_event) return (1); +#ifdef illumos if (a->ls_lock < b->ls_lock) return (-1); if (a->ls_lock > b->ls_lock) return (1); +#else + cmp = strcmp(a->ls_lock, b->ls_lock); + if (cmp != 0) + return (cmp); +#endif return (b->ls_count - a->ls_count); } @@ -698,7 +722,11 @@ dprog_addevent(int event) caller = "(uintptr_t)arg0"; arg1 = "arg2"; } else { +#ifdef illumos arg0 = "(uintptr_t)arg0"; +#else + arg0 = "stringof(args[0]->lock_object.lo_name)"; +#endif caller = "caller"; } @@ -912,12 +940,17 @@ lsrec_fill(lsrec_t *lsrec, const dtrace_recdesc_t *rec, int nrecs, caddr_t data) lsrec->ls_event = (uint32_t)*((uint64_t *)(data + rec->dtrd_offset)); rec++; +#ifdef illumos if (rec->dtrd_size != sizeof (uintptr_t)) fail(0, "bad lock address size in second record"); /* LINTED - alignment */ lsrec->ls_lock = *((uintptr_t *)(data + rec->dtrd_offset)); rec++; +#else + lsrec->ls_lock = strdup((const char *)(data + rec->dtrd_offset)); + rec++; +#endif if (rec->dtrd_size != sizeof (uintptr_t)) fail(0, "bad caller size in third record"); @@ -1224,9 +1257,11 @@ main(int argc, char **argv) events_specified = 1; break; +#ifdef illumos case 'c': g_cflag = 1; break; +#endif case 'k': g_kflag = 1; @@ -1539,6 +1574,9 @@ main(int argc, char **argv) caller_in_stack = 1; bcopy(oldlsp, lsp, LS_TIME); lsp->ls_caller = oldlsp->ls_stack[fr]; +#ifndef illumos + lsp->ls_lock = strdup(oldlsp->ls_lock); +#endif /* LINTED - alignment */ lsp = (lsrec_t *)((char *)lsp + LS_TIME); } @@ -1547,6 +1585,9 @@ main(int argc, char **argv) /* LINTED - alignment */ lsp = (lsrec_t *)((char *)lsp + LS_TIME); } +#ifndef illumos + free(oldlsp->ls_lock); +#endif } g_nrecs = g_nrecs_used = ((uintptr_t)lsp - (uintptr_t)newlsp) / LS_TIME; @@ -1604,8 +1645,10 @@ main(int argc, char **argv) for (i = 0; i < g_nrecs_used; i++) { int fr; lsp = sort_buf[i]; +#ifdef illumos if (g_cflag) coalesce_symbol(&lsp->ls_lock); +#endif if (g_kflag) { for (fr = 0; fr < g_stkdepth; fr++) coalesce_symbol(&lsp->ls_stack[fr]); @@ -1659,6 +1702,15 @@ main(int argc, char **argv) first = current; } +#ifndef illumos + /* + * Free lock name buffers + */ + for (i = 0, lsp = (lsrec_t *)data_buf; i < g_nrecs_used; i++, + lsp = (lsrec_t *)((char *)lsp + g_recsize)) + free(lsp->ls_lock); +#endif + return (0); } @@ -1748,8 +1800,12 @@ report_stats(FILE *out, lsrec_t **sort_buf, size_t nrecs, uint64_t total_count, (void) fprintf(out, "%u %u", lsp->ls_event, lsp->ls_count); +#ifdef illumos (void) fprintf(out, " %s", format_symbol(buf, lsp->ls_lock, g_cflag)); +#else + (void) fprintf(out, " %s", lsp->ls_lock); +#endif (void) fprintf(out, " %s", format_symbol(buf, lsp->ls_caller, 0)); (void) fprintf(out, " %f", @@ -1811,8 +1867,12 @@ report_stats(FILE *out, lsrec_t **sort_buf, size_t nrecs, uint64_t total_count, (void) fprintf(out, "%4.2f %8s ", (double)lsp->ls_refcnt / lsp->ls_count, buf); +#ifdef illumos (void) fprintf(out, "%-22s ", format_symbol(buf, lsp->ls_lock, g_cflag)); +#else + (void) fprintf(out, "%-22s ", lsp->ls_lock); +#endif (void) fprintf(out, "%-24s\n", format_symbol(buf, lsp->ls_caller, 0)); @@ -1908,7 +1968,11 @@ report_trace(FILE *out, lsrec_t **sort_buf) (void) fprintf(out, "%2d %10llu %11p %-24s %-24s\n", lsp->ls_event, (unsigned long long)lsp->ls_time, (void *)lsp->ls_next, +#ifdef illumos format_symbol(buf, lsp->ls_lock, 0), +#else + lsp->ls_lock, +#endif format_symbol(buf2, lsp->ls_caller, 0)); if (rectype <= LS_STACK(0))