- Increase default number of trace buffers to 10000.

- New options:
     -f         Trace only by calling functions.
     -m         Merge call sites within unique functions.
     -M         Merge lock addresses within unique objects.
This commit is contained in:
ad 2007-07-14 13:30:43 +00:00
parent 8f6e6386cb
commit 5c2240bb95
5 changed files with 146 additions and 49 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: lockstat.c,v 1.9 2007/06/15 20:17:07 ad Exp $ */ /* $NetBSD: lockstat.c,v 1.10 2007/07/14 13:30:44 ad Exp $ */
/*- /*-
* Copyright (c) 2006, 2007 The NetBSD Foundation, Inc. * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
@ -44,7 +44,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lockstat.c,v 1.9 2007/06/15 20:17:07 ad Exp $"); __KERNEL_RCSID(0, "$NetBSD: lockstat.c,v 1.10 2007/07/14 13:30:44 ad Exp $");
#include <sys/types.h> #include <sys/types.h>
#include <sys/param.h> #include <sys/param.h>
@ -69,9 +69,9 @@ __KERNEL_RCSID(0, "$NetBSD: lockstat.c,v 1.9 2007/06/15 20:17:07 ad Exp $");
#define LOCKSTAT_HASH_SHIFT 2 #define LOCKSTAT_HASH_SHIFT 2
#endif #endif
#define LOCKSTAT_MINBUFS 100 #define LOCKSTAT_MINBUFS 1000
#define LOCKSTAT_DEFBUFS 1000 #define LOCKSTAT_DEFBUFS 10000
#define LOCKSTAT_MAXBUFS 10000 #define LOCKSTAT_MAXBUFS 50000
#define LOCKSTAT_HASH_SIZE 64 #define LOCKSTAT_HASH_SIZE 64
#define LOCKSTAT_HASH_MASK (LOCKSTAT_HASH_SIZE - 1) #define LOCKSTAT_HASH_MASK (LOCKSTAT_HASH_SIZE - 1)
@ -103,6 +103,7 @@ volatile u_int lockstat_enabled;
uintptr_t lockstat_csstart; uintptr_t lockstat_csstart;
uintptr_t lockstat_csend; uintptr_t lockstat_csend;
uintptr_t lockstat_csmask; uintptr_t lockstat_csmask;
uintptr_t lockstat_lamask;
uintptr_t lockstat_lockstart; uintptr_t lockstat_lockstart;
uintptr_t lockstat_lockend; uintptr_t lockstat_lockend;
@ -236,6 +237,11 @@ lockstat_start(lsenable_t *le)
else else
lockstat_csmask = 0; lockstat_csmask = 0;
if ((le->le_flags & LE_LOCK) != 0)
lockstat_lamask = (uintptr_t)-1LL;
else
lockstat_lamask = 0;
lockstat_csstart = le->le_csstart; lockstat_csstart = le->le_csstart;
lockstat_csend = le->le_csend; lockstat_csend = le->le_csend;
lockstat_lockstart = le->le_lockstart; lockstat_lockstart = le->le_lockstart;
@ -373,6 +379,7 @@ lockstat_event(uintptr_t lock, uintptr_t callsite, u_int flags, u_int count,
return; return;
callsite &= lockstat_csmask; callsite &= lockstat_csmask;
lock &= lockstat_lamask;
/* /*
* Find the table for this lock+callsite pair, and try to locate a * Find the table for this lock+callsite pair, and try to locate a

View File

@ -1,4 +1,4 @@
/* $NetBSD: lockstat.h,v 1.4 2007/02/09 21:55:26 ad Exp $ */ /* $NetBSD: lockstat.h,v 1.5 2007/07/14 13:30:44 ad Exp $ */
/*- /*-
* Copyright (c) 2006 The NetBSD Foundation, Inc. * Copyright (c) 2006 The NetBSD Foundation, Inc.
@ -59,7 +59,7 @@
#define IOC_LOCKSTAT_GVERSION _IOR('L', 0, int) #define IOC_LOCKSTAT_GVERSION _IOR('L', 0, int)
#define LS_VERSION 3 #define LS_VERSION 4
/* /*
* Enable request. We can limit tracing by the call site and by * Enable request. We can limit tracing by the call site and by
@ -72,6 +72,7 @@
#define LE_CALLSITE 0x01 /* track call sites */ #define LE_CALLSITE 0x01 /* track call sites */
#define LE_ONE_CALLSITE 0x02 /* specific call site */ #define LE_ONE_CALLSITE 0x02 /* specific call site */
#define LE_ONE_LOCK 0x04 /* specific lock */ #define LE_ONE_LOCK 0x04 /* specific lock */
#define LE_LOCK 0x08 /* track locks */
typedef struct lsenable { typedef struct lsenable {
uintptr_t le_csstart; /* callsite start */ uintptr_t le_csstart; /* callsite start */

View File

@ -1,4 +1,4 @@
/* $NetBSD: elf32.c,v 1.5 2006/12/25 11:57:40 ad Exp $ */ /* $NetBSD: elf32.c,v 1.6 2007/07/14 13:30:43 ad Exp $ */
/*- /*-
* Copyright (c) 2006 The NetBSD Foundation, Inc. * Copyright (c) 2006 The NetBSD Foundation, Inc.
@ -72,7 +72,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#if !defined(lint) #if !defined(lint)
__RCSID("$NetBSD: elf32.c,v 1.5 2006/12/25 11:57:40 ad Exp $"); __RCSID("$NetBSD: elf32.c,v 1.6 2007/07/14 13:30:43 ad Exp $");
#endif #endif
#ifndef ELFSIZE #ifndef ELFSIZE
@ -217,6 +217,11 @@ NAME(findsym)(findsym_t find, char *name, uintptr_t *start, uintptr_t *end)
if (*start < sa || *start > ea) if (*start < sa || *start > ea)
break; break;
off = (int)(*start - sa); off = (int)(*start - sa);
*start = sa;
if (end != NULL)
*end = ea;
if (name == NULL)
goto found;
if (off == 0) if (off == 0)
strlcpy(name, &strp[symp[i].st_name], strlcpy(name, &strp[symp[i].st_name],
NAME_SIZE); NAME_SIZE);

View File

@ -1,6 +1,6 @@
.\" $NetBSD: lockstat.8,v 1.5 2006/12/15 20:25:55 ad Exp $ .\" $NetBSD: lockstat.8,v 1.6 2007/07/14 13:30:43 ad Exp $
.\" .\"
.\" Copyright (c) 2006 The NetBSD Foundation, Inc. .\" Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
.\" All rights reserved. .\" All rights reserved.
.\" .\"
.\" This code is derived from software contributed to The NetBSD Foundation .\" This code is derived from software contributed to The NetBSD Foundation
@ -34,7 +34,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE. .\" POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd September 1, 2006 .Dd July 14, 2007
.Dt LOCKSTAT 8 .Dt LOCKSTAT 8
.Os .Os
.Sh NAME .Sh NAME
@ -42,7 +42,7 @@
.Nd display kernel locking statistics .Nd display kernel locking statistics
.Sh SYNOPSIS .Sh SYNOPSIS
.Nm .Nm
.Op Fl celpst .Op Fl ceflMmpst
.Op Fl b Ar nbuf .Op Fl b Ar nbuf
.Op Fl E Ar event .Op Fl E Ar event
.Op Fl F Ar func .Op Fl F Ar func
@ -86,6 +86,8 @@ option to list valid events.
List valid event types for the List valid event types for the
.Fl E .Fl E
option and exit. option and exit.
.It Fl f
Trace only by calling functions; do not report on individual locks.
.It Fl F Ar func .It Fl F Ar func
Limit tracing to locking operations performed within the specified function. Limit tracing to locking operations performed within the specified function.
.Ar func .Ar func
@ -97,6 +99,10 @@ may either be the name of a lock object in the kernel, or a kernel virtual
address. address.
.It Fl l .It Fl l
Trace only by lock; do not report on calling functions. Trace only by lock; do not report on calling functions.
.It Fl m
Merge call sites within unique functions.
.It Fl M
Merge lock addresses within unique objects.
.It Fl N Ar nlist .It Fl N Ar nlist
Extract symbol information from the Extract symbol information from the
.Ar nlist .Ar nlist
@ -137,16 +143,27 @@ namelist
.El .El
.Sh EXAMPLES .Sh EXAMPLES
.Bd -literal .Bd -literal
# lockstat sleep 10 # lockstat -T kernel_lock sleep 10
Elapsed time: 10.02s Elapsed time: 10.01 seconds.
-- Spin mutex spin -- Kernel lock spin
Total% Count Time/ms Lock Caller Total% Count Time/ms Lock Caller
------ ------- --------- -------------- ------------------------------- ------ ------- --------- ---------------------- ------------------------------
100.00 1576 44.27 kernel_mutex \*[Lt]all\*[Gt] 100.00 74941 1545.54 kernel_lock <all>
95.71 1493 42.46 kernel_mutex _kernel_lock+0xd1 43.54 28467 673.00 kernel_lock trap+71e
4.29 82 1.80 kernel_mutex _kernel_lock_acquire_count+0xb0 42.87 34466 662.51 kernel_lock syscall_plain+111
7.38 7565 114.14 kernel_lock uiomove+17a
1.92 1221 29.61 kernel_lock sleepq_block+20b
1.84 1759 28.40 kernel_lock trap+706
0.81 124 12.54 kernel_lock x86_softintlock+1a
0.64 587 9.87 kernel_lock pmap_load+2a6
0.52 214 8.10 kernel_lock intr_biglock_wrapper+1e
0.20 219 3.09 kernel_lock pmap_load+323
0.14 175 2.12 kernel_lock do_sys_wait+2d0
0.09 85 1.43 kernel_lock lwp_startup+66
0.04 49 0.64 kernel_lock sleepq_block+18c
0.01 10 0.12 kernel_lock lwp_userret+3c
.Ed .Ed
.Sh DIAGNOSTICS .Sh DIAGNOSTICS
.Bl -diag .Bl -diag

View File

@ -1,7 +1,7 @@
/* $NetBSD: main.c,v 1.8 2007/01/20 20:01:03 ad Exp $ */ /* $NetBSD: main.c,v 1.9 2007/07/14 13:30:44 ad Exp $ */
/*- /*-
* Copyright (c) 2006 The NetBSD Foundation, Inc. * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
* All rights reserved. * All rights reserved.
* *
* This code is derived from software contributed to The NetBSD Foundation * This code is derived from software contributed to The NetBSD Foundation
@ -49,7 +49,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifndef lint #ifndef lint
__RCSID("$NetBSD: main.c,v 1.8 2007/01/20 20:01:03 ad Exp $"); __RCSID("$NetBSD: main.c,v 1.9 2007/07/14 13:30:44 ad Exp $");
#endif /* not lint */ #endif /* not lint */
#include <sys/types.h> #include <sys/types.h>
@ -73,6 +73,7 @@ __RCSID("$NetBSD: main.c,v 1.8 2007/01/20 20:01:03 ad Exp $");
#include <util.h> #include <util.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdbool.h>
#include "extern.h" #include "extern.h"
@ -138,9 +139,10 @@ locklist_t sortlist;
lsbuf_t *bufs; lsbuf_t *bufs;
lsdisable_t ld; lsdisable_t ld;
int lflag; bool lflag;
bool fflag;
int nbufs; int nbufs;
int cflag; bool cflag;
int lsfd; int lsfd;
int displayed; int displayed;
int bin64; int bin64;
@ -149,11 +151,12 @@ double cscale;
double cpuscale[sizeof(ld.ld_freq) / sizeof(ld.ld_freq[0])]; double cpuscale[sizeof(ld.ld_freq) / sizeof(ld.ld_freq[0])];
FILE *outfp; FILE *outfp;
void findsym(findsym_t, char *, uintptr_t *, uintptr_t *); void findsym(findsym_t, char *, uintptr_t *, uintptr_t *, bool);
void spawn(int, char **); void spawn(int, char **);
void display(int, const char *name); void display(int, const char *name);
void listnames(const name_t *); void listnames(const name_t *);
int matchname(const name_t *, const char *); void collapse(bool, bool);
int matchname(const name_t *, char *);
void makelists(int, int); void makelists(int, int);
void nullsig(int); void nullsig(int);
void usage(void); void usage(void);
@ -163,7 +166,8 @@ lock_t *morelocks(void);
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int eventtype, locktype, ch, nlfd, sflag, fd, i, pflag; int eventtype, locktype, ch, nlfd, fd, i;
bool sflag, pflag, mflag, Mflag;
const char *nlistf, *outf; const char *nlistf, *outf;
char *lockname, *funcname; char *lockname, *funcname;
const name_t *name; const name_t *name;
@ -178,10 +182,12 @@ main(int argc, char **argv)
eventtype = -1; eventtype = -1;
locktype = -1; locktype = -1;
nbufs = 0; nbufs = 0;
sflag = 0; sflag = false;
pflag = 0; pflag = false;
mflag = false;
Mflag = false;
while ((ch = getopt(argc, argv, "E:F:L:M:N:T:b:ceflo:pst")) != -1) while ((ch = getopt(argc, argv, "E:F:L:MN:T:b:ceflmo:pst")) != -1)
switch (ch) { switch (ch) {
case 'E': case 'E':
eventtype = matchname(eventnames, optarg); eventtype = matchname(eventnames, optarg);
@ -204,22 +210,31 @@ main(int argc, char **argv)
usage(); usage();
break; break;
case 'c': case 'c':
cflag = 1; cflag = true;
break; break;
case 'e': case 'e':
listnames(eventnames); listnames(eventnames);
break; break;
case 'f':
fflag = true;
break;
case 'l': case 'l':
lflag = 1; lflag = true;
break;
case 'm':
mflag = true;
break;
case 'M':
Mflag = true;
break; break;
case 'o': case 'o':
outf = optarg; outf = optarg;
break; break;
case 'p': case 'p':
pflag = 1; pflag = true;
break; break;
case 's': case 's':
sflag = 1; sflag = true;
break; break;
case 't': case 't':
listnames(locknames); listnames(locknames);
@ -270,15 +285,17 @@ main(int argc, char **argv)
*/ */
if (lockname != NULL) { if (lockname != NULL) {
findsym(LOCK_BYNAME, lockname, &le.le_lockstart, findsym(LOCK_BYNAME, lockname, &le.le_lockstart,
&le.le_lockend); &le.le_lockend, true);
le.le_flags |= LE_ONE_LOCK; le.le_flags |= LE_ONE_LOCK;
} }
if (!lflag) if (!lflag)
le.le_flags |= LE_CALLSITE; le.le_flags |= LE_CALLSITE;
if (!fflag)
le.le_flags |= LE_LOCK;
if (funcname != NULL) { if (funcname != NULL) {
if (lflag) if (lflag)
usage(); usage();
findsym(FUNC_BYNAME, funcname, &le.le_csstart, &le.le_csend); findsym(FUNC_BYNAME, funcname, &le.le_csstart, &le.le_csend, true);
le.le_flags |= LE_ONE_CALLSITE; le.le_flags |= LE_ONE_CALLSITE;
} }
le.le_mask = (eventtype & LB_EVENT_MASK) | (locktype & LB_LOCK_MASK); le.le_mask = (eventtype & LB_EVENT_MASK) | (locktype & LB_LOCK_MASK);
@ -340,6 +357,9 @@ main(int argc, char **argv)
TAILQ_INIT(&sortlist); TAILQ_INIT(&sortlist);
TAILQ_INIT(&freelist); TAILQ_INIT(&freelist);
if ((mflag | Mflag) != 0)
collapse(mflag, Mflag);
/* /*
* Display the results. * Display the results.
*/ */
@ -381,9 +401,12 @@ usage(void)
"-c\t\treport percentage of total events by count, not time\n" "-c\t\treport percentage of total events by count, not time\n"
"-E evt\t\tdisplay only one type of event\n" "-E evt\t\tdisplay only one type of event\n"
"-e\t\tlist event types\n" "-e\t\tlist event types\n"
"-f\t\ttrace only by function\n"
"-F func\t\tlimit trace to one function\n" "-F func\t\tlimit trace to one function\n"
"-L lock\t\tlimit trace to one lock (name, or address)\n" "-L lock\t\tlimit trace to one lock (name, or address)\n"
"-l\t\ttrace only by lock\n" "-l\t\ttrace only by lock\n"
"-m\t\tmerge call sites within unique functions\n"
"-M\t\tmerge lock addresses within unique objects\n"
"-N nlist\tspecify name list file\n" "-N nlist\tspecify name list file\n"
"-o file\t\tsend output to named file, not stdout\n" "-o file\t\tsend output to named file, not stdout\n"
"-p\t\tshow average count/time per CPU, not total\n" "-p\t\tshow average count/time per CPU, not total\n"
@ -413,16 +436,33 @@ listnames(const name_t *name)
} }
int int
matchname(const name_t *name, const char *string) matchname(const name_t *name, char *string)
{ {
int empty, mask;
char *sp;
for (; name->name != NULL; name++) empty = 1;
if (strcasecmp(name->name, string) == 0) mask = 0;
return name->mask;
warnx("unknown type `%s'", string); while ((sp = strsep(&string, ",")) != NULL) {
usage(); if (*sp == '\0')
return 0; usage();
for (; name->name != NULL; name++) {
if (strcasecmp(name->name, sp) == 0) {
mask |= name->mask;
break;
}
}
if (name->name == NULL)
errx(EXIT_FAILURE, "unknown identifier `%s'", sp);
empty = 0;
}
if (empty)
usage();
return mask;
} }
/* /*
@ -447,12 +487,18 @@ ncpu(void)
* Call into the ELF parser and look up a symbol by name or by address. * Call into the ELF parser and look up a symbol by name or by address.
*/ */
void void
findsym(findsym_t find, char *name, uintptr_t *start, uintptr_t *end) findsym(findsym_t find, char *name, uintptr_t *start, uintptr_t *end, bool chg)
{ {
uintptr_t tend; uintptr_t tend, sa, ea;
char *p; char *p;
int rv; int rv;
if (!chg) {
sa = *start;
start = &sa;
end = &ea;
}
if (end == NULL) if (end == NULL)
end = &tend; end = &tend;
@ -523,6 +569,26 @@ morelocks(void)
return l; return l;
} }
/*
* Collapse addresses from unique objects.
*/
void
collapse(bool func, bool lock)
{
lsbuf_t *lb, *max;
for (lb = bufs, max = bufs + nbufs; lb < max; lb++) {
if (func && lb->lb_callsite != 0) {
findsym(FUNC_BYADDR, NULL, &lb->lb_callsite, NULL,
true);
}
if (lock && lb->lb_lock != 0) {
findsym(LOCK_BYADDR, NULL, &lb->lb_lock, NULL,
true);
}
}
}
/* /*
* From the kernel supplied data, construct two dimensional lists of locks * From the kernel supplied data, construct two dimensional lists of locks
* and event buffers, indexed by lock type and sorted by event type. * and event buffers, indexed by lock type and sorted by event type.
@ -698,7 +764,7 @@ display(int mask, const char *name)
metric *= pcscale; metric *= pcscale;
if (l->name[0] == '\0') if (l->name[0] == '\0')
findsym(LOCK_BYADDR, l->name, &l->lock, NULL); findsym(LOCK_BYADDR, l->name, &l->lock, NULL, false);
if (lflag || l->nbufs > 1) if (lflag || l->nbufs > 1)
fprintf(outfp, "%6.2f %7d %9.2f %-22s <all>\n", fprintf(outfp, "%6.2f %7d %9.2f %-22s <all>\n",
@ -715,7 +781,8 @@ display(int mask, const char *name)
metric = lb->lb_times[event]; metric = lb->lb_times[event];
metric *= pcscale; metric *= pcscale;
findsym(FUNC_BYADDR, fname, &lb->lb_callsite, NULL); findsym(FUNC_BYADDR, fname, &lb->lb_callsite, NULL,
false);
fprintf(outfp, "%6.2f %7d %9.2f %-22s %s\n", fprintf(outfp, "%6.2f %7d %9.2f %-22s %s\n",
metric, (int)(lb->lb_counts[event] * cscale), metric, (int)(lb->lb_counts[event] * cscale),
lb->lb_times[event] * tscale, l->name, fname); lb->lb_times[event] * tscale, l->name, fname);