diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2013-02-11 17:08:54 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2013-02-11 17:08:54 +0000 |
commit | 978c2a9a6ce439c855d41c5574cde2c05d305dea (patch) | |
tree | 80a1b938cee19a7f5c11387d3fa886cdb3e0abb6 | |
parent | 0bc83736ede1f82c457e48727982eae123b2a215 (diff) |
Teach kgmon(8) to deal with per-CPU kernel profiling.
ok mikeb@, haesbaert@
-rw-r--r-- | usr.sbin/kgmon/kgmon.8 | 35 | ||||
-rw-r--r-- | usr.sbin/kgmon/kgmon.c | 144 |
2 files changed, 117 insertions, 62 deletions
diff --git a/usr.sbin/kgmon/kgmon.8 b/usr.sbin/kgmon/kgmon.8 index dbbc34faa64..7667c9310c0 100644 --- a/usr.sbin/kgmon/kgmon.8 +++ b/usr.sbin/kgmon/kgmon.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: kgmon.8,v 1.9 2007/05/31 19:20:25 jmc Exp $ +.\" $OpenBSD: kgmon.8,v 1.10 2013/02/11 17:08:53 mpi Exp $ .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -27,9 +27,9 @@ .\" SUCH DAMAGE. .\" .\" from: @(#)kgmon.8 8.1 (Berkeley) 6/6/93 -.\" $Id: kgmon.8,v 1.9 2007/05/31 19:20:25 jmc Exp $ +.\" $Id: kgmon.8,v 1.10 2013/02/11 17:08:53 mpi Exp $ .\" -.Dd $Mdocdate: May 31 2007 $ +.Dd $Mdocdate: February 11 2013 $ .Dt KGMON 8 .Os .Sh NAME @@ -38,6 +38,7 @@ .Sh SYNOPSIS .Nm kgmon .Op Fl bhpr +.Op Fl c Ar cpuid .Op Fl M Ar core .Op Fl N Ar system .Sh DESCRIPTION @@ -45,7 +46,7 @@ is a tool used when profiling the operating system. When no arguments are supplied, .Nm kgmon -indicates the state of operating system profiling as +indicates the state of per-CPU operating system profilings as .Dq running , .Dq off , or @@ -56,15 +57,18 @@ If the .Fl p flag is specified, .Nm kgmon -extracts profile data from the operating system and produces a -.Pa gmon.out -file suitable for later analysis by +extracts profile data from the operating system and produces a file for each +CPU suitable for later analysis by .Xr gprof 1 . .Pp The options are as follows: .Bl -tag -width Ds .It Fl b Resume the collection of profile data. +.It Fl c Ar cpuid +Operate on the CPU specified by +.Pa cpuid +instead of all of them. .It Fl h Stop the collection of profile data. .It Fl M Ar core @@ -79,15 +83,16 @@ instead of the default .Pa /bsd . .It Fl p Dump the contents of the profile buffers into a -.Pa gmon.out -file. +.Pa gmon-<id>.out +file where +.Dq id +is the id of the CPU. .It Fl r Reset all the profile buffers. If the .Fl p -flag is also specified, the -.Pa gmon.out -file is generated before the buffers are reset. +flag is also specified, the profile files are generated before the buffers are +reset. .El .Pp If neither @@ -113,10 +118,8 @@ Users with only read permission on .Pa /dev/kmem cannot change the state of profiling collection. -They can get a -.Pa gmon.out -file with the warning that the data may be -inconsistent if profiling is in progress. +They can get profile files with the warning that the data may be inconsistent +if profiling is in progress. .Sh SEE ALSO .Xr gprof 1 , .Xr config 8 diff --git a/usr.sbin/kgmon/kgmon.c b/usr.sbin/kgmon/kgmon.c index 7f4c8cf56a7..887a8c84368 100644 --- a/usr.sbin/kgmon/kgmon.c +++ b/usr.sbin/kgmon/kgmon.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kgmon.c,v 1.15 2009/10/27 23:59:51 deraadt Exp $ */ +/* $OpenBSD: kgmon.c,v 1.16 2013/02/11 17:08:53 mpi Exp $ */ /* * Copyright (c) 1983, 1992, 1993 @@ -58,28 +58,32 @@ struct kvmvars { struct gmonparam gpm; }; -int bflag, hflag, kflag, rflag, pflag; +extern char *__progname; + +int bflag, cflag, hflag, kflag, rflag, pflag; int debug = 0; -void setprof(struct kvmvars *, int); -void dumpstate(struct kvmvars *); -void reset(struct kvmvars *); +void kgmon(char *, char *, struct kvmvars *, int); +void setprof(struct kvmvars *, int, int); +void dumpstate(struct kvmvars *, int); +void reset(struct kvmvars *, int); void kern_readonly(int); -int getprof(struct kvmvars *); +int getprof(struct kvmvars *, int); int getprofhz(struct kvmvars *); -int openfiles(char *, char *, struct kvmvars *); +int openfiles(char *, char *, struct kvmvars *, int); +int getncpu(void); int main(int argc, char **argv) { - extern char *__progname; - int ch, mode, disp, accessmode; + int ch, err, ncpu, cpuid = -1; struct kvmvars kvmvars; char *sys, *kmemf; + const char *p; seteuid(getuid()); kmemf = NULL; sys = NULL; - while ((ch = getopt(argc, argv, "M:N:bhpr")) != -1) { + while ((ch = getopt(argc, argv, "M:N:bc:hpr")) != -1) { switch((char)ch) { case 'M': @@ -95,6 +99,13 @@ main(int argc, char **argv) bflag = 1; break; + case 'c': + cflag = 1; + cpuid = strtonum(optarg, 0, 1024, &p); + if (p) + errx(1, "illegal CPU id %s: %s", optarg, p); + break; + case 'h': hflag = 1; break; @@ -108,9 +119,8 @@ main(int argc, char **argv) break; default: - fprintf(stderr, - "usage: %s [-bhpr] [-M core] [-N system]\n", - __progname); + fprintf(stderr, "usage: %s [-bhpr] " + "[-c cpuid] [-M core] [-N system]\n", __progname); exit(1); } } @@ -127,8 +137,25 @@ main(int argc, char **argv) } } #endif - accessmode = openfiles(sys, kmemf, &kvmvars); - mode = getprof(&kvmvars); + + if (cflag) { + kgmon(sys, kmemf, &kvmvars, cpuid); + } else { + ncpu = getncpu(); + for (cpuid = 0; cpuid < ncpu; cpuid++) + kgmon(sys, kmemf, &kvmvars, cpuid); + } + + return (0); +} + +void +kgmon(char *sys, char *kmemf, struct kvmvars *kvp, int cpuid) +{ + int mode, disp, accessmode; + + accessmode = openfiles(sys, kmemf, kvp, cpuid); + mode = getprof(kvp, cpuid); if (hflag) disp = GMON_PROF_OFF; else if (bflag) @@ -136,23 +163,22 @@ main(int argc, char **argv) else disp = mode; if (pflag) - dumpstate(&kvmvars); + dumpstate(kvp, cpuid); if (rflag) - reset(&kvmvars); + reset(kvp, cpuid); if (accessmode == O_RDWR) - setprof(&kvmvars, disp); - printf("%s: kernel profiling is %s.\n", __progname, - disp == GMON_PROF_OFF ? "off" : "running"); - return (0); + setprof(kvp, cpuid, disp); + printf("%s: kernel profiling is %s for cpu %d.\n", __progname, + disp == GMON_PROF_OFF ? "off" : "running", cpuid); } /* * Check that profiling is enabled and open any ncessary files. */ int -openfiles(char *sys, char *kmemf, struct kvmvars *kvp) +openfiles(char *sys, char *kmemf, struct kvmvars *kvp, int cpuid) { - int mib[3], state, openmode; + int mib[4], state, openmode; size_t size; char errbuf[_POSIX2_LINE_MAX]; @@ -160,14 +186,15 @@ openfiles(char *sys, char *kmemf, struct kvmvars *kvp) mib[0] = CTL_KERN; mib[1] = KERN_PROF; mib[2] = GPROF_STATE; + mib[3] = cpuid; size = sizeof state; - if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) + if (sysctl(mib, 4, &state, &size, NULL, 0) < 0) errx(20, "profiling not defined in kernel."); if (!(bflag || hflag || rflag || (pflag && state == GMON_PROF_ON))) return (O_RDONLY); (void)seteuid(0); - if (sysctl(mib, 3, NULL, NULL, &state, size) >= 0) + if (sysctl(mib, 4, NULL, NULL, &state, size) >= 0) return (O_RDWR); (void)seteuid(getuid()); kern_readonly(state); @@ -216,9 +243,9 @@ kern_readonly(int mode) * Get the state of kernel profiling. */ int -getprof(struct kvmvars *kvp) +getprof(struct kvmvars *kvp, int cpuid) { - int mib[3]; + int mib[4]; size_t size; if (kflag) { @@ -228,8 +255,9 @@ getprof(struct kvmvars *kvp) mib[0] = CTL_KERN; mib[1] = KERN_PROF; mib[2] = GPROF_GMONPARAM; + mib[3] = cpuid; size = sizeof kvp->gpm; - if (sysctl(mib, 3, &kvp->gpm, &size, NULL, 0) < 0) + if (sysctl(mib, 4, &kvp->gpm, &size, NULL, 0) < 0) size = 0; } if (size != sizeof kvp->gpm) @@ -242,10 +270,10 @@ getprof(struct kvmvars *kvp) * Enable or disable kernel profiling according to the state variable. */ void -setprof(struct kvmvars *kvp, int state) +setprof(struct kvmvars *kvp, int cpuid, int state) { struct gmonparam *p = (struct gmonparam *)nl[N_GMONPARAM].n_value; - int mib[3], oldstate; + int mib[4], oldstate; size_t sz; sz = sizeof(state); @@ -253,12 +281,13 @@ setprof(struct kvmvars *kvp, int state) mib[0] = CTL_KERN; mib[1] = KERN_PROF; mib[2] = GPROF_STATE; - if (sysctl(mib, 3, &oldstate, &sz, NULL, 0) < 0) + mib[3] = cpuid; + if (sysctl(mib, 4, &oldstate, &sz, NULL, 0) < 0) goto bad; if (oldstate == state) return; (void)seteuid(0); - if (sysctl(mib, 3, NULL, NULL, &state, sz) >= 0) { + if (sysctl(mib, 4, NULL, NULL, &state, sz) >= 0) { (void)seteuid(getuid()); return; } @@ -275,22 +304,25 @@ bad: * Build the gmon.out file. */ void -dumpstate(struct kvmvars *kvp) +dumpstate(struct kvmvars *kvp, int cpuid) { FILE *fp; struct rawarc rawarc; struct tostruct *tos; u_long frompc; u_short *froms, *tickbuf; - int mib[3]; + int mib[4]; size_t i; struct gmonhdr h; int fromindex, endfrom, toindex; + char buf[16]; - setprof(kvp, GMON_PROF_OFF); - fp = fopen("gmon.out", "w"); + snprintf(buf, sizeof(buf), "gmon-%02d.out", cpuid); + + setprof(kvp, cpuid, GMON_PROF_OFF); + fp = fopen(buf, "w"); if (fp == 0) { - perror("gmon.out"); + perror(buf); return; } @@ -317,8 +349,9 @@ dumpstate(struct kvmvars *kvp) kvp->gpm.kcountsize); } else { mib[2] = GPROF_COUNT; + mib[3] = cpuid; i = kvp->gpm.kcountsize; - if (sysctl(mib, 3, tickbuf, &i, NULL, 0) < 0) + if (sysctl(mib, 4, tickbuf, &i, NULL, 0) < 0) i = 0; } if (i != kvp->gpm.kcountsize) @@ -339,8 +372,9 @@ dumpstate(struct kvmvars *kvp) kvp->gpm.fromssize); } else { mib[2] = GPROF_FROMS; + mib[3] = cpuid; i = kvp->gpm.fromssize; - if (sysctl(mib, 3, froms, &i, NULL, 0) < 0) + if (sysctl(mib, 4, froms, &i, NULL, 0) < 0) i = 0; } if (i != kvp->gpm.fromssize) @@ -354,8 +388,9 @@ dumpstate(struct kvmvars *kvp) kvp->gpm.tossize); } else { mib[2] = GPROF_TOS; + mib[3] = cpuid; i = kvp->gpm.tossize; - if (sysctl(mib, 3, tos, &i, NULL, 0) < 0) + if (sysctl(mib, 4, tos, &i, NULL, 0) < 0) i = 0; } if (i != kvp->gpm.tossize) @@ -415,13 +450,13 @@ getprofhz(struct kvmvars *kvp) * Reset the kernel profiling date structures. */ void -reset(struct kvmvars *kvp) +reset(struct kvmvars *kvp, int cpuid) { char *zbuf; u_long biggest; - int mib[3]; + int mib[4]; - setprof(kvp, GMON_PROF_OFF); + setprof(kvp, cpuid, GMON_PROF_OFF); biggest = kvp->gpm.kcountsize; if (kvp->gpm.fromssize > biggest) @@ -447,14 +482,31 @@ reset(struct kvmvars *kvp) mib[0] = CTL_KERN; mib[1] = KERN_PROF; mib[2] = GPROF_COUNT; - if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.kcountsize) < 0) + mib[3] = cpuid; + if (sysctl(mib, 4, NULL, NULL, zbuf, kvp->gpm.kcountsize) < 0) err(13, "tickbuf zero"); mib[2] = GPROF_FROMS; - if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.fromssize) < 0) + if (sysctl(mib, 4, NULL, NULL, zbuf, kvp->gpm.fromssize) < 0) err(14, "froms zero"); mib[2] = GPROF_TOS; - if (sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.tossize) < 0) + if (sysctl(mib, 4, NULL, NULL, zbuf, kvp->gpm.tossize) < 0) err(15, "tos zero"); (void)seteuid(getuid()); free(zbuf); } + +int +getncpu(void) +{ + int mib[2] = { CTL_HW, HW_NCPU }; + size_t size; + int ncpu; + + size = sizeof(ncpu); + if (sysctl(mib, 2, &ncpu, &size, NULL, 0) < 0) { + warnx("cannot read hw.ncpu"); + return (1); + } + + return (ncpu); +} |