Date: Thu, 01 Jul 2010 16:46:41 -0700 From: Sean Bruno <seanbru@yahoo-inc.com> To: "freebsd-hackers@freebsd.org" <freebsd-hackers@freebsd.org> Subject: [Patch] Kgmon/Gprof On/Off Switch Message-ID: <1278028001.2438.113.camel@localhost.localdomain>
next in thread | raw e-mail | index | archive | help
--=-Wh2r+zOr01orih2mjubK
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit
Found this lying around the Yahoo tree this week. Basically it allows
you to activate, reset and deactivate profiling with the '-f" flag.
Kind of nice to have if you want the ability to turn on profiling for
debugging live systems.
Applies cleanly to head at the moment.
Sean
--=-Wh2r+zOr01orih2mjubK
Content-Disposition: attachment; filename="kgmon_gprof_dynamic.diff"
Content-Type: text/x-patch; name="kgmon_gprof_dynamic.diff"; charset="UTF-8"
Content-Transfer-Encoding: 7bit
Index: usr.sbin/kgmon/kgmon.8
===================================================================
--- usr.sbin/kgmon/kgmon.8 (revision 209631)
+++ usr.sbin/kgmon/kgmon.8 (working copy)
@@ -70,6 +70,8 @@
Dump the contents of the profile buffers into a
.Pa gmon.out
file.
+.It Fl f
+Free profiling buffer. Also stops profiling.
.It Fl r
Reset all the profile buffers.
If the
Index: usr.sbin/kgmon/kgmon.c
===================================================================
--- usr.sbin/kgmon/kgmon.c (revision 209631)
+++ usr.sbin/kgmon/kgmon.c (working copy)
@@ -72,7 +72,7 @@
struct gmonparam gpm;
};
-int Bflag, bflag, hflag, kflag, rflag, pflag;
+int Bflag, bflag, hflag, kflag, rflag, pflag, fflag;
int debug = 0;
int getprof(struct kvmvars *);
int getprofhz(struct kvmvars *);
@@ -82,6 +82,7 @@
void dumpstate(struct kvmvars *kvp);
void reset(struct kvmvars *kvp);
static void usage(void);
+void freebuf(struct kvmvars *kvp);
int
main(int argc, char **argv)
@@ -93,7 +94,7 @@
seteuid(getuid());
kmemf = NULL;
system = NULL;
- while ((ch = getopt(argc, argv, "M:N:Bbhpr")) != -1) {
+ while ((ch = getopt(argc, argv, "M:N:Bbfhpr")) != -1) {
switch((char)ch) {
case 'M':
@@ -113,6 +114,10 @@
bflag = 1;
break;
+ case 'f':
+ fflag = 1;
+ break;
+
case 'h':
hflag = 1;
break;
@@ -158,6 +163,10 @@
dumpstate(&kvmvars);
if (rflag)
reset(&kvmvars);
+ if (fflag) {
+ freebuf(&kvmvars);
+ disp = GMON_PROF_OFF;
+ }
if (accessmode == O_RDWR)
setprof(&kvmvars, disp);
(void)fprintf(stdout, "kgmon: kernel profiling is %s.\n",
@@ -403,36 +412,44 @@
/*
* Write out the arc info.
*/
- if ((froms = (u_short *)malloc(kvp->gpm.fromssize)) == NULL)
- errx(8, "cannot allocate froms space");
- if (kflag) {
- i = kvm_read(kvp->kd, (u_long)kvp->gpm.froms, (void *)froms,
- kvp->gpm.fromssize);
- } else {
- mib[2] = GPROF_FROMS;
- i = kvp->gpm.fromssize;
- if (sysctl(mib, 3, froms, &i, NULL, 0) < 0)
- i = 0;
- }
- if (i != kvp->gpm.fromssize)
- errx(9, "read froms: read %lu, got %ld: %s",
- kvp->gpm.fromssize, (long)i,
- kflag ? kvm_geterr(kvp->kd) : strerror(errno));
- if ((tos = (struct tostruct *)malloc(kvp->gpm.tossize)) == NULL)
- errx(10, "cannot allocate tos space");
- if (kflag) {
- i = kvm_read(kvp->kd, (u_long)kvp->gpm.tos, (void *)tos,
- kvp->gpm.tossize);
- } else {
- mib[2] = GPROF_TOS;
- i = kvp->gpm.tossize;
- if (sysctl(mib, 3, tos, &i, NULL, 0) < 0)
- i = 0;
- }
- if (i != kvp->gpm.tossize)
- errx(11, "read tos: read %lu, got %ld: %s",
- kvp->gpm.tossize, (long)i,
- kflag ? kvm_geterr(kvp->kd) : strerror(errno));
+ if (kvp->gpm.fromssize > 0) {
+ if ((froms = (u_short *)malloc(kvp->gpm.fromssize)) == NULL)
+ errx(8, "cannot allocate froms space");
+ if (kflag) {
+ i = kvm_read(kvp->kd, (u_long)kvp->gpm.froms,
+ (void *)froms,
+ kvp->gpm.fromssize);
+ } else {
+ mib[2] = GPROF_FROMS;
+ i = kvp->gpm.fromssize;
+ if (sysctl(mib, 3, froms, &i, NULL, 0) < 0)
+ i = 0;
+ }
+ if (i != kvp->gpm.fromssize)
+ errx(9, "read froms: read %lu, got %ld: %s",
+ kvp->gpm.fromssize, (long)i,
+ kflag ? kvm_geterr(kvp->kd) : strerror(errno));
+ }
+ if (kvp->gpm.tossize > 0) {
+ if ((tos = (struct tostruct *)malloc(kvp->gpm.tossize)) ==
+ NULL)
+ errx(10, "cannot allocate tos space");
+ if (kflag) {
+ i = kvm_read(kvp->kd, (u_long)kvp->gpm.tos,
+ (void *)tos,
+ kvp->gpm.tossize);
+ } else {
+ mib[2] = GPROF_TOS;
+ i = kvp->gpm.tossize;
+ if (sysctl(mib, 3, tos, &i, NULL, 0) < 0)
+ i = 0;
+ }
+ if (i != kvp->gpm.tossize)
+ errx(11, "read tos: read %lu, got %ld: %s",
+ kvp->gpm.tossize, (long)i,
+ kflag ? kvm_geterr(kvp->kd) : strerror(errno));
+ }
+
if (debug)
warnx("lowpc 0x%lx, textsize 0x%lx",
(unsigned long)kvp->gpm.lowpc, kvp->gpm.textsize);
@@ -509,11 +526,13 @@
if (kvm_write(kvp->kd, (u_long)kvp->gpm.kcount, zbuf,
kvp->gpm.kcountsize) != kvp->gpm.kcountsize)
errx(13, "tickbuf zero: %s", kvm_geterr(kvp->kd));
- if (kvm_write(kvp->kd, (u_long)kvp->gpm.froms, zbuf,
- kvp->gpm.fromssize) != kvp->gpm.fromssize)
+ if (kvp->gpm.fromssize > 0 &&
+ kvm_write(kvp->kd, (u_long)kvp->gpm.froms, zbuf,
+ kvp->gpm.fromssize) != kvp->gpm.fromssize)
errx(14, "froms zero: %s", kvm_geterr(kvp->kd));
- if (kvm_write(kvp->kd, (u_long)kvp->gpm.tos, zbuf,
- kvp->gpm.tossize) != kvp->gpm.tossize)
+ if (kvp->gpm.tossize > 0 &&
+ kvm_write(kvp->kd, (u_long)kvp->gpm.tos, zbuf,
+ kvp->gpm.tossize) != kvp->gpm.tossize)
errx(15, "tos zero: %s", kvm_geterr(kvp->kd));
return;
}
@@ -524,11 +543,33 @@
if (sysctl(mib, 3, 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 (kvp->gpm.fromssize > 0 &&
+ sysctl(mib, 3, 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)
- err(15, "tos zero");
+ if (kvp->gpm.tossize > 0 &&
+ sysctl(mib, 3, NULL, NULL, zbuf, kvp->gpm.tossize) < 0)
(void)seteuid(getuid());
free(zbuf);
}
+
+/*
+ * Free the kernel profiling date structures.
+ */
+void
+freebuf(kvp)
+ struct kvmvars *kvp;
+{
+ int mib[3];
+
+ setprof(kvp, GMON_PROF_OFF);
+ if (kflag)
+ return;
+ (void)seteuid(0);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROF;
+ mib[2] = GPROF_FREEBUF;
+ if (sysctl(mib, 3, NULL, 0, NULL, 0) < 0)
+ err(16, "Freeing profiling buffer failed");
+ (void)seteuid(getuid());
+}
Index: sys/kern/kern_clock.c
===================================================================
--- sys/kern/kern_clock.c (revision 209631)
+++ sys/kern/kern_clock.c (working copy)
@@ -68,9 +68,7 @@
#include <sys/limits.h>
#include <sys/timetc.h>
-#ifdef GPROF
#include <sys/gmon.h>
-#endif
#ifdef HWPMC_HOOKS
#include <sys/pmckern.h>
@@ -714,10 +712,8 @@
profclock(int usermode, uintfptr_t pc)
{
struct thread *td;
-#ifdef GPROF
struct gmonparam *g;
uintfptr_t i;
-#endif
td = curthread;
if (usermode) {
@@ -730,7 +726,6 @@
if (td->td_proc->p_flag & P_PROFIL)
addupc_intr(td, pc, 1);
}
-#ifdef GPROF
else {
/*
* Kernel statistics are just like addupc_intr, only easier.
@@ -743,7 +738,6 @@
}
}
}
-#endif
}
/*
Index: sys/kern/subr_prof.c
===================================================================
--- sys/kern/subr_prof.c (revision 209631)
+++ sys/kern/subr_prof.c (working copy)
@@ -44,7 +44,6 @@
#include <machine/cpu.h>
-#ifdef GPROF
#include <sys/malloc.h>
#include <sys/gmon.h>
#undef MCOUNT
@@ -136,7 +135,46 @@
free(cp, M_GPROF);
}
+#ifndef GPROF
+/* Allocate kcount buffer and initialize state */
+static int
+prof_alloc_kcountbuf(void)
+{
+ char *cp;
+ struct gmonparam *p = &_gmonparam;
+ int error = 0;
+
+ mtx_lock(&Giant);
+ if (p->kcount == NULL) {
+ cp = (char *)malloc(p->kcountsize, M_GPROF, M_NOWAIT);
+ if (cp == 0) {
+ printf("No memory for profiling.\n");
+ error = ENOMEM;
+ goto out;
+ }
+ bzero(cp, p->kcountsize);
+ p->kcount = (HISTCOUNTER *)cp;
+ }
+out:
+ mtx_unlock(&Giant);
+ return error;
+}
+
static void
+prof_free_kcountbuf(void)
+{
+ struct gmonparam *p = &_gmonparam;
+
+ mtx_lock(&Giant);
+ if (p->kcount != NULL) {
+ free(p->kcount, M_GPROF);
+ p->kcount = (HISTCOUNTER *)NULL;
+ }
+ mtx_unlock(&Giant);
+}
+#endif
+
+static void
kmstartup(dummy)
void *dummy;
{
@@ -152,6 +190,7 @@
int nullfunc_loop_profiled_time;
uintfptr_t tmp_addr;
#endif
+ int bufsize;
/*
* Round lowpc and highpc to multiples of the density we're using
@@ -164,6 +203,7 @@
p->textsize, (uintmax_t)p->lowpc, (uintmax_t)p->highpc);
p->kcountsize = p->textsize / HISTFRACTION;
p->hashfraction = HASHFRACTION;
+#ifdef GPROF
p->fromssize = p->textsize / HASHFRACTION;
p->tolimit = p->textsize * ARCDENSITY / 100;
if (p->tolimit < MINARCS)
@@ -171,13 +211,30 @@
else if (p->tolimit > MAXARCS)
p->tolimit = MAXARCS;
p->tossize = p->tolimit * sizeof(struct tostruct);
- cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize,
- M_GPROF, M_WAITOK | M_ZERO);
+ bufsize = p->kcountsize + p->fromssize + p->tossize;
+#else
+ p->fromssize = 0;
+ p->tolimit = 0;
+ p->tossize = 0;
+ bufsize = 0;
+ p->kcount = (HISTCOUNTER *)NULL;
+#endif
+ cp = NULL;
+ if (bufsize > 0)
+ cp = (char *)malloc(bufsize, M_GPROF, M_WAITOK | M_ZERO);
+#ifdef GPROF
p->tos = (struct tostruct *)cp;
cp += p->tossize;
+#else
+ p->tos = (struct tostruct *)NULL;
+#endif
p->kcount = (HISTCOUNTER *)cp;
cp += p->kcountsize;
+#ifdef GPROF
p->froms = (u_short *)cp;
+#else
+ p->froms = (u_short *)NULL;
+#endif
p->histcounter_type = FUNCTION_ALIGNMENT / HISTFRACTION * NBBY;
#ifdef GUPROF
@@ -351,6 +408,12 @@
} else if (state == GMON_PROF_ON) {
gp->state = GMON_PROF_OFF;
stopguprof(gp);
+#ifndef GUPROF
+ /* Allocate kcount buffer and initialize state */
+ error = prof_alloc_kcountbuf();
+ if (error)
+ return error;
+#endif
gp->profrate = profhz;
PROC_LOCK(&proc0);
startprofclock(&proc0);
@@ -368,15 +431,24 @@
} else if (state != gp->state)
return (EINVAL);
return (0);
+#ifndef GPROF
+ if (gp->state != GMON_PROF_OFF)
+ return EINVAL;
+ /* Free kcount buffer */
+ prof_free_kcountbuf();
+#endif
+ return 0;
case GPROF_COUNT:
return (sysctl_handle_opaque(oidp,
gp->kcount, gp->kcountsize, req));
+#ifdef GPROF
case GPROF_FROMS:
return (sysctl_handle_opaque(oidp,
gp->froms, gp->fromssize, req));
case GPROF_TOS:
return (sysctl_handle_opaque(oidp,
gp->tos, gp->tossize, req));
+#endif
case GPROF_GMONPARAM:
return (sysctl_handle_opaque(oidp, gp, sizeof *gp, req));
default:
@@ -386,7 +458,6 @@
}
SYSCTL_NODE(_kern, KERN_PROF, prof, CTLFLAG_RW, sysctl_kern_prof, "");
-#endif /* GPROF */
/*
* Profiling system call.
Index: sys/sys/gmon.h
===================================================================
--- sys/sys/gmon.h (revision 209631)
+++ sys/sys/gmon.h (working copy)
@@ -197,6 +197,7 @@
#define GPROF_FROMS 2 /* struct: from location hash bucket */
#define GPROF_TOS 3 /* struct: destination/count structure */
#define GPROF_GMONPARAM 4 /* struct: profiling parameters (see above) */
+#define GPROF_FREEBUF 5 /* int: free flat profiling buffer */
#ifdef _KERNEL
--=-Wh2r+zOr01orih2mjubK--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1278028001.2438.113.camel>
