From owner-freebsd-hackers@FreeBSD.ORG Tue Jul 6 21:08:35 2010 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 4B65B106566C; Tue, 6 Jul 2010 21:08:35 +0000 (UTC) (envelope-from seanbru@yahoo-inc.com) Received: from mrout3.yahoo.com (mrout3.yahoo.com [216.145.54.173]) by mx1.freebsd.org (Postfix) with ESMTP id 31BC38FC16; Tue, 6 Jul 2010 21:08:34 +0000 (UTC) Received: from [127.0.0.1] (cheese.corp.yahoo.com [216.145.50.99]) by mrout3.yahoo.com (8.13.8/8.13.8/y.out) with ESMTP id o66L8LLp070923; Tue, 6 Jul 2010 14:08:21 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; s=serpent; d=yahoo-inc.com; c=nofws; q=dns; h=subject:from:reply-to:to:cc:in-reply-to:references: content-type:date:message-id:mime-version:x-mailer; b=Xj2bRrZHftzqg2qa5qAFB4wSLb55PxZrR6b7ji+w/rCumHZmrdoxk7t9YrIbcTT8 From: Sean Bruno To: "freebsd-hackers@freebsd.org" In-Reply-To: <1278028001.2438.113.camel@localhost.localdomain> References: <1278028001.2438.113.camel@localhost.localdomain> Content-Type: multipart/mixed; boundary="=-bd7m8DoUYtvZhXKeUTe8" Date: Tue, 06 Jul 2010 14:08:21 -0700 Message-ID: <1278450501.6494.0.camel@localhost.localdomain> Mime-Version: 1.0 X-Mailer: Evolution 2.28.3 (2.28.3-1.fc12) Cc: bde Subject: Re: [Patch] Kgmon/Gprof On/Off Switch X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: "sbruno@freebsd.org" List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 06 Jul 2010 21:08:35 -0000 --=-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 #include -#ifdef GPROF #include -#endif #ifdef HWPMC_HOOKS #include @@ -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 -#ifdef GPROF #include #include #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--