summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libc/gmon/mcount.c22
-rw-r--r--sys/arch/alpha/include/cpu.h5
-rw-r--r--sys/arch/amd64/include/cpu.h5
-rw-r--r--sys/arch/arm/include/cpu.h5
-rw-r--r--sys/arch/hppa/include/cpu.h5
-rw-r--r--sys/arch/hppa64/include/cpu.h5
-rw-r--r--sys/arch/i386/include/cpu.h5
-rw-r--r--sys/arch/m68k/include/cpu.h5
-rw-r--r--sys/arch/m88k/include/cpu.h5
-rw-r--r--sys/arch/mips64/include/cpu.h5
-rw-r--r--sys/arch/powerpc/include/cpu.h5
-rw-r--r--sys/arch/sh/include/cpu.h5
-rw-r--r--sys/arch/sparc64/include/cpu.h5
-rw-r--r--sys/arch/vax/include/cpu.h5
-rw-r--r--sys/kern/kern_clock.c6
-rw-r--r--sys/kern/subr_prof.c107
-rw-r--r--sys/lib/libkern/mcount.c24
-rw-r--r--sys/sys/gmon.h6
-rw-r--r--usr.sbin/kgmon/kgmon.814
-rw-r--r--usr.sbin/kgmon/kgmon.c144
20 files changed, 268 insertions, 120 deletions
diff --git a/lib/libc/gmon/mcount.c b/lib/libc/gmon/mcount.c
index e7619c7599b..942d8c1887f 100644
--- a/lib/libc/gmon/mcount.c
+++ b/lib/libc/gmon/mcount.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mcount.c,v 1.13 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: mcount.c,v 1.14 2013/03/12 09:37:16 mpi Exp $ */
/*-
* Copyright (c) 1983, 1992, 1993
* The Regents of the University of California. All rights reserved.
@@ -41,10 +41,6 @@
* _mcount updates data structures that represent traversals of the
* program's call graph edges. frompc and selfpc are the return
* address and function address that represents the given call graph edge.
- *
- * Note: the original BSD code used the same variable (frompcindex) for
- * both frompcindex and frompc. Any reasonable, modern compiler will
- * perform this optimization.
*/
_MCOUNT_DECL(u_long frompc, u_long selfpc) __used;
/* _mcount; may be static, inline, etc */
@@ -56,9 +52,21 @@ _MCOUNT_DECL(u_long frompc, u_long selfpc)
long toindex;
#ifdef _KERNEL
int s;
-#endif
+ /*
+ * Do not profile execution if memory for the current CPU
+ * desciptor and profiling buffers has not yet been allocated
+ * or if the CPU we are running on has not yet set its trap
+ * handler.
+ */
+ if (gmoninit == 0)
+ return;
+
+ if ((p = curcpu()->ci_gmon) == NULL)
+ return;
+#else
p = &_gmonparam;
+#endif
/*
* check that we are profiling
* and that we aren't recursively invoked.
@@ -171,10 +179,8 @@ overflow:
return;
}
-#ifndef lint
/*
* Actual definition of mcount function. Defined in <machine/profile.h>,
* which is included by <sys/gmon.h>.
*/
MCOUNT
-#endif
diff --git a/sys/arch/alpha/include/cpu.h b/sys/arch/alpha/include/cpu.h
index 6ce34749606..d43c510d202 100644
--- a/sys/arch/alpha/include/cpu.h
+++ b/sys/arch/alpha/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.48 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.49 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.45 2000/08/21 02:03:12 thorpej Exp $ */
/*-
@@ -203,6 +203,9 @@ struct cpu_info {
u_long ci_ipis; /* interprocessor interrupts pending */
#endif
u_int32_t ci_randseed;
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
#define CPUF_PRIMARY 0x01 /* CPU is primary CPU */
diff --git a/sys/arch/amd64/include/cpu.h b/sys/arch/amd64/include/cpu.h
index 61e9889d71f..c9977c895bb 100644
--- a/sys/arch/amd64/include/cpu.h
+++ b/sys/arch/amd64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.78 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.79 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.1 2003/04/26 18:39:39 fvdl Exp $ */
/*-
@@ -128,6 +128,9 @@ struct cpu_info {
struct ksensordev ci_sensordev;
struct ksensor ci_sensor;
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
#define CPUF_BSP 0x0001 /* CPU is the original BSP */
diff --git a/sys/arch/arm/include/cpu.h b/sys/arch/arm/include/cpu.h
index 7e1ca74122c..5da7d8333bc 100644
--- a/sys/arch/arm/include/cpu.h
+++ b/sys/arch/arm/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.33 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.34 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.34 2003/06/23 11:01:08 martin Exp $ */
/*
@@ -198,6 +198,9 @@ struct cpu_info {
uint32_t ci_cpl;
uint32_t ci_ipending;
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
#ifndef MULTIPROCESSOR
diff --git a/sys/arch/hppa/include/cpu.h b/sys/arch/hppa/include/cpu.h
index b477fc6b15a..536ae85f1fb 100644
--- a/sys/arch/hppa/include/cpu.h
+++ b/sys/arch/hppa/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.83 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.84 2013/03/12 09:37:16 mpi Exp $ */
/*
* Copyright (c) 2000-2004 Michael Shalayeff
@@ -103,6 +103,9 @@ struct cpu_info {
#ifdef DIAGNOSTIC
int ci_mutex_level;
#endif
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
} __attribute__((__aligned__(64)));
#define CPUF_RUNNING 0x0001 /* CPU is running. */
diff --git a/sys/arch/hppa64/include/cpu.h b/sys/arch/hppa64/include/cpu.h
index 509a8a21b14..193a1bc7588 100644
--- a/sys/arch/hppa64/include/cpu.h
+++ b/sys/arch/hppa64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.30 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.31 2013/03/12 09:37:16 mpi Exp $ */
/*
* Copyright (c) 2005 Michael Shalayeff
@@ -109,6 +109,9 @@ struct cpu_info {
#ifdef DIAGNOSTIC
int ci_mutex_level;
#endif
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
struct cpu_info *curcpu(void);
diff --git a/sys/arch/i386/include/cpu.h b/sys/arch/i386/include/cpu.h
index 2fe58c1d2a5..99a7448a763 100644
--- a/sys/arch/i386/include/cpu.h
+++ b/sys/arch/i386/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.127 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.128 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.35 1996/05/05 19:29:26 christos Exp $ */
/*-
@@ -148,6 +148,9 @@ struct cpu_info {
struct ksensordev ci_sensordev;
struct ksensor ci_sensor;
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
/*
diff --git a/sys/arch/m68k/include/cpu.h b/sys/arch/m68k/include/cpu.h
index bac5eedc662..02c99c399a7 100644
--- a/sys/arch/m68k/include/cpu.h
+++ b/sys/arch/m68k/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.28 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.29 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.3 1997/02/02 06:56:57 thorpej Exp $ */
/*
@@ -59,6 +59,9 @@ struct cpu_info {
#ifdef DIAGNOSTIC
int ci_mutex_level;
#endif
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
extern struct cpu_info cpu_info_store;
diff --git a/sys/arch/m88k/include/cpu.h b/sys/arch/m88k/include/cpu.h
index f5055a5463e..a9c7089d92d 100644
--- a/sys/arch/m88k/include/cpu.h
+++ b/sys/arch/m88k/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.58 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.59 2013/03/12 09:37:16 mpi Exp $ */
/*
* Copyright (c) 1996 Nivas Madhur
* Copyright (c) 1992, 1993
@@ -172,6 +172,9 @@ struct cpu_info {
#ifdef DIAGNOSTIC
int ci_mutex_level;
#endif
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
extern cpuid_t master_cpu;
diff --git a/sys/arch/mips64/include/cpu.h b/sys/arch/mips64/include/cpu.h
index c7ba15de925..7c036339265 100644
--- a/sys/arch/mips64/include/cpu.h
+++ b/sys/arch/mips64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.93 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.94 2013/03/12 09:37:16 mpi Exp $ */
/*-
* Copyright (c) 1992, 1993
@@ -198,6 +198,9 @@ struct cpu_info {
#ifdef DIAGNOSTIC
int ci_mutex_level;
#endif
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
#define CPUF_PRIMARY 0x01 /* CPU is primary CPU */
diff --git a/sys/arch/powerpc/include/cpu.h b/sys/arch/powerpc/include/cpu.h
index a9561d6e820..3f47bdc7953 100644
--- a/sys/arch/powerpc/include/cpu.h
+++ b/sys/arch/powerpc/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.50 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.51 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.1 1996/09/30 16:34:21 ws Exp $ */
/*
@@ -85,6 +85,9 @@ struct cpu_info {
#ifdef DIAGNOSTIC
int ci_mutex_level;
#endif
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
static __inline struct cpu_info *
diff --git a/sys/arch/sh/include/cpu.h b/sys/arch/sh/include/cpu.h
index e313d701d22..31959429bd7 100644
--- a/sys/arch/sh/include/cpu.h
+++ b/sys/arch/sh/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.24 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.25 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.41 2006/01/21 04:24:12 uwe Exp $ */
/*-
@@ -65,6 +65,9 @@ struct cpu_info {
#ifdef DIAGNOSTIC
int ci_mutex_level;
#endif
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
extern struct cpu_info cpu_info_store;
diff --git a/sys/arch/sparc64/include/cpu.h b/sys/arch/sparc64/include/cpu.h
index 7b5e4fee0a0..e1bca2f7fa1 100644
--- a/sys/arch/sparc64/include/cpu.h
+++ b/sys/arch/sparc64/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.81 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.82 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.28 2001/06/14 22:56:58 thorpej Exp $ */
/*
@@ -156,6 +156,9 @@ struct cpu_info {
#ifdef DIAGNOSTIC
int ci_mutex_level;
#endif
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
#define CPUF_RUNNING 0x0001 /* CPU is running */
diff --git a/sys/arch/vax/include/cpu.h b/sys/arch/vax/include/cpu.h
index 509556a3358..6284fd9e230 100644
--- a/sys/arch/vax/include/cpu.h
+++ b/sys/arch/vax/include/cpu.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.44 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: cpu.h,v 1.45 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: cpu.h,v 1.41 1999/10/21 20:01:36 ragge Exp $ */
/*
@@ -55,6 +55,9 @@ struct cpu_info {
#ifdef DIAGNOSTIC
int ci_mutex_level;
#endif
+#ifdef GPROF
+ struct gmonparam *ci_gmon;
+#endif
};
extern struct cpu_info cpu_info_store;
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c
index d7d51646c2c..7aec79d3e69 100644
--- a/sys/kern/kern_clock.c
+++ b/sys/kern/kern_clock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_clock.c,v 1.78 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: kern_clock.c,v 1.79 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: kern_clock.c,v 1.34 1996/06/09 04:51:03 briggs Exp $ */
/*-
@@ -421,8 +421,8 @@ statclock(struct clockframe *frame)
/*
* Kernel statistics are just like addupc_intr, only easier.
*/
- g = &_gmonparam;
- if (g->state == GMON_PROF_ON) {
+ g = ci->ci_gmon;
+ if (g != NULL && g->state == GMON_PROF_ON) {
i = CLKF_PC(frame) - g->lowpc;
if (i < g->textsize) {
i /= HISTFRACTION * sizeof(*g->kcount);
diff --git a/sys/kern/subr_prof.c b/sys/kern/subr_prof.c
index 3786cb11df8..5289ab7f8b4 100644
--- a/sys/kern/subr_prof.c
+++ b/sys/kern/subr_prof.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_prof.c,v 1.23 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: subr_prof.c,v 1.24 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: subr_prof.c,v 1.12 1996/04/22 01:38:50 christos Exp $ */
/*-
@@ -49,49 +49,72 @@
#include <uvm/uvm_extern.h>
/*
- * Froms is actually a bunch of unsigned shorts indexing tos
+ * Flag to prevent CPUs from executing the mcount() monitor function
+ * until we're sure they are in a sane state.
*/
-struct gmonparam _gmonparam = { GMON_PROF_OFF };
+int gmoninit = 0;
extern char etext[];
-
void
kmstartup(void)
{
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+ struct gmonparam *p;
+ u_long lowpc, highpc, textsize;
+ u_long kcountsize, fromssize, tossize;
+ long tolimit;
char *cp;
- struct gmonparam *p = &_gmonparam;
int size;
/*
* Round lowpc and highpc to multiples of the density we're using
* so the rest of the scaling (here and in gprof) stays in ints.
*/
- p->lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
- p->highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
- p->textsize = p->highpc - p->lowpc;
+ lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
+ highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
+ textsize = highpc - lowpc;
printf("Profiling kernel, textsize=%ld [%lx..%lx]\n",
- p->textsize, p->lowpc, p->highpc);
- p->kcountsize = p->textsize / HISTFRACTION;
- p->hashfraction = HASHFRACTION;
- p->fromssize = p->textsize / HASHFRACTION;
- p->tolimit = p->textsize * ARCDENSITY / 100;
- if (p->tolimit < MINARCS)
- p->tolimit = MINARCS;
- else if (p->tolimit > MAXARCS)
- p->tolimit = MAXARCS;
- p->tossize = p->tolimit * sizeof(struct tostruct);
- size = p->kcountsize + p->fromssize + p->tossize;
- cp = (char *)uvm_km_zalloc(kernel_map, round_page(size));
- if (cp == 0) {
- printf("No memory for profiling.\n");
- return;
+ textsize, lowpc, highpc);
+ kcountsize = textsize / HISTFRACTION;
+ fromssize = textsize / HASHFRACTION;
+ tolimit = textsize * ARCDENSITY / 100;
+ if (tolimit < MINARCS)
+ tolimit = MINARCS;
+ else if (tolimit > MAXARCS)
+ tolimit = MAXARCS;
+ tossize = tolimit * sizeof(struct tostruct);
+ size = sizeof(*p) + kcountsize + fromssize + tossize;
+
+ /* Allocate and initialize one profiling buffer per CPU. */
+ CPU_INFO_FOREACH(cii, ci) {
+ cp = km_alloc(round_page(size), &kv_any, &kp_zero, &kd_nowait);
+ if (cp == NULL) {
+ printf("No memory for profiling.\n");
+ return;
+ }
+
+ p = (struct gmonparam *)cp;
+ cp += sizeof(*p);
+ p->tos = (struct tostruct *)cp;
+ cp += tossize;
+ p->kcount = (u_short *)cp;
+ cp += kcountsize;
+ p->froms = (u_short *)cp;
+
+ p->state = GMON_PROF_OFF;
+ p->lowpc = lowpc;
+ p->highpc = highpc;
+ p->textsize = textsize;
+ p->hashfraction = HASHFRACTION;
+ p->kcountsize = kcountsize;
+ p->fromssize = fromssize;
+ p->tolimit = tolimit;
+ p->tossize = tossize;
+
+ ci->ci_gmon = p;
}
- p->tos = (struct tostruct *)cp;
- cp += p->tossize;
- p->kcount = (u_short *)cp;
- cp += p->kcountsize;
- p->froms = (u_short *)cp;
}
/*
@@ -101,14 +124,32 @@ int
sysctl_doprof(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
size_t newlen)
{
- struct gmonparam *gp = &_gmonparam;
- int error;
+ CPU_INFO_ITERATOR cii;
+ struct cpu_info *ci;
+ struct gmonparam *gp = NULL;
+ int error, cpuid, op;
- /* all sysctl names at this level are terminal */
- if (namelen != 1)
+ /* all sysctl names at this level are name and field */
+ if (namelen != 2)
return (ENOTDIR); /* overloaded */
- switch (name[0]) {
+ op = name[0];
+ cpuid = name[1];
+
+ CPU_INFO_FOREACH(cii, ci) {
+ if (cpuid == CPU_INFO_UNIT(ci)) {
+ gp = ci->ci_gmon;
+ break;
+ }
+ }
+
+ if (gp == NULL)
+ return (EOPNOTSUPP);
+
+ /* Assume that if we're here it is safe to execute profiling. */
+ gmoninit = 1;
+
+ switch (op) {
case GPROF_STATE:
error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
if (error)
diff --git a/sys/lib/libkern/mcount.c b/sys/lib/libkern/mcount.c
index c66314cefe0..684ddadb9aa 100644
--- a/sys/lib/libkern/mcount.c
+++ b/sys/lib/libkern/mcount.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mcount.c,v 1.12 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: mcount.c,v 1.13 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: mcount.c,v 1.3.6.1 1996/06/12 04:23:01 cgd Exp $ */
/*-
@@ -43,13 +43,10 @@
* _mcount updates data structures that represent traversals of the
* program's call graph edges. frompc and selfpc are the return
* address and function address that represents the given call graph edge.
- *
- * Note: the original BSD code used the same variable (frompcindex) for
- * both frompcindex and frompc. Any reasonable, modern compiler will
- * perform this optimization.
*/
_MCOUNT_DECL(u_long frompc, u_long selfpc) __used;
-_MCOUNT_DECL(u_long frompc, u_long selfpc) /* _mcount; may be static, inline, etc */
+/* _mcount; may be static, inline, etc */
+_MCOUNT_DECL(u_long frompc, u_long selfpc)
{
u_short *frompcindex;
struct tostruct *top, *prevtop;
@@ -57,9 +54,21 @@ _MCOUNT_DECL(u_long frompc, u_long selfpc) /* _mcount; may be static, inline, et
long toindex;
#ifdef _KERNEL
int s;
-#endif
+ /*
+ * Do not profile execution if memory for the current CPU
+ * desciptor and profiling buffers has not yet been allocated
+ * or if the CPU we are running on has not yet set its trap
+ * handler.
+ */
+ if (gmoninit == 0)
+ return;
+
+ if ((p = curcpu()->ci_gmon) == NULL)
+ return;
+#else
p = &_gmonparam;
+#endif
/*
* check that we are profiling
* and that we aren't recursively invoked.
@@ -156,7 +165,6 @@ _MCOUNT_DECL(u_long frompc, u_long selfpc) /* _mcount; may be static, inline, et
*frompcindex = toindex;
goto done;
}
-
}
done:
#ifdef _KERNEL
diff --git a/sys/sys/gmon.h b/sys/sys/gmon.h
index 192b7c7ebbc..303d756a327 100644
--- a/sys/sys/gmon.h
+++ b/sys/sys/gmon.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: gmon.h,v 1.6 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: gmon.h,v 1.7 2013/03/12 09:37:16 mpi Exp $ */
/* $NetBSD: gmon.h,v 1.5 1996/04/09 20:55:30 cgd Exp $ */
/*-
@@ -137,7 +137,11 @@ struct gmonparam {
u_long textsize;
u_long hashfraction;
};
+#ifdef _KERNEL
+extern int gmoninit; /* Is the kernel ready for beeing profiled? */
+#else
extern struct gmonparam _gmonparam;
+#endif
/*
* Possible states of profiling.
diff --git a/usr.sbin/kgmon/kgmon.8 b/usr.sbin/kgmon/kgmon.8
index 6f12062f5c5..f3229800a46 100644
--- a/usr.sbin/kgmon/kgmon.8
+++ b/usr.sbin/kgmon/kgmon.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: kgmon.8,v 1.12 2013/02/12 08:06:22 mpi Exp $
+.\" $OpenBSD: kgmon.8,v 1.13 2013/03/12 09:37:16 mpi Exp $
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -27,9 +27,8 @@
.\" SUCH DAMAGE.
.\"
.\" from: @(#)kgmon.8 8.1 (Berkeley) 6/6/93
-.\" $Id: kgmon.8,v 1.12 2013/02/12 08:06:22 mpi Exp $
.\"
-.Dd $Mdocdate: February 12 2013 $
+.Dd $Mdocdate: March 12 2013 $
.Dt KGMON 8
.Os
.Sh NAME
@@ -38,6 +37,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 +45,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
@@ -117,10 +117,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 82b9700f98f..eced000d57a 100644
--- a/usr.sbin/kgmon/kgmon.c
+++ b/usr.sbin/kgmon/kgmon.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kgmon.c,v 1.17 2013/02/12 08:06:22 mpi Exp $ */
+/* $OpenBSD: kgmon.c,v 1.18 2013/03/12 09:37:16 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);
+}