summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/prof_machdep.c
diff options
context:
space:
mode:
authorbde <bde@FreeBSD.org>1997-11-24 18:16:23 +0000
committerbde <bde@FreeBSD.org>1997-11-24 18:16:23 +0000
commitc4476760704a44e0aad712d9447f95b4f2963a61 (patch)
tree8c87d19a18c3d34ece804b990919484de4a56f7b /sys/i386/isa/prof_machdep.c
parentf48794b9f592747b49a561fac3392de4ae98657b (diff)
downloadFreeBSD-src-c4476760704a44e0aad712d9447f95b4f2963a61.zip
FreeBSD-src-c4476760704a44e0aad712d9447f95b4f2963a61.tar.gz
Added a sysctl (machdep.cputime_clock) to select the clock used by
"high resolution" profiling. The available clocks are: - the i8254 clock - on non-SMP i586's and i686's: the TSC - on systems with I586_PMC_GUPROF configured, and PERFMON configured and available: all the performance counters. This is unfinshed (there are problems with locking out the PERFMON device driver, and with losing calibration after switching the clock), but better than static configuration or writing to kmem. Changed ifdefs to avoid generating code for non-working option combinations.
Diffstat (limited to 'sys/i386/isa/prof_machdep.c')
-rw-r--r--sys/i386/isa/prof_machdep.c66
1 files changed, 55 insertions, 11 deletions
diff --git a/sys/i386/isa/prof_machdep.c b/sys/i386/isa/prof_machdep.c
index 5f6684d..63c2102 100644
--- a/sys/i386/isa/prof_machdep.c
+++ b/sys/i386/isa/prof_machdep.c
@@ -23,17 +23,18 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id$
+ * $Id: prof_machdep.c,v 1.6 1997/02/22 09:36:59 peter Exp $
*/
#ifdef GUPROF
-#include "opt_cpu.h"
#include "opt_i586_guprof.h"
#include "opt_perfmon.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/gmon.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
#include <machine/clock.h>
#include <machine/perfmon.h>
@@ -175,14 +176,14 @@ cputime()
u_char high, low;
static u_int prev_count;
-#if defined(I586_CPU) || defined(I686_CPU)
+#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP)
if (cputime_clock == CPUTIME_CLOCK_I586_CTR) {
count = (u_int)rdtsc();
delta = (int)(count - prev_count);
prev_count = count;
return (delta);
}
-#ifdef I586_PMC_GUPROF
+#if defined(PERFMON) && defined(I586_PMC_GUPROF)
if (cputime_clock == CPUTIME_CLOCK_I586_PMC) {
/*
* XXX permon_read() should be inlined so that the
@@ -196,8 +197,8 @@ cputime()
prev_count = count;
return (delta);
}
-#endif /* I586_PMC_GUPROF */
-#endif /* I586_CPU or I686_CPU */
+#endif /* PERFMON && I586_PMC_GUPROF */
+#endif /* (I586_CPU || I686_CPU) && !SMP */
/*
* Read the current value of the 8254 timer counter 0.
@@ -223,6 +224,49 @@ cputime()
return (delta);
}
+static int
+sysctl_machdep_cputime_clock SYSCTL_HANDLER_ARGS
+{
+ int clock;
+ int event;
+ int error;
+ struct pmc pmc;
+
+ clock = cputime_clock;
+#if defined(PERFMON) && defined(I586_PMC_GUPROF)
+ if (clock == CPUTIME_CLOCK_I586_PMC) {
+ pmc.pmc_val = cputime_clock_pmc_conf;
+ clock += pmc.pmc_event;
+ }
+#endif
+ error = sysctl_handle_opaque(oidp, &clock, sizeof clock, req);
+ if (error == 0 && req->newptr != NULL) {
+#if defined(PERFMON) && defined(I586_PMC_GUPROF)
+ if (clock >= CPUTIME_CLOCK_I586_PMC) {
+ event = clock - CPUTIME_CLOCK_I586_PMC;
+ if (event >= 256)
+ return (EINVAL);
+ pmc.pmc_num = 0;
+ pmc.pmc_event = event;
+ pmc.pmc_unit = 0;
+ pmc.pmc_flags = PMCF_E | PMCF_OS | PMCF_USR;
+ pmc.pmc_mask = 0;
+ cputime_clock_pmc_conf = pmc.pmc_val;
+ cputime_clock = CPUTIME_CLOCK_I586_PMC;
+ } else
+#endif
+ {
+ if (clock < 0 || clock >= CPUTIME_CLOCK_I586_PMC)
+ return (EINVAL);
+ cputime_clock = clock;
+ }
+ }
+ return (error);
+}
+
+SYSCTL_PROC(_machdep, OID_AUTO, cputime_clock, CTLTYPE_INT | CTLFLAG_RW,
+ 0, sizeof(u_int), sysctl_machdep_cputime_clock, "I", "");
+
/*
* The start and stop routines need not be here since we turn off profiling
* before calling them. They are here for convenience.
@@ -234,16 +278,16 @@ startguprof(gp)
{
if (cputime_clock == CPUTIME_CLOCK_UNINITIALIZED) {
cputime_clock = CPUTIME_CLOCK_I8254;
-#if defined(I586_CPU) || defined(I686_CPU)
+#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP)
if (i586_ctr_freq != 0)
cputime_clock = CPUTIME_CLOCK_I586_CTR;
#endif
}
gp->profrate = timer_freq << CPUTIME_CLOCK_I8254_SHIFT;
-#if defined(I586_CPU) || defined(I686_CPU)
+#if (defined(I586_CPU) || defined(I686_CPU)) && !defined(SMP)
if (cputime_clock == CPUTIME_CLOCK_I586_CTR)
gp->profrate = i586_ctr_freq;
-#ifdef I586_PMC_GUPROF
+#if defined(PERFMON) && defined(I586_PMC_GUPROF)
else if (cputime_clock == CPUTIME_CLOCK_I586_PMC) {
if (perfmon_avail() &&
perfmon_setup(0, cputime_clock_pmc_conf) == 0) {
@@ -268,8 +312,8 @@ startguprof(gp)
}
}
}
-#endif /* I586_PMC_GUPROF */
-#endif /* I586_CPU or I686_CPU */
+#endif /* PERFMON && I586_PMC_GUPROF */
+#endif /* (I586_CPU || I686_CPU) && !SMP */
cputime_bias = 0;
cputime();
}
OpenPOWER on IntegriCloud