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
This commit is contained in:
Mark Johnston 2015-09-30 05:46:56 +00:00
parent b22ef02080
commit 3142b37664
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=288417
2 changed files with 66 additions and 4 deletions

View File

@ -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

View File

@ -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 <duration>\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))