Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 06 Jul 2010 14:08:21 -0700
From:      Sean Bruno <seanbru@yahoo-inc.com>
To:        "freebsd-hackers@freebsd.org" <freebsd-hackers@freebsd.org>
Cc:        bde <bde@freebsd.org>
Subject:   Re: [Patch] Kgmon/Gprof On/Off Switch
Message-ID:  <1278450501.6494.0.camel@localhost.localdomain>
In-Reply-To: <1278028001.2438.113.camel@localhost.localdomain>
References:  <1278028001.2438.113.camel@localhost.localdomain>

next in thread | previous in thread | raw e-mail | index | archive | help

--=-bd7m8DoUYtvZhXKeUTe8
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: 7bit

On Thu, 2010-07-01 at 16:46 -0700, Sean Bruno wrote:
> 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

Updated with proper man page formatting.

Sean



--=-bd7m8DoUYtvZhXKeUTe8
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 209745)
+++ usr.sbin/kgmon/kgmon.8	(working copy)
@@ -70,6 +70,9 @@
 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 209745)
+++ 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 209745)
+++ 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 209745)
+++ 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 209745)
+++ 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
 

--=-bd7m8DoUYtvZhXKeUTe8--




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1278450501.6494.0.camel>